-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathNoetherNormalization.m2
361 lines (316 loc) · 14.5 KB
/
NoetherNormalization.m2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
--=========================================================================--
newPackage(
"NoetherNormalization",
Version => "0.9.1",
Date => "Jan 18, 2007",
Authors => {
{Name => "Bart Snapp", Email => "snapp@coastal.edu", HomePage => "http://ww2.coastal.edu/snapp/"},
{Name => "Nathaniel Stapleton", Email => "nstaple2@math.uiuc.edu"}
},
Headline => "place an ideal in Noether normal position",
DebuggingMode => true
)
-- The algorithm given here is based on A. Logar's algorithm as given
-- in:
-- A. Logar. A Computational Proof of the Noether Normalization
-- Lemma. In: Proceedings 6th AAEEC, Lecture Notes in Computer Science
-- 357, Springer, 1989, 259--273.
-- an additional algorithm was implemented from:
-- H. Kredel and V. Weispfenning. Computing Dimension and Independent
-- sets for Polynomial Ideals. J. Symbolic Computation (1988) 6,
-- 231--247.
--=========================================================================--
export{noetherNormalization,LimitList,RandomRange}
--=========================================================================--
-- initial comments: noetherNormalization takes in an ideal I of a
-- ring R over a field k such that the dimension of I in R is d (fix
-- these symbols for all comments) and returns a linear transformation
-- that puts the ideal in Noether position as well as the independent
-- variables of R.
-- comments: The procedure integralSet takes a Groebner basis G (ie. a
-- list of polynomials) and returns the variables that already have an
-- integral relation. It does this by taking the lead monomial of each
-- polynomial and checking whether or not it consists of a power of a
-- single variable. We are assuming that the ring is over a field and
-- thus we don't check the lead coefficient.
integralSet = G -> (
J := {};
M := gens G;
for i from 0 to numgens source M - 1 do ( -- check the gens of G to see if their leadMonomial is in a single variable
if # support leadMonomial (M)_(0,i) === 1 then J = J | {support leadMonomial (M)_(0,i)} --checks how many vars are in the lead
);
J = unique flatten J; --note that according to the algorithm J is a set of integers (in fact indices), we choose to return the variables
J);
--=========================================
--comments:
-- varPrep is the initial function we run on the Groebner basis of the
-- inputted ideal I. It returns sets U and V, with U being
-- algebraically independent and V being algebraically dependent. For
-- all prime ideals it returns a maximal algebraically independent set
-- of variables whose cardinality is equal to d.
varPrep = (X,I) -> (
U := support (independentSets(I,Limit => 1))_0;
(U,X - set U)
);
--==================================================
-- comments: We use lastCheck to check that our final Groebner basis
-- (the gb of the ideal after the change of variables) witnesses the
-- integrality of each variable that should be integral. It first
-- checks that there are no elements of the Groebner basis with support
-- in the independent variables and then that each variable that
-- should be integral after the linear transformation is integral.
lastCheck = (X,G,d) -> (
M := gens G;
i := 0;
while i < numgens source M and not isSubset(support M_(0,i),toList(X_{0..d-1})) do (
i = i+1;
);
if i != numgens source M then return false
else(
if X_{d..#X-1} != integralSet(G) then return false
);
true
);
--==============================================
-- comments: inverseSequence is used to give the inverse of a ring
-- map. A ring map is given by a list explaining where each of the
-- ring's variables should go. If the ring map is just a permutation
-- of the variables then it is obviously an isomorphism and
-- inverseSequence returns the sequence that gives the inverse
-- morphism.
inverseSequence = (U,X) -> (
N := {};
for i to #X - 1 do (
for j to #U - 1 do (
if X_i == U_j then (
N = {X_j}|N;
break;
);
);
);
return N;
);
--========================================================
-- comments: randomSum is used to make the random linear
-- transformations which are candidates for putting I in
-- noetherPosition. It takes in two lists and adds the second to the
-- first with random coefficients.
randomSum1 = (U,V,k,rr) -> (
for j to #V - 1 do (
if rr == 0 then rand:= random(k) else rand=random(-rr,rr);
U=for i to #U-1 list ( if not i<j then U_i+rand*V_j else U_i)
);
return U;
);
randomSum = (U,V,k,rr) -> (
for j to #V - 1 do (
if rr == 0 then
U = apply(U, i -> i + random(k)*V_j) else
U = apply(U, i -> i + random(-rr,rr)*V_j);
);
return U;
);
--========================================================
-- comments: noetherNormalization is the main method. I is passed to
-- it by the user and it's Groebner basis is immediately computed. It
-- takes the ideal and does a random linear transformation adding to
-- the independent variables the dependent ones that are not initially
-- integral. It then checks that the transformation put the ideal in
-- Noether position. It does this by partially computing a Groebner
-- basis for the ideal until the partially computed Groebner basis
-- witnesses the integrality of all of the dependent variables. If the
-- entire Groebner basis is computed and the integrality is never
-- witnessed then we apply another random linear transformation and
-- start the process again. While doing all this we keep track of the
-- maps and the inverses of the maps that we use.
noetherNormalization = method(Options => {Verbose => false, LimitList => {5,20,40,60,80,infinity}, RandomRange => 0})
noetherNormalization(Ideal) := opts -> I -> (
A := ring I;
(flatA,fAtoFlatA) := flattenRing A;
fFlatAtoA := fAtoFlatA^-1;
-- (flatA,fAtoFlatA,fFlatAtoA) := flattenRing A;
if not isPolynomialRing A then error "expected an ideal over a polynomial ring";
k := coefficientRing flatA;
if not isField k then error "expected the ring to contain a field";
R := k (monoid [gens flatA,MonomialOrder => Lex]);
ff := map(R,flatA,gens R)*fAtoFlatA; --these maps merely change the order of the ring
ffinverse := fFlatAtoA*map(flatA, R, gens flatA); --these maps merely change the order of the ring
I = ff(I);
G = gb I;
d := dim I;
X := sort gens R;
(U,V) := varPrep(X,I);
counter := 1; --counts the number of times lastCheck is called
limitsequence := opts.LimitList; -- {5,20,40,60,80,infinity}; -- this is for the basiselementlimit setting for computing gb and is based on experience (and nothing else)
done := false;
indep := U;
f := map(R,R,inverseSequence(U|V,X));
finverse := map(R,R, reverse(U|V));
J := apply(integralSet G,i -> f i); -- may need to do a gb comp.
V = apply(V, i -> f(i)); --there might be a faster way to do this, perhaps V={x_(#U)..x_(#U+#V-1)}
U = apply(U, i -> f(i)); -- might be faster to do U = {x_0..x_(#U-1)}
Uold := U;
while not done do (
if opts.Verbose then << "--trying random transformation: " << counter << endl;
seqindex := 0;
stuff := Uold;
rr := opts.RandomRange;
if counter == 0 then U = randomSum(U,V-set J,k,rr);
if counter >= 1 then U = randomSum(U,V-set integralSet(G),k,rr);
stuff = stuff + (stuff - U);
g := map(R,R,reverse(U|V));
ginverse := map(R,R,reverse(stuff|V));
f = g*f;
finverse = finverse*ginverse;
while (not done and seqindex < #limitsequence) do (
if opts.Verbose then (<< "--trying with basis element limit: " << limitsequence_seqindex << endl;);
G = gb(f I, BasisElementLimit => limitsequence_seqindex);
done = lastCheck(X,G,d);-- may want to define f I above, but this causes noetherNormalization to fail at the moment
seqindex = seqindex + 1;
);
if counter == 5 then << "--warning: no good linear transformation found by noetherNormalization" <<endl;
if done or counter == 5 then(
ffinal = ffinverse*f*ff;
ffinalInverse = ffinverse*finverse*ff;
ffinal.cache.inverse = ffinalInverse;
ffinalInverse.cache.inverse = ffinal;
X = apply(X, i -> ffinverse i);
-- return (ffinal, ffinverse f I,map(A, k[X_{0..d-1}], X_{0..d-1}));
return (ffinal, ffinverse f I,X_{0..d-1});
);
counter = counter + 1;
); -- f puts the ideal into noether normal position. f inverse goes back to the original ring
);
nPosition = (I,X) -> (
dimI := dim I - 1;
algind := support (independentSets(I,Limit => 1))_0;
d := dim(I + ideal(X_{((#X-1)-dimI)..(#X-1)}));
return d;
);
homNoetherNormalization = (I,R,k,X) -> (
d := nPosition(I,X);
algind := support (independentSets(I,Limit => 1))_0;
f := map(R,R,reverse inverseSequence(X-set algind|algind,X));
U := apply(algind,i->f i);
V := apply(X-set algind,i->f i);
while d > 0 do (
g = map(R,R,V|randomSum(U,V,k,rr));
J := g f I;
d = dim(J+ideal(apply(algind,i->f i)));
);
return g*f;
);
--======================================================================================================================
noetherNormalization(QuotientRing) := noetherNormalization(PolynomialRing) := opts -> R -> (
if not isPolynomialRing ring ideal R then error "expected a quotient of a polynomial ring";
noetherNormalization(ideal R, Verbose => opts.Verbose)
);
--=========================================================================--
beginDocumentation() -- the start of the documentation
-----------------------------------------------------------------------------
document {
Key => NoetherNormalization,
Headline => "routines related to Noether normalization",
EM "NoetherNormalization", " is a package for computing ring homomorphisms
which will place ideals in Noether normal position. The algorithms
used are based on algorithms found in A. Logar's paper: A
Computational Proof of the Noether Normalization Lemma. In:
Proceedings 6th AAEEC, Lecture Notes in Computer Science 357,
Springer, 1989, 259-273."
}
-----------------------------------------------------------------------------
document {
Key => {noetherNormalization,
(noetherNormalization,Ideal),
(noetherNormalization,QuotientRing),
(noetherNormalization,PolynomialRing),
LimitList,
RandomRange,
[noetherNormalization,LimitList],
[noetherNormalization,RandomRange],
[noetherNormalization,Verbose]
},
Headline => "data for Noether normalization",
Usage => "(f,J,X) = noetherNormalization C",
Inputs => {
"C" => null => {"which is either ", ofClass Ideal, " ", TT "I", ", or ", ofClass QuotientRing, " ", TT "R/I", " where ", TT "R", " is ", ofClass PolynomialRing },
LimitList => List => "gives the value which ", TO "BasisElementLimit", "will take",
RandomRange => ZZ => "if not 0, gives a integer bound for the random coefficients. If 0, then chooses random elements from the coefficient field."
},
Outputs => {
"f" => RingMap => {"an automorphism of ", TT "R"},
"J" => Ideal => { "the image of ", TT "I", " under ", TT "f"},
"X" => List => { "a list of variables which are algebraically independent in ", TT "R/J"},
},
"The computations performed in the routine ", TT "noetherNormalization", " use a random linear change of coordinates,
hence one should expect the output to change each time the routine is executed.",
EXAMPLE lines ///
R = QQ[x_1..x_4];
I = ideal(x_2^2+x_1*x_2+1, x_1*x_2*x_3*x_4+1);
(f,J,X) = noetherNormalization I
///,
"The next example shows how when we use the lexicographical ordering, we can see the integrality of ",
TT "R/ f I", " over the polynomial ring in ", TT "dim(R/I)", " variables:",
EXAMPLE lines ///
R = QQ[x_1..x_5, MonomialOrder => Lex];
I = ideal(x_2*x_1-x_5^3, x_5*x_1^3);
(f,J,X) = noetherNormalization I
transpose gens gb J
///,
"If ", TT "noetherNormalization", " is unable to place the ideal into the desired position after a few tries, the following warning is given:",
EXAMPLE lines ///
R = ZZ/2[a,b];
I = ideal(a^2*b+a*b^2+1);
(f,J,X) = noetherNormalization I
///,
"Here is an example with the option ", TT "Verbose => true", ":",
EXAMPLE lines ///
R = QQ[x_1..x_4];
I = ideal(x_2^2+x_1*x_2+1, x_1*x_2*x_3*x_4+1);
(f,J,X) = noetherNormalization(I,Verbose => true)
///,
"The first number in the output above gives the number of
linear transformations performed by the routine while attempting to
place ", TT "I", " into the desired position.
The second number tells which ", TO "BasisElementLimit", " was used when computing the (partial) Groebner basis.
By default, ", TT "noetherNormalization", " tries to use a partial
Groebner basis. It does this by sequentially computing a Groebner
basis with the option ", TO "BasisElementLimit", " set to
predetermined values. The default values come from the following list:", TT "{5,20,40,60,80,infinity}",
". To set the values manually, use the option ", TT "LimitList", ":",
EXAMPLE lines ///
R = QQ[x_1..x_4];
I = ideal(x_2^2+x_1*x_2+1, x_1*x_2*x_3*x_4+1);
(f,J,X) = noetherNormalization(I,Verbose => true,LimitList => {5,10})
///,
"To limit the randomness of the coefficients, use the option ", TT "RandomRange",
". Here is an example where the coefficients of the linear transformation are
random integers from ", TT "-2", " to ", TT "2", ":",
EXAMPLE lines ///
R = QQ[x_1..x_4];
I = ideal(x_2^2+x_1*x_2+1, x_1*x_2*x_3*x_4+1);
(f,J,X) = noetherNormalization(I,Verbose => true,RandomRange => 2)
///,
PARA {
"This symbol is provided by the package ", TO NoetherNormalization, "."
}
}
--=========================================================================--
--======================================================================================================================
--Assertions
TEST ///
--uninstallPackage "NoetherNormalization"
--installPackage "NoetherNormalization"
A = QQ[x_1..x_4]
I = ideal(x_1^2 + x_1*x_4+1,x_1*x_2*x_3*x_4+1)
assert((noetherNormalization(I))_2=={x_4,x_3})
///
TEST ///
--loadPackage "NoetherNormalization"
R = QQ[x,y]
I = ideal (y^2-x^2*(x+1))
(F,J,xs) = noetherNormalization I
assert(F === map(R,R,{x, y}))
assert(J == ideal(-x^3-x^2+y^2))
assert(xs == {y})
///