Date: Sun, 2 Jul 2006 19:07:47 -0500 (CDT)
From: Dan Grayson <dan@math.uiuc.edu>
To: Amelia Taylor <ataylor@stolaf.edu>
CC: dan@math.uiuc.edu
In-reply-to: <276899F6-9E18-4432-8BDD-73DE2EDEA8A3@stolaf.edu> (message from
	Amelia Taylor on Sun, 2 Jul 2006 16:43:00 -0500)
Subject: Re: normal.m2
Reply-to: dan@math.uiuc.edu


That's probably the kind of thing I would have to set up.  Thanks for the
feedback -- I'll let you know if I manage to get around to it in the next few
days.

I assume you want the very latest M2 installed for your workshop...

> Cc: mike@math.cornell.edu
> From: Amelia Taylor <ataylor@stolaf.edu>
> Subject: Re: normal.m2
> Date: Sun, 2 Jul 2006 16:43:00 -0500
> To: dan@math.uiuc.edu
> 
> 
> Dan,
> 
> > It's probably a good idea to reserve the name "Strategy" for an  
> > option that
> > changes the way something is compute, not what is computed.  I'm  
> > not sure what
> > the option should be called, though.
> 
> I agree.  I don't have much control over options and that seemed the  
> closest.  I'll leave this up to you.  If I have any good ideas, but  
> then maybe we should just think about the following.
> 
> > As for ICfractions, it also seems redundant, sort of.  If we had a  
> > (new) type
> > of ring called Subring, then integralClosure could return a sub-k- 
> > algebra of
> > frac(R), and then "gens" could return its generators: that would be  
> > the long
> > list.  Alternatively, if we had the integral closure as a sub-R- 
> > algebra of
> > frac(R), then "gens" of it would be the short version.  I guess the  
> > definition
> > of "subring" could be the image of a ring homomorphism f from a  
> > polynomial ring
> > to some other ring.  Taking "gens" of it would be the same as  
> > applying f to the
> > generators of the source of f
> 
> I am not sure if you are saying we (you) should create a way to do  
> this sort of subring, or if it is already possible to set this sort  
> of thing up and we (one of us) should implement this idea in the code.
> 
> Either way, I generally agree that this sort of idea is probably  
> better than what is there now (ICfractions, etc).  I could still  
> effectively use the code for ideal integral closure stuff  (my  
> personal primary use of this feature) and I think the way the  
> information is stored/displayed/disseminated to the user is better.    
> And making the integral closure as a R or k subring of frac(R),  
> rather than just a presentation with new variables, is the motivation  
> for these commands - actually giving it to the user as a subring  
> rather than a matrix seems very sensible.  It also makes the commands/ 
> process more algebraically intuitive (something I'm a big fan of).
> 
> Do you want me to try and do this, or can you it quickly?
> 
> - Amelia
> 
> 
> > If you want to find an efficient presentation for a subring, then  
> > "prune" it.
> >
> >> Cc: mike@math.cornell.edu
> >> From: Amelia Taylor <ataylor@stolaf.edu>
> >> Subject: Re: normal.m2
> >> Date: Sun, 2 Jul 2006 14:55:25 -0500
> >> To: dan@math.uiuc.edu
> >>
> >>
> >> --Apple-Mail-14--383249626
> >> Content-Transfer-Encoding: 7bit
> >> Content-Type: text/plain;
> >> 	charset=US-ASCII;
> >> 	delsp=yes;
> >> 	format=flowed
> >>
> >>
> >> Dan,
> >>
> >> They are different.  The difference is that the cycles through the
> >> program may compute redundant fractions and there are some cases
> >> where the user might want access to those, however, I agree
> >> completely with an optional argument and that the default be the old
> >> ICfractions and the user puts Strategy => Long to get the other -
> >> actually as I wrote the user could put anything but null and get the
> >> longer version.  With this process I cleaned it up a bit (there were
> >> un-used assignments) and I think I can clean it up a bit more, but
> >> this works well and keeps us moving forward.
> >>
> >> I have attached updated code that does that.  I am also attaching an
> >> updated minPres.m2.  This is key as the old one has a pretty serious
> >> bug Mike and I found.  He may have fixed it in the version you have,
> >> but this does it even more efficiently.
> >>
> >> - Amelia
> >>
> >>
> >> --Apple-Mail-14--383249626
> >> Content-Transfer-Encoding: 7bit
> >> Content-Type: application/octet-stream;
> >> 	x-unix-mode=0644;
> >> 	name="normal-2-7-06.m2"
> >> Content-Disposition: attachment;
> >> 	filename=normal-2-7-06.m2
> >>
> >> -- This file written by Amelia Taylor <ataylor@math.rutgers.edu>
> >>
> >> -- debug Macaulay2Core
> >>
> >> -- Computes the integral closure of a reduced ring (R/I where I is  
> >> radical).  
> >> -- integralClosure takes R/I as input and outputs a sequence of  
> >> ideals, 
> >> -- I_1,..., I_n such that the integral closure of R/I is the  
> >> direct product 
> >> -- of R_1/I_1,..., R_n/I_n.
> >>
> >>
> >> -- Included is a function for checking if an affine domain is  
> >> normal.  
> >> -- isNormal works for any ring given as a quotient ring.  
> >> -- The fractions that generate the integral closure over R/I are  
> >> obtained 
> >> -- by the command ICfractions(R/I).  
> >> -- Included is a command conductor that computes the conductor of  
> >> S into R
> >> -- where S is the image of a ring map from R to S where S is  
> >> finite over
> >> -- R.  ICmap constructs this map (the natural map R/I->R_j/I_j)  
> >> for R 
> >> -- into its integral closure and applying conductor to this map 
> >> -- yeilds the conductor of the integral closure into R.
> >>
> >> isNormal2 = method()
> >> isNormal2(Ring) := Boolean => (R) -> (
> >>      --Input:  Takes a quotient ring.
> >>      --Method:  Check if the Jacobian ideal of R has
> >>      --codim >= 2, if true then check the codimension
> >>      --of Ext^i(S/I,S) where R = S/I and i>codim I. If
> >>      --the codimensions are >= i+2 then return true.
> >>      I := ideal (R);
> >>      M := cokernel generators I;
> >>      n := codim I;
> >>      m := dim ring I;    -- 11 June 01 -- Write this so that it  
> >> checks
> >>      m2:= dim R;         -- S2 first and prints "is S2".  Then checks
> >>      Jac := minors(n,jacobian R);  -- R1 this way the user gets  
> >> more info.
> >>      S2 := apply (m-n-1, i-> codim Ext^(i+n+1)(M,ring M));
> >>      test := apply(m-n-1,i->i+n+3);
> >>      m2-dim Jac >= 2 and S2 >= test
> >>      )
> >>
> >> -- As the engine code changes, comparisons of the time for 
> >> -- radical and radical0 must be checked.  16.5.01 radical0 
> >> -- in the code is universally faster.  However, for the 
> >> -- example in Wolmer's book where one takes the radical of 3
> >> -- generators, radical computes it in about 4 or 5 sec and 
> >> -- radical0 does not finish.
> >> radical0 = (I) -> (
> >>      I = ideal mingens ideal generators gb I;
> >>      comps := decompose I;
> >>      result := if #comps === 1 then comps#0
> >>                else intersect toSequence comps;
> >>      result)
> >>
> >> -- 16.5.01 This has now been fixed in the system!
> >> -- Needed because we have problems with multigraded over char 0 and 
> >> -- have to kill the multigrading in this case at the very beginning.
> >> isSinglyGraded := (R) -> (
> >>      n := numgens (ring presentation R).degreesRing;
> >>      if n===1 then true else false)
> >>
> >>
> >> -- The idea of ICnode is to keep track of where we are in the process
> >> -- and the various maps and fractions we generate.  It is  
> >> particularly 
> >> -- important in the reduced-not-domain case since we have to  
> >> divide the 
> >> -- the ring into pieces and keep track of those we have normalized.
> >>
> >> -- The idea in general is to use normal0 to find the 
> >> -- Non-normal locus.  First looking at the singular locus.  If it 
> >> -- is just variables (max'l ideal) then it matches the NNL and we 
> >> -- use it.  If not then we use the Jacobian to compute the NNL.
> >>
> >> -- Once we have the defining ideal for the NNL we use idealizer0
> >> -- to start looking at Hom(J,J).  (Recall (1/f)(fJ:J)=Hom(J,J)  
> >> where f 
> >> -- is a NZD in J mod I.)  For the reduced not domain case we must  
> >> check 
> >> -- for a NZD and if I:f strictly contains I and f is in J but not  
> >> I then 
> >> -- we consider the two new rings R/I:f and R/I:(I:f), continuing the 
> >> -- process with these.  In the domain case we could just pick the  
> >> first 
> >> -- generator of J that is not in I works.
> >>
> >>
> >> -- ICnode is a mutable hash table that allows us to collect all of  
> >> the 
> >> -- necessary information throughout this process.  Most of the  
> >> elements 
> >> -- in the hash table are clear, however, C#"todo", C#"pending",  
> >> C#"storing" and 
> >> -- C#"answer" are the key pieces to working through the  
> >> algorithm.  C#"todo" is
> >> -- the ideal that we need to work on next before starting the  
> >> algorithm.  Once
> >> -- the algorithm is started this ideal, along with its NNL (once  
> >> computed) are
> >> -- stored in C#"pending" and C#"todo" = {}.  After we have passed  
> >> through the 
> >> -- algorithm once newI and newJ are put into C#"todo" and we begin  
> >> again.  If 
> >> -- a zero divisor is detected (in idealizer0) then the first  
> >> ideal, I, in 
> >> -- C#"pending" is split into I:f and I:I:f.  I:f is placed in  
> >> C#"todo" so that 
> >> -- the algorithm can begin again with that ideal and I:I:f is  
> >> placed in 
> >> -- C#"storing".  Once the integral closure of R_i/I_i for some I_i  
> >> is obtained, 
> >> -- then the defining ideal of theis integral closure is placed in  
> >> C#"answer".
> >>
> >> ICnode = new Type of MutableHashTable;
> >>
> >> newICnode = (R) -> (
> >>      I := ideal presentation R;
> >>      C := new ICnode;
> >>      C#"todo" = {{I,null}};
> >>      C#"pending" = null;
> >>      C#"storing" = {};
> >>      C#"answer" = {};
> >>      C#"degrees" = degrees source vars ring I;
> >>      C#"blocks" = {numgens ring I};
> >>      C#"basefield" = coefficientRing ring I;
> >>      C#"vars" = toSequence (ring I).generatorSymbols;
> >>      C#"numgens" = 0;
> >>      C#"newvars" = {};
> >>      C#"fractions" = generators R;
> >>      C#"fraclong" = {};
> >>      C#"map" = null;
> >>      C#"rings" = R;
> >>      R#IIICCC = C;
> >>      C)
> >>
> >> -- Tells us when to stop the algorithm.  Moves ideals from  
> >> C#"todo" to C#"pending".
> >> next := (C) -> (
> >>      if C#"pending" =!= null then true
> >>      else if #C#"todo" > 0
> >>      then (
> >> 	  C#"pending" = C#"todo"#0;
> >> 	  C#"todo" = drop(C#"todo",1);
> >> 	  true)
> >>      else false)
> >>
> >> idealizer0 = (C,w) -> (
> >>      -- Takes {I,J} off the pending list of C,
> >>      -- computes the ring sturcture of Hom_R(J,J).
> >>      -- This is done using the IC structure, since we wish to be  
> >> able to
> >>      -- handle interrupts, and the creation of the ring is somewhat
> >>      -- easier.  It also facilitates handling the non prime case.
> >>      I := C#"pending"#0;
> >>      J := C#"pending"#1;
> >>      Jc := ideal compress (generators J % generators I);
> >>      << "--checking Jc" << Jc << endl;
> >>  --    error "debug me";
> >>      -- Find an element of J, a nzd in S/I.  Need to make sure we  
> >> donot
> >>      -- choose an element in I, so first we reduce J mod I.
> >>      J1 := I:Jc_0;
> >>      if J1 != I then(
> >> 	  -- If Jc_0 is a ZD then we split the ring.
> >> 	  C#"todo" = append(C#"todo",{J1,null});
> >> 	  C#"pending" = null;
> >> 	  C#"storing" = append(C#"storing",I:J1);
> >> 	  )
> >>      else(
> >> 	  -- If Jc_0 is a NZD then we continue setting f = Jc_0.
> >> 	  f := Jc_0;
> >>      	  -- Compute Hom_R(J,J), with R = S/I.
> >>      	  -- From now on, we work in this quotient:
> >>      	  R := (ring I)/I;
> >>      	  JR := ideal (generators J ** R);
> >>      	  fR := substitute(f, R);
> >>      	  idJ := mingens ideal generators gb (fR * JR : JR);
> >>      	  if ideal(idJ) == ideal(fR)  then (
> >> 	       -- We have the answer for this ideal!
> >> 	       C#"answer" = append(C#"answer", {ring I,I});
> >> 	       if #C#"storing" > 0 then (
> >> 	       	    C#"todo" = {{C#"storing"#0,null}};
> >> 	       	    C#"storing" = drop(C#"storing", 1);
> >> 	       	    C#"pending" = null;
> >> 	       	    )
> >> 	       else(C#"pending" = null;)
> >> 	       )
> >>      	  else (
> >>      	       H := compress (idJ % fR);
> >> 	       C#"fractions" = join((apply(first entries H,i->i/ 
> >> fR)),C#"fractions");
> >> 	       C#"fraclong" = join((apply(first entries H,i->i/ 
> >> fR)),C#"fraclong");
> >>      	       Ha := (fR // generators JR);
> >> 	       -- MES: what is this Ha all about: the problem is that
> >> 	       -- although f is a minimal generator of (fJ:J) mod I,
> >> 	       -- it might not be given immediately as one of the elements.
> >>      	       Hf := H | matrix{{fR}};
> >>      	       -- Make the new polynomial ring.
> >> 	       n := numgens source H;
> >> 	       newdegs := degrees source H - toList(n:degree fR);
> >> 	       C#"degrees" = join(newdegs, C#"degrees");
> >>      	       C#"blocks" = prepend(n, C#"blocks");
> >> 	       C#"numgens" = C#"numgens" + n;   	    	      	   	
> >>       	       varsA := w_(C#"numgens" - n) .. w_(C#"numgens" -1);
> >>        	       C#"vars" = splice(varsA, C#"vars");
> >>      	       C#"blocks" = select(C#"blocks", d -> d =!= 0);
> >>      	       A := (if any(C#"degrees", d -> d#0 <= 0) then (
> >>        			 (C#"basefield")[C#"vars",
> >> 	  		      MonomialOrder=>ProductOrder (C#"blocks"),
> >> 	  		      MonomialSize=>16])
> >>      		    else (
> >>        			 (C#"basefield")[C#"vars",
> >> 	  		      Degrees => C#"degrees",
> >> 	  		      MonomialOrder=>ProductOrder (C#"blocks"),
> >> 	  		      MonomialSize=>16])
> >>      		    );
> >> 	       newvars := (vars A)_{0..n-1};
> >> 	       C#"newvars" = join(entries newvars,C#"newvars");
> >>      	       RtoA := map(A,R,(vars A)_{n..numgens R + n - 1});
> >> 	       IA := ideal ((map(A,ring I,RtoA.matrix)) (generators I));
> >> 	       XX := newvars | matrix{{1_A}};
> >>      	       -- Linear relations in the new variables
> >>      	       lins := XX * RtoA syz Hf;
> >> 	       -- linear equations(in new variables) in the ideal
> >>      	       -- Quadratic relations in the new variables
> >> 	       tails := (symmetricPower(2,H) // fR) // Hf;
> >> 	       tails = RtoA tails;
> >> 	       quads := matrix(A, entries (symmetricPower(2,newvars) - XX  
> >> * tails));
> >> 	       newI1 := trim ideal matrix entries generators (
> >> 		    ideal lins + ideal quads + IA);
> >> 	       newJ1 := newI1 + RtoA JR;
> >> 	       newI = minimalPresentation(newI1);
> >> 	       R2 = ring newI;
> >> 	       FF := substitute 
> >> (((newI1).cache.minimalPresentationMap).matrix,R2);
> >> 	       F := map(R2,A,FF);
> >> 	       newJ :=  F newJ1;
> >> 	       --Making the map from S to it's integral closure.
> >> 	       S1 := C#"rings";
> >> 	       F1 := map(A,S1);
> >> 	       if C#"map" === null then C#"map" = F * F1
> >> 	       else C#"map" = F * F1 * C#"map";
> >> 	       --Resetting the necessary values of the hash table.
> >> 	       indexvars = apply(first entries substitute(vars R2,A),  
> >> index);
> >>       	       C#"degrees" = apply(indexvars,i->(C#"degrees")#i);
> >> 	       C#"fractions" = apply(indexvars, i->(C#"fractions")#i);
> >> 	       C#"blocks" = {numgens R2};
> >> 	       C#"vars" = toSequence R2.generatorSymbols;
> >> 	       -- See the note in "normal0" about the if char R = 0  
> >> statement.
> >> 	       newJ = radical0 newJ;
> >> 	       C#"todo" = append(C#"todo", {newI,newJ});
> >> 	       C#"pending" = null;
> >> 	       C#"rings" = R2;
> >> 	       )
> >>      	  );
> >>      )
> >>
> >>
> >> normal0 = (C) -> (
> >>      -- This handles the first node: finding an ideal that  
> >> contains the NNL
> >>      -- locus.
> >>      I := C#"pending"#0;
> >>      III = I;
> >>      local J;
> >>      SI := jacobian I;
> >>      R := (ring I)/I;
> >>      SIR := substitute(SI,R);
> >>      if isHomogeneous I and #(first entries generators I)+# 
> >> (generators ring I) <= 20 then (
> >> 	  SIdets := minors(codim I, SIR);
> >> 	   -- the codimension of the singular locus.
> >> 	  cs := codim SIdets + codim R;  -- codim of SIdets in poly ring.
> >> 	  if cs === dim ring I or SIdets == ideal (1_R)
> >> 	  -- i.e. the sing locus is empty.
> >> 	  then (J = ideal vars ring I;)
> >> 	  else (J = radical0(lift(ideal SIdets_0,ring I)));
> >> 	  )           	
> >>      else (
> >> 	  n := 1;
> >> 	  det1 := ideal (0_R);
> >> 	  while det1 == ideal (0_R) do (
> >> 	       det1 = minors(codim I, SIR, Limit=>n);
> >> 	       n = n+1);
> >> 	     if det1 == ideal (1_R)
> >> 	     -- i.e. the sing locus is empty.
> >> 	     then (J = ideal vars ring I;)
> >> 	     else (J = radical0(lift(ideal det1_0,ring I)))
> >> 	     );	
> >>      C#"todo" = append(C#"todo", {I,J});
> >>      C#"pending" = null;
> >>      )
> >>
> >> w := local w
> >> integralClosure = method(Options=>{Variable => null}) -- changed  
> >> to local variable, and hid it from the documentation -- drg
> >> integralClosure Ring := Ring => o -> (R) -> (
> >>      if not R#?IIICCC then newICnode R;
> >>      C := R#IIICCC;
> >>      while next C do (
> >>       	  if C#"pending"#1 === null
> >>      	  then normal0 (C) --Compute J defining the NNL.
> >>      	  else idealizer0(C,if o.Variable =!= null then o.Variable  
> >> else local w));
> >>      A := apply(C#"answer",i->minimalPresentation2(i_0/i_1));
> >>      if #A == 1 then A#0
> >>      else toSequence A
> >>      )
> >>
> >>
> >> --------------------------------------------------------------------
> >>
> >> -- R#IIICCC#"map" is needed to find the conductor
> >> ICmap = method()
> >> ICmap(Ring) := RingMap => (R) -> (
> >>      -- Input:  a quotient ring.
> >>      -- Output:  The natural map from R to its integral closure S.
> >>      -- Note:  This is needed to compute the conductor of R into S.
> >>      if R#?IIICCC or not isNormal R then (
> >> 	  if not R#?IIICCC then integralClosure2(R);
> >> 	  S := (R#IIICCC#"answer"#0)#0/(R#IIICCC#"answer"#0)#1;
> >> 	  U := R#IIICCC#"map";
> >>      	  if U === null then R#IIICCC#"map" = map(S,S)
> >>      	  else R#IIICCC#"map" = map(S,R,substitute((U).matrix,S));
> >> 	       R#IIICCC#"map"
> >> 	       )
> >>      else (map(R,R))
> >>      )
> >>
> >> --------------------------------------------------------------------
> >> ICfractions = method(Options => {Strategy => null})
> >> ICfractions(Ring) := RingMap => o-> R -> (
> >>      -- Input:  A quotient ring that is a domain.
> >>      -- Output:  A matrix of the fractions added to R to get the  
> >> integral closure.
> >>      -- These correspond directly to the variables in the output  
> >> of integralClosure
> >>      -- and the matrix is in the fraction field of the original ring.
> >>      --
> >>      -- I haven't figured out how to do the fractions and the maps
> >>      -- for reduced rings yet.  #C#"answer" == 1 if and only if a
> >>      -- domain was the input into the function.
> >>      if R#?IIICCC or not isNormal R then (
> >> 	  integralClosure2 R;
> >> 	  K := (R#IIICCC#"basefield")[join(flatten  
> >> R#IIICCC#"newvars",R.generatorSymbols)];
> >> 	  -- This constructs the new ring using all of the new variables.
> >> 	  KF := frac(K);
> >> 	  M1 := first entries substitute(vars R,KF);  -- puts the vars of  
> >> R in KF
> >> 	  M2 := apply(R#IIICCC#"fraclong", i->matrix{{i}});
> >> 	  M2' := apply(M2, i->substitute(i,KF));
> >> 	  M3 := flatten apply(M2', j-> first entries j);
> >> 	  if o.Strategy === null then (
> >> 	       L1 := apply(R#IIICCC#"fractions", i->matrix{{i}});
> >> 	       L2 := matrix{flatten apply(apply(L1, i->substitute(i,KF)),  
> >> j-> first entries j)};
> >> 	       done := false;
> >> 	       while done == false do (
> >> 		    G := map(KF,KF,matrix{join(M3,M1)});
> >> 	       	    L2 = G(L2);
> >> 	       	    done = isSubset(ideal apply(first entries L2,i- 
> >> >numerator i), ideal take(generators K , {#(generators K)-# 
> >> (R.generatorSymbols),#(generators K)}));
> >> 	       	    );
> >> 	       K2 := frac R;
> >> 	       substitute(L2,K2)
> >> 	       )
> >> 	       else (
> >> 		    G2 := matrix{join(M3,M1)};
> >>      	  	    Map := map(KF,KF,G2);
> >>      	  	    done = false;
> >> 	  	    while done == false do (
> >> 	       		 G2 = Map(G2);
> >> 	       		 done = isSubset(ideal apply(first entries G2,i- 
> >> >numerator i), ideal take(generators K , {#(generators K)-# 
> >> (R.generatorSymbols),#(generators K)}));
> >> 	       		 );
> >> 	  	    K2 = frac R;
> >> 	  	    substitute(G2,K2)
> >> 		    )
> >> 	       )
> >>      else (
> >> 	  I := ideal(R);
> >> 	  vars R)
> >> 	  )
> >>
> >> --------------------------------------------------------------------
> >> conductor = method()
> >> conductor(RingMap) := Ideal => (F) -> (
> >>      --Input:  A ring map where the target is finitely generated as a
> >>      --module over the source.
> >>      --Output: The conductor of the target into the source.
> >>      --NOTE:  If using this in conjunction with the command  
> >> normalization,
> >>      --then the input is R#IIICCC#"map" where R is the name of the  
> >> ring used as
> >>      --input into normalization.
> >>      if isSinglyGraded (source F) and isHomogeneous (source F)
> >>      	  then(M := presentation pushForward(F, (target F)^1);
> >>      	       P := target M;
> >>      	       intersect apply((numgens P)-1, i->(
> >> 	       m:=matrix{P_(i+1)};
> >> 	       I:=ideal modulo(m,matrix{P_0}|M))))
> >> 	  else (<< " --No conductor for " << F << endl;)
> >>      )
> >>
> >> ///
> >> restart
> >>
> >> R = ZZ/101[symbol x..symbol z,Degrees=>{2,5,6}]/(z*y^2-x^5*z-x^8)
> >> ICfractions(R)
> >> ICfractions(R, Strategy => Long)
> >>
> >> debug Macaulay2Core
> >> load "normal-15-6-06.m2"
> >> S = ZZ/32003[x,y,z]
> >> I = ideal"xy-z2, x2-yz"
> >> A = S/I
> >> integralClosure2(A)
> >>
> >> load "minPres-17-6-06.m2"
> >> S = ZZ/32003[w_0,w_1,x,y,z,MonomialSize => 16]
> >> newI1 = ideal (y^2-x*z, x*y-z^2, x^2-y*z, w_1*z-x, w_1*y-z, w_1*x- 
> >> y, w_0*z-y,
> >> w_0*y-x, w_0*x-z, w_1^2-w_0, w_0*w_1-1, w_0^2-w_1)
> >>
> >> S=ZZ/101[symbol a,symbol b,symbol c, symbol d]
> >> I=ideal(a*(b-c),c*(b-d),b*(c-d))
> >> A=S/I
> >> time V = integralClosure2 A
> >> apply(V, i-> ideal i) == (ideal (S_3, S_1, S_0),ideal (S_2,  
> >> S_1),ideal (S_2 - S_3, S_1 - S_3), ideal (S_3, S_2, S_0))
> >>
> >> ///
> >>
> >> -- Local Variables:
> >> -- compile-command: "make -C $M2BUILDDIR/Macaulay2/m2 "
> >> -- End:
> >>
> >>
> >> --Apple-Mail-14--383249626
> >> Content-Transfer-Encoding: 7bit
> >> Content-Type: application/octet-stream;
> >> 	x-unix-mode=0644;
> >> 	name="minPres-17-6-06.m2"
> >> Content-Disposition: attachment;
> >> 	filename=minPres-17-6-06.m2
> >>
> >> -- This file written by Amelia Taylor <ataylor@stolaf.edu>
> >>
> >> ----- This file was last updated on June 22, 2006
> >>
> >> --------------------------------------------------------------
> >> -- This begins the code for minimalPresentation which takes both  
> >> ideals and 
> >> -- quotient rings as input.   
> >>
> >> -- checkpoly, finishmap, monOrder and coreProgram are called 
> >> -- in the top-level program minimalPresentation.  
> >>
> >> checkpoly := (f)->(
> >>      -- 1 Argument:  A polynomial.
> >>      -- Return:      A list of the index of the first
> >>      --              (by index in the ring) variable that occurs
> >>      --              linearly in f and does not occur in any other
> >>      --              term of f and a polynomial with that term
> >>      --              eliminated.
> >>      A := ring(f);
> >>      p := first entries contract(vars A,f);
> >>      i := position(p, g -> g != 0 and first degree g === 0);
> >>      if i === null then
> >>          {}
> >>      else (
> >>      	  v := A_i;
> >>      	  c := f_v;
> >>      	  {i,(-1)*(c^(-1)*(f-c*v))}
> >> 	  )
> >>      )
> >>
> >> finishMap := (L,xmap) -> (
> >>      -- 2 Arguments:  A matrix and a new mutable list.
> >>      -- Return:       a map from the ring corresponding to
> >>      --               entries in the matix to itself given by
> >>      --               entries in the matrix which have a linear
> >>      --               term that does not occur elsewhere in the
> >>      --               polynomial.
> >>      A := ring L_0;
> >>      count := #L;
> >>      while count > 0 do (
> >> 	  M := map(A,A,matrix{toList xmap});
> >> 	  p := checkpoly(M(L_(count-1)));
> >> 	  if p =!= {} then (
> >> 	       xmap#(p#0) = p#1;
> >> 	       F1 := map(A,A,toList xmap);
> >> 	       F2 := map(A,A, F1 (F1.matrix));
> >> 	       xmap = new MutableList from first entries F2.matrix;);
> >> 	  count = count-1
> >> 	  );
> >>      map(A,A,toList xmap)
> >>      )
> >>
> >> monOrder := (Ord, l) -> (
> >>      -- 2 arguments: a monomial order and a list of variables.
> >>      -- return:  a new monomial order corresponding to the subset of
> >>      --          of variables in l.
> >>      if (Ord === Lex or Ord === GRevLex or Ord === RevLex)
> >>      then newOrd := Ord
> >>      -- The order for the original ring is a product order.
> >>      -- Build a new product order based on variables remaining
> >>      -- for the minimal presentation.
> >>      else (oldpieces := toList Ord;
> >> 	  newpieces := {};
> >> 	  count := 0;
> >> 	  done := #oldpieces;
> >> 	  m := l;
> >> 	  while done > 0 do (
> >> 	       sm := #(select(m, i -> i < oldpieces#0 + count));
> >> 	       newpieces = append(newpieces, sm);
> >> 	       if sm == 0 then m = m else m = drop(m, sm);
> >> 	       count = count + oldpieces#0;
> >> 	       oldpieces = drop(oldpieces, 1);
> >> 	       done = #oldpieces;
> >> 	       );
> >> 	  newpieces = select(newpieces, i -> i != 0);
> >> 	  newOrd = ProductOrder newpieces;
> >> 	  );
> >>      newOrd
> >>      )   	
> >>
> >> monOrder = (Ord, l) -> GRevLex=>#l
> >>
> >> coreProgram := (I, newvar) -> (
> >>      -- 2 Arguments:  An ideal and a variable, or null.
> >>      -- Return:       A list consisting of an ideal, a
> >>      --               quotient ring, a polynomial ring,
> >>      --               two matrices and a list of variables.
> >>      -- Note:         The ideal is the ideal promised by
> >>      --               minimalPresentation ideal and the polynomial  
> >> ring,
> >>      --               the ring for this idea.  The quotient
> >>      --               ring similar for minimalPresentation ring.  The
> >>      --               matrices set up the maps.
> >>      R := ring I;
> >>      F := finishMap(flatten entries generators I, new MutableList  
> >> from first entries (vars R));
> >>      -- The key computation of the polynomials with linear
> >>      -- terms is complete.  Now build desired rings, ideals
> >>      -- and maps through this map.
> >>      LF := flatten entries F.matrix;
> >>      l1 := apply(LF, f -> sum(exponents f));
> >>      l := positions(l1,f -> if f===0 then false else (sum f) === 1);
> >>      -- l contains the indices for the variables remaining in
> >>      -- the minimal presentation.  l is used to set new rings,
> >>      -- including getting the correct monomial order.
> >>      varsR := apply(l,f->R_f);
> >>      degreesS := apply(l,i->((monoid R).degrees)#i);
> >>      newMonOrder := monOrder((monoid R).Options.MonomialOrder, l);
> >>      -- The two cases cover if the user does not or does  
> >> (respectively
> >>      -- give a new variable name for the minimal presentation ring).
> >>      if newvar === null then (
> >> 	  S := (coefficientRing R)[varsR, Degrees => degreesS,  
> >> MonomialOrder => newMonOrder];
> >> 	  vv := map(S,S);
> >> 	  newI := trim vv(substitute (ideal compress generators F(I), S));
> >> 	  S2 := S/newI;
> >> 	  FmatS := substitute(F.matrix, S);
> >> 	  FmatS2 := substitute(F.matrix, S2))
> >>      else (
> >> 	  R2 := (coefficientRing R)[varsR];
> >> 	  y := newvar;
> >> 	  var := splice{y_0..y_(#l-1)};
> >> 	  S = (coefficientRing R)[var,Degrees => degreesS, MonomialOrder  
> >> => newMonOrder];
> >> 	  vv = map(S, R2,vars S);
> >> 	  J := substitute (ideal compress generators F(I), R2);
> >> 	  newI = trim vv(J);
> >> 	  S2 = S/newI;
> >> 	  FmatS = vv(substitute(F.matrix,R2));
> >> 	  FmatS2 = substitute(FmatS, S2);
> >> 	  );
> >>      (newI, S, S2, FmatS, FmatS2, varsR)	      	   	
> >>      )
> >>
> >>
> >> minimalPresentation = method(Options=>{Variable => null})
> >> minimalPresentation Ideal := o -> (I) -> (
> >>      --1 Argument: Any ideal in a polynomial ring.
> >>      --Return:     An ideal J in a polynomial ring S such that
> >>      --            S/J is isomorphic with R/I. Maps from R to S
> >>      --            and S to R are encoded in  
> >> I.cache.minimalPresentationMap
> >>      --            and I.cache.minimalPresentationMapInv  
> >> respectively.
> >>      --Method:     Generators of I that are linear and occur
> >>      --            only once in that generator are removed.
> >>      --            This top level program calls coreProgram.
> >>      --            coreProgram calls monOrder and finishMap.
> >>      --            finishMap calls checkpoly.
> >>      if I == 0 then I else (
> >> 	  S := coreProgram(I,o.Variable);
> >> 	  I.cache.minimalPresentationMap = map(S_1, ring I, S_3);
> >>      	  I.cache.minimalPresentationMapInv = map(ring I, S_1, S_5);
> >> 	  S_0
> >>      	  )
> >>      )
> >>
> >> minimalPresentation Ring := o -> (R) -> (
> >>      -- 1 Argument: Any quotient of a polynomial ring R.
> >>      -- Return:     An quotient ring R' = S'/J isomorphic to
> >>      --             R. Maps from R to R' and R' to R are
> >>      --             encoded in R.minimalPresentationMap and  
> >> R.minimalPresentationMapInv
> >>      --             respectively.
> >>      --Method:      Write R as S/I, then generators of I that
> >>      --             are linear and occur only once in that
> >>      --             generator are removed.  This top level
> >>      --             program calls coreProgram.
> >>      --             coreProgram calls monOrder and finishMap.
> >>      --             finishMap calls checkpoly.
> >>      M := presentation R;
> >>      S := coreProgram(ideal M, o.Variable);
> >>      R.minimalPresentationMap = map(S_2,R,S_4);
> >>      R.minimalPresentationMapInv = map(R,S_2,S_5);
> >>      S_2)
> >>
> >> ---------------------------
> >> -- minimalPresentationMap2 = method()
> >>
> >> -- minimalPresentationMap2 Ring := (R) -> (
> >>      --Input:   A quotient ring.
> >>      --Output:  A map from the polynomial ring to itself
> >>      --         that is the map used to form a minimal
> >>      --         presentation of R.
> >> --     finishMap(flatten entries presentation R, new MutableList  
> >> from first entries (generators ideal presentation R))
> >> --          )
> >>
> >> --minimalPresentationMap2 Ideal := (I) -> (
> >>      --Input:   An ideal.
> >>      --Output:  A map from the ring of I, call it A,
> >>      --         to itself, that is the map used to form a minimal
> >>      --         presentation of R.
> >> --     finishMap(flatten entries generators I, new MutableList  
> >> from first entries (generators I))
> >> --     )
> >>
> >>
> >>
> >> --Apple-Mail-14--383249626
> >> Content-Transfer-Encoding: 7bit
> >> Content-Type: text/plain;
> >> 	charset=US-ASCII;
> >> 	delsp=yes;
> >> 	format=flowed
> >>
> >>
> >> On Jul 2, 2006, at 7:01 AM, Dan Grayson wrote:
> >>
> >>>
> >>> Dear Amelia,
> >>>
> >>> I was about to document ICfractionsLong, but I can't figure out the
> >>> difference
> >>> betweent it and ICfractions.
> >>>
> >>>
> >>>     i21 : ICfractions R
> >>>
> >>>     o21 = | x/y |
> >>>
> >>> 			1             1
> >>>     o21 : Matrix frac(R)  <--- frac(R)
> >>>
> >>>     i22 : ICfractionsLong R
> >>>
> >>>     o22 = | x/y x y |
> >>>
> >>> 			1             3
> >>>     o22 : Matrix frac(R)  <--- frac(R)
> >>>
> >>>     i23 : describe R
> >>>
> >>> 	  QQ [x, y]
> >>>     o23 = ---------
> >>> 	     3    2
> >>> 	  - y  + x
> >>>
> >>> What is it?
> >>>
> >>> Do we need both functions?
> >>>
> >>> Should we change it so there is just one function with an optional
> >>> argument?
> >>
> >>
> >> --Apple-Mail-14--383249626--
> >>
> 

