source: git/Singular/LIB/hodge.lib

spielwiese
Last change on this file was 7c7a10, checked in by Hans Schoenemann <hannes@…>, 3 years ago
chg: size(ringlist(..)..) -> nvars/npars/ring_list(..)
  • Property mode set to 100644
File size: 16.5 KB
Line 
1////////////////////////////////////////////////////////////////
2version="version hodge.lib 4.2.0.0 Feb_2021 "; // $Id$
3category="Noncommutative";
4info="
5LIBRARY:  hodge.lib  Algorithms for Hodge ideals
6
7AUTHORS:  Guillem Blanco, email: guillem.blanco@kuleuven.be
8
9OVERVIEW:
10A library for computing the Hodge ideals [MP19] of Q-divisors associated to any reduced hypersurface @math{f \in R}.
11@* The implemented algorithm [Bla21] is based on the characterization of the Hodge ideals in terms of the @math{V}-filtration of Malgrange and Kashiwara on @math{R_f f^s}, see [MP20].
12@* As a consequence, this library provides also an algorithm to compute the multiplier ideals and the jumping numbers of any hypersurface, see [BS05].
13
14REFERENCES:
15@*[Bla21] G. Blanco, An algorithm for Hodge ideals, to appear.
16@*[BS05] N. Budur, M. Saito, Multiplier ideals, V-filtration, and spectrum, J. Algebraic Geom. 14 (2005), no. 2, 269-282. 2, 4
17@*[MP19] M. Mustata, M. Popa: Hodge ideals, Mem. Amer. Math. Soc. 262 (2019), no. 1268
18@*[MP20] M. Mustata, M. Popa: Hodge ideals for Q-divisors, V-filtration, and minimal exponent, Forum Math. Sigma 8 (2020), no. e19, 41 pp.
19
20KEYWORDS: Hodge ideals; V-filtration; Multiplier ideals; Jumping numbers
21
22PROCEDURES:
23  Vfiltration(f, p [, eng]);  compute @math{R}-generators for the @math{V}-filtration on @math{R_f f^s} truncated up to degree @math{p} in @math{\partial_t}.
24  hodgeIdeals(f, p [, eng]);  compute the Hodge ideals of @math{f^\alpha} up to level @math{p}, for a reduced hypersurface @math{f \in R}.
25  multIdeals(f, p [, eng]);   compute the multiplier ideals of a hypersurface @math{f \in R}.
26  nextHodgeIdeal(f, I, p);  given the @math{p}-th Hodge ideal @math{I} of @math{f^\alpha} compute the @math{p+1}-th Hodge ideal assuming that the Hodge filtration of the underlying mixed Hodge module is generated at level less than or equal to @math{p}.
27
28SEE ALSO: dmodapp_lib
29";
30
31LIB "dmod.lib"; // SannfsBM, vec2poly, bFactor
32
33// Test whether the polynomial f is reduced or not.
34static proc isReduced(poly f) {
35  // Compute square-free part.
36  ideal j = jacob(f); poly g = f;
37  for (int i = 1; i <= size(j); i++) { g = gcd(g, j[i]); }
38  return(g == 1);
39}
40
41// The Q-polynomial as defined by Mustata & Popa.
42static proc Qpoly(int k, number a) {
43  poly Q = 1;
44  for (int i = 1; i <= k; i++) { Q = Q*(a+i-1); }
45  return(Q);
46}
47
48// The procedure to compute the truncated V-filtration.
49proc Vfiltration(poly f, int p, list #)
50"USAGE:    Vfiltration(f, p [, eng]);     f a poly, p a non-negative integer, eng an optional integer.
51RETURN:    ring
52PURPOSE:   compute @math{R}-generators for the @math{V}-filtration on @math{R_f f^s} truncated up to degree @math{p} in @math{\partial_t}.
53NOTE:      activate the output ring with the @code{setring} command.
54@*In the output ring, the list @code{Vfilt} contains the @math{V}-filtration.
55@*The value of @code{eng} controls the algorithm used for Groebner basis computations.
56@*See the @code{engine} procedure from @ref{dmodapp_lib} for the available algorithms.
57DISPLAY:   If @code{printlevel}=1, progress debug messages will be printed.
58EXAMPLE:   example Vfiltration; shows an example
59"
60{
61  // The level 'p' must be a non-negative integer.
62  if (p < 0) { ERROR("Level p must be non-negative."); }
63  // The base ring must be non-commutative.
64  if (size(ring_list(basering)) > 4) { ERROR("Base ring must be commutative."); }
65
66  // Default engine & option.
67  int slimgb_ = 0; int eng = slimgb_;
68  // The first optional argument must be an integer.
69  if (size(#) >= 1) {
70    if (typeof(#[1]) == "int") { eng = int(#[1]); }
71    else { ERROR("First argument must be an integer."); }
72    // The check that the engine number is valid will be done by the engine.
73  }
74
75  // Save basering & set basic variables.
76  def @R = basering; int N = nvars(@R);
77  int ppl = printlevel - voice + 2; int i, j; string str;
78  list Names = ringlist(@R)[2]; list Dnames;
79  for (i = 1; i <= N; i++) { Dnames = Dnames + list("D" + Names[i]); }
80
81  // No variable can be named 't' or 'Dt'.
82  for (i = 1; i <= size(Names); i++) {
83    if (Names[i] == "t" || Names[i] == "Dt" || Names[i] == "a") {
84      ERROR("Variable names should not include 't', 'Dt' or 'a'");
85    }
86  }
87
88  // Compute s-parametric annhilator of f via BM algorithm & move to D[s].
89  dbprint(ppl, "// -1-1- Computing the annhilator of f^s...");
90  // SannfsBM returns a ring with elimination ordering for s.
91  def @Ds = SannfsBM(f, slimgb_); setring(@Ds);
92  dbprint(ppl, "// -1-2- Annhilator of f^s computed in @Ds");
93
94  list RL = ringlist(basering); list RL1;
95  RL1[1] = RL[1]; //char.
96  RL1[2] = list("s") + Dnames + Names;
97  //RL1[3] = list(list("dp", 1:1), list("dp", 1:N), list("dp", 1:N), list("C", 0));
98  RL1[3] = list(list("c", 0), list("dp", 1:1), list("dp", 1:N), list("dp", 1:N));
99  RL1[4] = RL[4]; //min. poly.
100  // Make new ring non-commutative.
101  ring @Ds1 = ring(RL1); matrix @Dmat[2*N+1][2*N+1];
102  for (i = 1; i <= N; i++) { @Dmat[i+1, N+1+i] = -1; }
103  def @Ds2 = nc_algebra(1, @Dmat); setring @Ds2; kill @Ds1;
104
105  // Move annihilator & f to the new ring.
106  ideal Annfs = imap(@Ds, LD); poly f = imap(@R, f);
107
108  // Compute the B-S polynomial of f.
109  dbprint(ppl, "// -2-1- Computing Groebner basis of Ann f^s + <f>...");
110  // The partial derivatives trick might make everything run a bit faster.
111  ideal I = engine(Annfs+f+jacob(f), eng);
112  dbprint(ppl, "// -2-2- Groebner basis of Ann f^s + <f> computed");
113  dbprint(ppl, "// -2-3- Intersecting Ann f^s + <f> with QQ[s]...");
114  // Add the missing s = -1 root.
115  poly bfct = vec2poly(pIntersect(s, I))*(var(1)+1);
116  list BS = bFactor(bfct);
117  dbprint(ppl, "// -2-4- Intersection of Ann f^s + <f> with QQ[s] finished");
118
119  // Shifts feigen = delete(eigen, i); mul = delete(mul, i);or the annihilator of f^s.
120  int m = -p; int k = 1;
121  ideal J = subst(Annfs, s, s+m)+f^(k-m);
122
123  // Shift roots of the BS to (0, 1], this avoids having to compute the BS of J.
124  list eigen; list mul;
125  for (i = 1; i <= size(BS[1]); i++) {
126    for (j = 0; j <= p; j++) {
127      if (BS[1][i]+j < 0) {
128        eigen = eigen+list(number(-BS[1][i]-j));
129        mul = mul+list(BS[2][i]);
130      }
131    } // Sort shifted eigen.
132  } list S = sort(eigen); eigen = S[1]; mul = mul[S[2]];
133
134  // Remove duplicates & keep max. multiplicity.
135  for (i = 1; i <= size(eigen) - 1; i++) {
136    j = 1; while (eigen[i] == eigen[i+j]) { mul[i] = max(mul[i], mul[i+j]); j++; }
137    while (j != 1) { eigen = delete(eigen, i+j-1); mul = delete(mul, i+j-1); j--; }
138  }
139
140  // Compute the kernels of the eigenvalues in 'eigen' in J.
141  str = sprintf("// -3-1- Computing the kernels of the eigenvalues of Dt*t... (p = %p)",
142    p); dbprint(ppl, str);
143  list Ker; ideal K;
144  for (i = 1; i <= size(eigen); i++) {
145    str = sprintf("// -3-1-%p- Kernel for eigenvalue %p, multiplicity %p... (%p/%p)",
146      i, eigen[i], mul[i], i, size(eigen)); dbprint(ppl, str);
147    // *NO* need to add f^(k-m) as Ker[i] contains J = Annf^(s+m) + f^(k-m).
148    Ker[i] = ideal(modulo(s + eigen[i], J));
149    // If there are multiplicities, iterate the generalized eigenspaces.
150    for (j = 1; j < mul[i]; j++) {
151      // Reduce the number of generators before calling modulo.
152      K = engine(Ker[i], eng);
153      Ker[i] = ideal(modulo(s + eigen[i], K));
154    }
155  }
156
157  // Compress the kernels of the eigenvalues greater than 1.
158  for (i = size(eigen)-1; i > 0 && eigen[i] > 1; i--) {
159    Ker[i] = Ker[i] + Ker[i+1]; Ker = delete(Ker, i+1);
160    eigen = delete(eigen, i+1); mul = delete(mul, i+1);
161  }
162  // Heuristically, it is better to compute a Groebner basis here before
163  // doing the elimination of the variables.
164  dbprint(ppl, "// -3-3- Computing Groebner basis of kernels...");
165  for (i = 1; i <= size(Ker); i++) { Ker[i] = engine(Ker[i], eng); }
166
167  // Create new ring with elimination order for _Dx.
168  list RL = ringlist(basering); list RL1;
169  RL1[1] = RL[1]; //char.
170  RL1[2] = Dnames + list("s") + Names;
171  RL1[3] = list(list("dp", 1:N), list("dp", 1:(N+1)), list("C", 0)); //orders.
172  RL1[4] = RL[4]; //min. poly.
173  // Make new ring non-commutative.
174  ring @Ds3 = ring(RL1);
175  matrix @Dmat[2*N+1][2*N+1];
176  for (i = 1; i <= N; i++) { @Dmat[i, N+i+1] = -1; }
177  def @Ds4 = nc_algebra(1, @Dmat); setring @Ds4; kill @Ds3;
178  dbprint(ppl, "// -4-1- The elimination ring @Ds4(_Dx,s,_x) is ready...");
179
180  // Map things to the new ring and eliminate
181  dbprint(ppl, "// -4-2- Moving kernels to the new elimination ring...");
182  list Ker = imap(@Ds2, Ker); poly f = imap(@Ds2, f); list eigen = imap(@Ds2, eigen);
183
184  dbprint(ppl, "// -4-3- Starting the elimination of _Dx in the V-filtration...");
185  int n = size(Ker); list S; S[n] = engine(Ker[n], eng); list H;
186  for (i = n - 1; i > 0; i--) {
187    str = sprintf("// -4-3-%p- Elimination for eigenvalue %p... (%p/%p)", n-i,
188      eigen[i], n-i, n); dbprint(ppl, str);
189    S[i] = engine(Ker[i] + S[i+1], eng);
190    H[i] = nselect(S[i], 1..N);
191  }
192  dbprint(ppl, "// -4-4- The variables _Dx are eliminated");
193
194  // Create new commutative ring with block order (s)(x_).
195  list RL = ringlist(basering); list RL1;
196  RL1[1] = RL[1]; //char.
197  RL1[2] = list("s") + Names; //vars.
198  RL1[3] = list(list("dp", 1), list("dp", 1:N), list("C", 0)); //orders.
199  RL1[4] = RL[4]; //min. poly.
200  // Make new ring non-commutative.
201  ring @R1 = ring(RL1); setring(@R1);
202  dbprint(ppl, "// -4-5- The commutative ring s,_x is ready");
203
204  // Compute Groebner bases for H in the new ring.
205  list H = imap(@Ds4, H);
206  dbprint(ppl, "// -4-6- Computing Groebner basis of the H ideals in the new ring...");
207  for (i = 1; i <= size(H); i++) { H[i] = slimgb(H[i]); }
208  dbprint(ppl, "// -4-7- Groebner basis of the H ideals computed");
209
210  // Create new ring (Dt,t,x_) where s -> -Dt*t.
211  list RL = ringlist(basering); list RL1;
212  RL1[1] = RL[1]; //char.
213  RL1[2] = list("Dt", "t") + Names; //vars.
214  RL1[3] = list(list("dp", 1:2), list("dp", 1:N), list("C", 0)); //orders.
215  RL1[4] = RL[4]; //min. poly.
216  // Make new ring non-commutative.
217  ring @Ds5 = ring(RL1);
218  matrix @Dmat[N+2][N+2]; @Dmat[1, 2] = -1;
219  def @Ds6 = nc_algebra(1, @Dmat); setring @Ds6; kill @Ds5;
220  dbprint(ppl, "// -5-1- The ring @Ds6(t,Dt,_x) is ready");
221
222  // Move things to the new (Dt,t,x_) ring.
223  def Max = maxideal(1); ideal J = -Dt*t;
224  for (i = 3; i <= N + 2; i++) { J = J + Max[i]; }
225  dbprint(ppl, "// -5-2- Moving H ideals to the new (Dt,t,_x) ring...");
226  map Map = @R1, J; list H = Map(H);
227  poly f = imap(@Ds4, f); list eigen = imap(@Ds4, eigen);
228
229  // Subtitute t = f and *exactly* divide H ideals by f^p.
230  dbprint(ppl, "// -5-3- Substituting t = f and dividing by f^p...");
231  list Vfilt;
232  for (i = 1; i <= size(H); i++) {
233    // Append the corresponding eigenvalue and its multiplicity to the output.
234    Vfilt[i] = list(list(), poly(eigen[i]), mul[i]);
235    for (j = 1; j <= size(H[i]); j++) {
236      if (leadexp(H[i][j])[1] <= p) {
237        Vfilt[i][1] = Vfilt[i][1] + list(subst(H[i][j], var(2), f)/f^p);
238      }
239    }
240  } export(Vfilt); return(@Ds6);
241}
242example
243{
244  "EXAMPLE:"; echo = 2;
245  ring R = 0,(x,y),dp;
246  poly f = y^2-x^3;
247  def D = Vfiltration(f, 1);
248  setring D; Vfilt;
249}
250
251proc hodgeIdeals(poly f, int p, list #)
252"USAGE:    hodgeIdeals(f, p [, eng]);    f a reduced poly, p a non-negative integer, eng an optional integer.
253RETURN:    ring
254PURPOSE:   compute the Hodge ideals of @math{f^\alpha} up to level @math{p}, for a reduced hypersurface @math{f}.
255NOTE:      activate the output ring with the @code{setring} command.
256@*In the output ring, the list of ideals @code{hodge} contains the Hodge ideals of @math{f}.
257@*The value of @code{eng} controls the algorithm used for Groebner basis computations.
258@*See the @code{engine} procedure from @ref{dmodapp_lib} for the available algorithms.
259DISPLAY:   If @code{printlevel}=1, progress debug messages will be printed.
260EXAMPLE:   example hodgeIdeals; shows an example
261"
262{
263  // Equation 'f' must be reduced.
264  if (!isReduced(f)) { ERROR("Polynomial f must be reduced."); }
265
266  def @R = basering; int N = nvars(@R);
267  list Trans = ringlist(@R)[1];
268  list Names = ringlist(@R)[2];
269  // Check for name collisions within Transcendental parameters.
270  int i, j;
271  if (size(Trans) != 1) {
272    for (i = 1; i <= size(Trans[2]); i++) {
273      if (Trans[2][i] == "t" || Trans[2][i] == "Dt" || Trans[2][i] == "a") {
274        ERROR("Transcendental parameters should not include 't', 'Dt' or 'a'");
275      }
276    }
277  }
278
279  int ppl = printlevel - voice + 2;
280  printlevel = printlevel + 1;
281  // Start by computing the Vfiltration of f truncated at level p.
282  def @Ddt = Vfiltration(f, p, #); setring(@Ddt);
283  printlevel = printlevel - 1;
284
285  // Commutative (x_) ring with trascendental parameter 'a'.
286  list RL = ringlist(basering); list RL1;
287  if (size(RL[1]) == 0) { // no transcendental parameters in basering.
288    RL1[1] = list(RL[1], list("a"), list(list("lp", 1)), ideal(0));
289  } else { // trascendental parameters already in basering.
290    RL1[1] = RL[1]; RL1[1][2] = RL1[1][2] + list("a");
291    RL1[1][3][1][2] = RL1[1][3][1][2],1;
292  }
293  RL1[2] = list("Dt") + Names; //vars.
294  RL1[3] = list(list("dp", 1), list("dp", 1:N), list("C", 0)); //orders.
295  RL1[4] = RL[4]; //min. poly.
296  // Make new ring non-commutative.
297  ring @R2 = ring(RL1); setring(@R2);
298  dbprint(ppl, "// -6-1- The commutative ring (a),_x is ready");
299  list Vfilt = imap(@Ddt, Vfilt); poly f = imap(@R, f);
300
301  option(redSB);
302  // Finally step, compute Hodge ideals using Theorem A' of Mustata & Popa.
303  dbprint(ppl, "// -6-2- Computing Hodge ideals...");
304  list hodge; ideal Iq; poly g, mon; int q, l, dg;
305  // For each eigenvalue...
306  for (i = 1; i <= size(Vfilt); i++) {
307    hodge[i] = list(list(), Vfilt[i][2], Vfilt[i][3]);
308    // For each level q = 0,1,..,p we have a the q-th Hodge ideal 'Iq'.
309    for (q = 0; q <= p; q++) { Iq = 0;
310      // For each generator of H[i], compute a generator g of the Hodge ideal.
311      for (j = 1; j <= size(Vfilt[i][1]); j++) { g = 0;
312        // Select only the generators of H[i] with degree <= q in Dt.
313        if (leadexp(Vfilt[i][1][j])[1] <= q) {
314          // For each monomial term of the j-th generator of H[i]...
315          for (l = 1; l <= size(Vfilt[i][1][j]); l++) {
316            mon = Vfilt[i][1][j][l]; dg = leadexp(mon)[1];
317            // Apply Theorem A' of Mustata & Popa.
318            g = g + Qpoly(dg, a)*f^(q-dg)*(mon/Dt^dg);
319          } // Add a new element of the q-th Hodge ideal.
320        } Iq = Iq + g;
321      // Save a reduced GB of the q-th Hodge ideal of the i-th eigenvalue.
322      } hodge[i][1] = hodge[i][1] + list(slimgb(Iq));
323    }
324  } option(noredSB);
325
326  export(hodge); return(@R2);
327}
328example
329{
330  "EXAMPLE:"; echo = 2;
331  ring R = 0,(x,y),dp;
332  poly f = y^2-x^3;
333  def Ra = hodgeIdeals(f, 2);
334  setring Ra; hodge;
335}
336
337proc multIdeals(poly f, list #)
338"USAGE:    multIdeals(f, [, eng]);    f a reduced poly, eng an optional integer.
339RETURN:    list
340PURPOSE:   compute the multiplier ideals of a hypersurface @math{f \in R}.
341NOTE:      The value of @code{eng} controls the algorithm used for Groebner basis computations.
342@* See the @code{engine} procedure from @ref{dmodapp_lib} for the available algorithms.
343DISPLAY:   If @code{printlevel}=1, progress debug messages will be printed.
344EXAMPLE:   example multIdeals; shows an example
345"
346{
347  // Compute the Vfiltration of f truncated at level 0.
348  printlevel = printlevel + 1;
349  def @Ddt = Vfiltration(f, 0, #);
350  printlevel = printlevel - 1;
351
352  // Compute Hodge ideals using Theorem 0.1 of Budur & Saito.
353  list Vfilt = imap(@Ddt, Vfilt);
354  list multIdeals; int i, j;
355  option(redSB);
356  for (i = 1; i <= size(Vfilt); i++) {
357    multIdeals[i] = list(ideal(), Vfilt[i][2], Vfilt[i][3]);
358    for (j = 1; j <= size(Vfilt[i][1]); j++) {
359      multIdeals[i][1] = multIdeals[i][1] + Vfilt[i][1][j];
360    } // Cosmetic Groebner basis.
361    multIdeals[i][1] = slimgb(ideal(multIdeals[i][1]));
362  } option(noredSB);
363
364  return(multIdeals);
365}
366example
367{
368  "EXAMPLE:"; echo = 2;
369  ring R = 0,(x,y),dp;
370  poly f = y^2-x^3;
371  multIdeals(f);
372}
373
374// If I is the p-th Hodge ideal and the Hodge filtration is generated at
375// level p, return the (p+1)-th Hodge ideal.
376proc nextHodgeIdeal(poly f, ideal I, int p)
377"USAGE:    nextHodgeIdeal(f, I, p);  f a poly, I an ideal, p a non-negative integer
378RETURN:    ideal
379PURPOSE:   given the @math{p}-th Hodge ideal @math{I} of @math{f^\alpha} compute the @math{p+1}-th Hodge ideal assuming that
380@*the Hodge filtration of the underlying mixed Hodge module is generated at level less than or equal to @math{p}.
381EXAMPLE:   example nextHodgeIdeal; shows an example
382"
383{
384  int N = nvars(basering); ideal J = f*I; int i, j;
385  for (i = 1; i <= size(I); i++) {
386    for (j = 1; j <= N; j++) {
387      J = J + (f*diff(I[i], var(j)) - (a + p)*I[i]*diff(f, var(j)));
388    }
389  } return(slimgb(J));
390}
391example
392{
393  "EXAMPLE:"; echo = 2;
394  ring R = 0,(x,y),dp;
395  poly f = y^2-x^3;
396  def Ra = hodgeIdeals(f, 2);
397  setring(Ra);
398  int p = 1;
399  nextHodgeIdeal(y^2-x^3, hodge[3][1][p+1], p);
400}
Note: See TracBrowser for help on using the repository browser.