/
VirtualResolutions.m2
665 lines (626 loc) · 32.5 KB
/
VirtualResolutions.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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
---------------------------------------------------------------------------
-- PURPOSE : Construct, display, and study virtual resolutions for products
-- of projective spaces.
--
-- PROGRAMMERS : Ayah Almousa, Christine Berkesch, Juliette Bruce,
-- David Eisenbud, Daniel Erman, Michael Loper,
-- Mahrud Sayrafi, and Greg Smith.
--
-- UPDATE HISTORY : created 14 April 2018 at M2@UW;
-- updated 15 April 2019 at IMA Coding Sprint.
-- updated 16 April 2020 for JSAG
-- updated 17 April 2021 with new regularity algorithm
---------------------------------------------------------------------------
newPackage ("VirtualResolutions",
Version => "1.4",
Date => "May 06, 2021",
Headline => "Methods for virtual resolutions on products of projective spaces",
Authors =>{
{Name => "Ayah Almousa", Email => "aka66@cornell.edu", HomePage => "http://pi.math.cornell.edu/~aalmousa "},
{Name => "Christine Berkesch", Email => "cberkesc@umn.edu", HomePage => "http://math.umn.edu/~cberkesc/"},
{Name => "Juliette Bruce", Email => "jebruce2@wisc.edu", HomePage => "https://juliettebruce.github.io"},
{Name => "David Eisenbud", Email => "de@msri.org", HomePage => "http://www.msri.org/~de/"},
{Name => "Michael Loper", Email => "loper012@umn.edu", HomePage => "http://math.umn.edu/~loper012/"},
{Name => "Mahrud Sayrafi", Email => "mahrud@umn.edu", HomePage => "http://math.umn.edu/~mahrud/"}
},
Keywords => {"Commutative Algebra", "Homological Algebra"},
PackageImports => {"Elimination", "Depth", "Saturation", "SpaceCurves"},
PackageExports => {"NormalToricVarieties", "TateOnProducts", "LinearTruncations"},
AuxiliaryFiles => true,
DebuggingMode => false,
Certification => {
"journal name" => "The Journal of Software for Algebra and Geometry",
"journal URI" => "https://msp.org/jsag/",
"article title" => "The virtual resolutions package for Macaulay2",
"acceptance date" => "19 May 2020",
"published article URI" => "https://msp.org/jsag/2020/10-1/p06.xhtml",
"published article DOI" => "10.2140/jsag.2020.10.51",
"published code URI" => "https://msp.org/jsag/2020/10-1/jsag-v10-n1-x06-VirtualResolutions.zip",
"repository code URI" => "https://github.com/Macaulay2/M2/blob/master/M2/Macaulay2/packages/VirtualResolutions.m2",
"release at publication" => "28038a52dcc3b0ad7adfd2562a9cd6b6414a6636",
"version at publication" => "1.2",
"volume number" => "10",
"volume URI" => "https://msp.org/jsag/2020/10-1/"
}
)
importFrom_Core { "raw", "rawKernelOfGB" }
importFrom_LinearTruncations { "gradedPolynomialRing" }
export{
"curveFromP3toP1P2",
"idealSheafGens",
"isVirtual",
"virtualOfPair",
"resolveViaFatPoint",
"randomRationalCurve",
"randomMonomialCurve",
"randomCurveP1P2",
"multigradedRegularity",
-- TODO: should we export these or fix NormalToricVarieties/TateOnProducts?
--"normalToricVarietyFromTateData",
--"normalToricVarietyWithTateData",
--"imbueRingWithTateData",
-- Options
"LowerLimit",
"UpperLimit",
"Attempt",
"PreserveDegree",
"GeneralElements"
}
--------------------------------------------------------------------
--------------------------------------------------------------------
----- CODE
--------------------------------------------------------------------
--------------------------------------------------------------------
-- Helper for saturation with respect to irrelevant ideal
ourSaturation = (I,irr) -> saturate(I, decompose irr, Strategy => Eliminate);
-- Helper for isVirtual, checks whether a module sheafifies to the zero sheaf
-- TODO: export this, either here or in NormalToricVarieties. Could be renamed to isFiniteLength
-- TODO: the "Support" strategy sometimes causes engine error:
-- terminate called after throwing an instance of 'std::logic_error'
-- what(): ERROR: Inserted duplicate entry into a KD tree.
isZeroSheaf = method(TypicalValue => Boolean, Options => { Strategy => null })
isZeroSheaf(NormalToricVariety, Module) := opts -> (X, M) -> isZeroSheaf(ideal X, M, opts)
isZeroSheaf(Ideal, Module) := opts -> (B, M) -> (
-- TODO: either cache this, or isSupportedInZeroLocus
if opts.Strategy === "Support" then isSupportedInZeroLocus(B, M)
else (J := ann M) == 1 or J != 0 and ourSaturation(J, B) == 1)
isIsomorphismOfSheaves = method(TypicalValue => Boolean, Options => options isZeroSheaf)
isIsomorphismOfSheaves(Ideal, Matrix) := opts -> (B, f) -> (
isZeroSheaf(B, ker f, opts) and isZeroSheaf(B, coker f, opts))
-- Helper for virtualOfPair
-- TODO: complete this into the dual of submatrixByDegrees
submatrixWinnow = (m, alphas) -> (
col := positions(degrees source m, deg -> any(alphas, alpha -> all(alpha - deg, x -> x >= 0)));
row := positions(degrees target m, deg -> any(alphas, alpha -> all(alpha - deg, x -> x >= 0)));
submatrix(m, row, col))
submatrixWinnowMap = (phi, alphas) -> (
col := positions(degrees source phi, deg -> any(alphas, alpha -> all(alpha - deg, x -> x >= 0)));
submatrix(phi, , col))
--------------------------------------------------------------------
--------------------------------------------------------------------
--Input: F a free chain complex on Cox(X), alphas a list of degrees
--Output: A subcomplex of summands generated only in degrees in the list alphas.
--Given a ring and its free resolution, keeps only the summands in resolution of specified degrees
--If the list alphas contains only one element, the output will be summands generated in degree less than or equal to alpha.
--See Algorithm 3.4 of [BES]
--------------------------------------------------------------------
--------------------------------------------------------------------
protect winnowingMap
virtualOfPair = method(Options => {LengthLimit => infinity})
-- TODO: return a Matrix in the Module case and ChainComplexMap in the ChainComplex case
-- TODO: document the winnoingMap
virtualOfPair(Ideal, List) := ChainComplex => opts -> (I, alphas) -> virtualOfPair(comodule I, alphas, opts)
virtualOfPair(Module, List) := ChainComplex => opts -> (M, alphas) -> (
R := ring M;
if M.cache.?resolution then return virtualOfPair(M.cache.resolution, alphas, opts);
if any(alphas, alpha -> #alpha =!= degreeLength R) then error "degree has wrong length";
m := schreyerOrder gens gb presentation M;
m = submatrixWinnow(m, alphas);
i := 2;
L := {m} | while m != 0 and i <= opts.LengthLimit list (
i = i + 1; m = map(R, rawKernelOfGB raw m); m = submatrixWinnow(m, alphas));
chainComplex L)
virtualOfPair(ChainComplex, List) := ChainComplex => opts -> (F, alphas) -> (
if any(alphas, alpha -> #alpha =!= degreeLength ring F) then error "degree has wrong length";
L := chainComplex apply(min F .. max F - 1, i -> submatrixWinnow(F.dd_(i+1), alphas));
-- winnowingMap is the map M --> HH_0 F
M := HH_0 F;
N := HH_0 L;
-- TODO: if the pruning map is the same for two different alphas, the ability to use the
-- same map would allow for a significant speedup in isVirtualOfPair and isIsomorphismOfSheaves
-- how can we cache this in F?
phi := map(M, source F.dd_0, id_(F_0));
phi = submatrixWinnowMap(phi, alphas);
-- TODO: return a single map or a chain complex map?
L.cache.winnowingMap = map(M, N, phi);
L)
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (J,irr,A)=(Ideal,Ideal,List) where J defines a 0-dim
----- subscheme and irr is the irrelevant ideal
----- Output: A virtual resolution of S/J, which is potentially short.
----- Description: This function implements Theorem 4.1 of [BES].
----- In particular, it computes a virtual resolution of S/J by
----- computing a graded minimal free resolution of S/(J\cap B^A).
----- By the theorem this might be a short virtual resolution
--------------------------------------------------------------------
--------------------------------------------------------------------
resolveViaFatPoint = method()
resolveViaFatPoint(Ideal, Ideal, List) := ChainComplex => (J, irr, A) -> (
L := decompose irr;
if #A != #L then error("resolveViaFatPoint: expected exponent vector of length " | toString degreeLength irr);
-- note: decompose doesn't necessarily return in the right order
Q := intersect for X in L list (
D := degree X_0;
d := (select((0..#D-1), i -> D#i == 1))_0;
X ^ (A#d)
);
res intersect (Q, J)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
-- This method checks if a given complex is a virtual resolution by computing
-- homology and checking whether its annihilator saturates to the whole ring.
-- Input: Ideal irr - the irrelevant ideal of the ring
-- Chain Complex C - proposed virtual resolution
-- Output: Boolean - true if complex is virtual resolution, false otherwise
-- Note: the Determinantal strategy is based on Theorem 1.3 of [Loper2019].
--------------------------------------------------------------------
--------------------------------------------------------------------
-- TODO: can this use winnowingMap?
isVirtual = method(TypicalValue => Boolean, Options => {Strategy => null})
isVirtual(NormalToricVariety, ChainComplex) := opts -> (X, C) -> isVirtual(ideal X, C)
isVirtual(Ideal, ChainComplex) := opts -> (irr, C) -> (
S := ring irr;
if S =!= ring C then error "isVirtual: expected objects in the same ring";
-- if strategy "determinantal is selected, the method checks virtuality
-- via the depth criterion on the saturated ideals of minors
debugInfo := if debugLevel < 1 then identity else i -> printerr("isVirtual: the complex is not virtual at homological degree ", toString i);
if opts.Strategy === "Determinantal" then (
for i from 1 to length(C) do (
if rank(source(C.dd_i)) != (rank(C.dd_i) + rank(C.dd_(i+1))) then (
debugInfo i; return false));
for i from 1 to length(C) do (
minor := minors(rank(C.dd_i),C.dd_i);
minorSat := ourSaturation(minor,irr);
if depth(minorSat, S) < i then (
debugInfo i; return false));
return true);
-- default strategy is calculating homology and checking homology is
-- supported on irrelevant ideal
for i from 1 to length(C) do (
if not isZeroSheaf(irr, HH_i C) then (
debugInfo i; return false));
true)
--------------------------------------------------------------------
--------------------------------------------------------------------
-- Input: ZZ n - size of subset of generators to check
-- Ideal J - ideal of ring
-- Ideal irr - irrelevant ideal
-- Output: a list of ideals generated by subsets of size n of the generators of J
-- that give the same ideal as J up to saturation by the irrelevant ideal
--------------------------------------------------------------------
--------------------------------------------------------------------
idealSheafGens = method(Options => {GeneralElements => false})
idealSheafGens(ZZ, Ideal, Ideal) := List => opts -> (n, J, irr) -> (
R := ring(J);
k := coefficientRing(R);
Jsat := ourSaturation(J,irr);
if opts.GeneralElements == true then (
degs := degrees(J);
-- place of all unique degrees
allmatches := unique(apply(degs, i -> positions(degs, j -> j == i)));
-- creates an ideal where if degrees of generators match
-- those generators are replaced by one generator that
-- is a random combination of all generators of that degree
J = ideal(apply(allmatches, i -> sum(apply(i, j -> random(k) * J_j))));
);
lists := subsets(numgens(J), n);
output := {};
apply(lists, l -> (
I := ideal(J_*_l);
if ourSaturation(I, irr) == Jsat then (
output = append(output, I);
);
)
);
output
)
idealSheafGens(ZZ, Ideal, NormalToricVariety) := List => opts -> (n, J, X) -> (
idealSheafGens(n, J, ideal X)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (d,e,F)=(degree,degree,base ring)
----- Output: The ideal of a random rational curve in P1xP2 of
----- degree (d,e) defined over F.
----- Description: This randomly generates 2 forms of degree
----- d and 3 forms of degree e in the ring S (locally defined),
----- and computes the ideal defining the image of the map of the
----- associated map P^1---->P^1xP^2.
--------------------------------------------------------------------
--------------------------------------------------------------------
randomRationalCurve = method()
randomRationalCurve(ZZ, ZZ, Ring) := Ideal => (d, e, F) -> (
-- Defines P1
s := getSymbol "s";
t := getSymbol "t";
R := F(monoid[s,t]);
--- Defines P1xP2
x := getSymbol "x";
y := getSymbol "y";
S1 := F(monoid[x_0, x_1]);
S2 := F(monoid[y_0,y_1,y_2]);
S := tensor(S1,S2);
--- Defines P1x(P1xP2)
U := tensor(R,S);
uVars := flatten entries vars U;
--- Defines graph of morphisms in P1x(P1xP2)
--M1 := matrix {apply(2,i->random({d,0,0},U)),{x_0,x_1}};
M1 := matrix {apply(2,i->random({d,0,0},U)),{uVars#2,uVars#3}};
--M2 := matrix {apply(3,i->random({e,0,0},U)),{y_0,y_1,y_2}};
M2 := matrix {apply(3,i->random({e,0,0},U)),{uVars#4,uVars#5,uVars#6}};
J := minors(2,M1)+minors(2,M2);
--- Computes saturation and then eliminates producing curve in P1xP2
J' := ourSaturation(J,ideal(uVars#0,uVars#1));
--J' := saturate(J,ideal(uVars#0,uVars#1),MinimalGenerators=>false);
I := sub(eliminate({uVars#0,uVars#1},J'),S);
(T, E) := productOfProjectiveSpaces({1, 2},CoefficientField=>F);
G := map(T,S,(flatten entries vars T));
G(I)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (d,e)=(degree,degree)
----- Output: The ideal of a random rational curve in P1xP2 of
----- degree (d,e) defined over ZZ/101
--------------------------------------------------------------------
--------------------------------------------------------------------
randomRationalCurve (ZZ,ZZ) := Ideal => (d,e) -> (
randomRationalCurve(d,e,ZZ/101)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (d,e,F)=(degree,degree,base ring)
----- Output: The ideal of a random rational curve in P1xP2 of degree (d,e).
----- Description: This randomly generates 2 monomials of degree
----- d and 3 monomials of degree e in the ring S (locally defined),
----- and computes the ideal defining the image of the map of the
----- associated map P^1---->P^1xP^2.
--------------------------------------------------------------------
--------------------------------------------------------------------
randomMonomialCurve = method()
randomMonomialCurve (ZZ,ZZ,Ring) := Ideal => (d,e,F) -> (
--- Defines P1
s := getSymbol "s";
t := getSymbol "t";
R := F[s,t];
--- Defines P1xP2
x := getSymbol "x";
y := getSymbol "y";
S1 := F(monoid[x_0, x_1]);
S2 := F(monoid[y_0,y_1,y_2]);
S := tensor(S1,S2);
--- Defines P1x(P1xP2)
U := tensor(R,S);
uVars := flatten entries vars U;
--- Choose random monomial to define map to P2.
B := drop(drop(flatten entries basis({e,0,0},U),1),-1);
f := (random(B))#0;
--- Defines graph of morphisms in P1x(P1xP2)
M1 := matrix {{(uVars#0)^d,(uVars#1)^d},{uVars#2,uVars#3}};
M2 := matrix {{(uVars#0)^e,(uVars#1)^e,f},{uVars#4,uVars#5,uVars#6}};
J := minors(2,M1)+minors(2,M2);
--- Computes saturation and then eliminates producing curve in P1xP2
J' := ourSaturation(J,ideal(uVars#0,uVars#1));
I := sub(eliminate({uVars#0,uVars#1},J'),S);
(T, E) := productOfProjectiveSpaces({1, 2},CoefficientField=>F);
G := map(T,S,(flatten entries vars T));
G(I)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (d,e)=(degree,degree)
----- Output: The ideal of a random rational curve in P1xP2 of
----- of degree (d,e) defined over ZZ/101.
--------------------------------------------------------------------
--------------------------------------------------------------------
randomMonomialCurve (ZZ,ZZ) := Ideal => (d,e) -> (
randomMonomialCurve(d,e,ZZ/101)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (J)=(ideal of curve in P3)
----- Output: The ideal of a corresponding curve in P1xP2.
----- Description: Given a curve defined by the ideal J in P3,
----- this outputs the ideal I of the curve in P1xP2 given by
----- considering the projection P3---->P1 on the first two variables,
----- and the projection P3----->P2 on the last three variables.
--------------------------------------------------------------------
--------------------------------------------------------------------
curveFromP3toP1P2 = method(Options => {PreserveDegree => true})
curveFromP3toP1P2 (Ideal) := Ideal => opts -> (J) -> (
--- Defines P3
w := getSymbol "w";
R := (coefficientRing ring J) monoid([w_0,w_1,w_2,w_3]);
rVars := flatten entries vars R;
J = sub(J,matrix{{R_0,R_1,R_2,R_3}});
--- Base locus of projection
BL1 := ideal(rVars#0,rVars#1);
BL2 := ideal(rVars#1,rVars#2,rVars#3);
BL := intersect(BL1,BL2);
--- If PreserveDegree => true checks whether curve intersects base locus;
--- this ensures the curve has the correct degree and genus.
if opts.PreserveDegree == true then (
if (ourSaturation(J+BL1,ideal(rVars))==ideal(rVars) or ourSaturation(J+BL2,ideal(rVars))==ideal(rVars)) then error "Given curve intersects places of projection.";
);
--- Defines P1xP2
x := getSymbol "x";
y := getSymbol "y";
S1 := (coefficientRing ring J) monoid([x_0, x_1]);
S2 := (coefficientRing ring J) monoid([y_0,y_1,y_2]);
S := tensor(S1,S2);
--- Defines P3x(P1xP2)
U := tensor(R,S);
uVars := flatten entries vars U;
--- Place curve in P3x(P1xP2)
C' := sub(J,U);
--- Defines graph of projection
M1 := matrix {{uVars#0,uVars#1},{uVars#4,uVars#5}};
M2 := matrix {{uVars#1,uVars#2,uVars#3},{uVars#6,uVars#7,uVars#8}};
D := minors(2,M1)+minors(2,M2);
--- Intersects irrelevant ideal with base locus
B1 := ideal(apply(4,i->uVars#i));
B2 := ideal(apply(2,i->uVars#(4+i)));
B3 := ideal(apply(3,i->uVars#(6+i)));
B := intersect(B1,B2,B3,sub(BL,U));
--- Computes saturation and then eliminates producing curve in P1xP2
K := ourSaturation(C'+D,B);
I := sub(eliminate({uVars#0,uVars#1,uVars#2,uVars#3},K),S);
(T, E) := productOfProjectiveSpaces({1, 2},CoefficientField=>(coefficientRing ring J));
G := map(T,S,(flatten entries vars T));
G(I)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (d,e,F)=(degree,genus,base ring)
----- Output: The ideal of a random curve in P1xP2 defined over F.
----- Description: This randomly generates a curve of degree d
----- and genus g in P3, and then computes the ideal of the corresponding
----- curve in P1xP2 given by considering the projection
----- P3---->P1 on the first two variables.
----- and the projection P3----->P2 on the last three variables.
--------------------------------------------------------------------
--------------------------------------------------------------------
randomCurveP1P2 = method(Options => {Attempt => 1000})
randomCurveP1P2 (ZZ,ZZ,Ring) := Ideal => opts -> (d,g,F) -> (
--- Defines P3
z := getSymbol "z";
R := F(monoid[z_0,z_1,z_2,z_3]);
rVars := flatten entries vars R;
--- Base locus of projection
BL1 := ideal(rVars#0,rVars#1);
BL2 := ideal(rVars#1,rVars#2,rVars#3);
BL := intersect(BL1,BL2);
--- Randomly generates curve in P3 until finds one not intersecting
--- base locus of projection or until Bound is reached.
C := ideal(0);
apply(opts.Attempt,i->(
C = curve(d,g,R);
if class(C) === Curve then C = ideal(C);
if (ourSaturation(C+BL1,ideal(rVars))!=ideal(rVars) and ourSaturation(C+BL2,ideal(rVars))!=ideal(rVars)) then break C;
)
);
--- Checks whether curve in P3 intersects base locus of projection;
--- this ensures the curve has the correct degree and genus.
if (ourSaturation(C+BL1,ideal(rVars))==ideal(rVars) or ourSaturation(C+BL2,ideal(rVars))==ideal(rVars)) then error "Unable to find curve not intersecting places of projection.";
--- Defines P1xP2
curveFromP3toP1P2(C)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (d,e)=(degree,genus)
----- Output: The ideal of a random curve in P1xP2 over ZZ/101
--------------------------------------------------------------------
--------------------------------------------------------------------
randomCurveP1P2 (ZZ,ZZ) := Ideal => opts -> (d,g) -> (
randomCurveP1P2(d,g,ZZ/101)
)
--------------------------------------------------------------------
--------------------------------------------------------------------
-- Multigraded Regularity
--------------------------------------------------------------------
--------------------------------------------------------------------
-- helpers for connecting NormalToricVarieties and TateOnProducts
load "./VirtualResolutions/helpers.m2"
multigradedRegularity = method(
TypicalValue => List,
Options => {
Strategy => null,
LowerLimit => null,
UpperLimit => null
}
)
-- keys: none
MultigradedRegularityOptions = new SelfInitializingType of BasicList
MultigradedRegularityOptions.synonym = "multigraded regularity options"
-- keys: LowerLimit, UpperLimit, "HilbertPolynomial", "CohomologyTable"
MultigradedRegularityComputation = new Type of MutableHashTable
MultigradedRegularityComputation.synonym = "multigraded regularity computation"
-- if there is a compatible computation stored in M.cache,
-- returns the computation object, otherwise creates the entry:
-- MultigradedRegularityOptions{} => MultigradedRegularityComputation{ LowerLimit, UpperLimit, Result }
new MultigradedRegularityComputation from Ideal :=
new MultigradedRegularityComputation from Module := (C, M) -> (
if instance(M, Ideal) then M = comodule M;
r := degreeLength ring M;
-- TODO: are there any options that could go in MultigradedRegularityOptions?
cacheKey := MultigradedRegularityOptions{};
try M.cache#cacheKey else M.cache#cacheKey = new MultigradedRegularityComputation from {
LowerLimit => toList(r : infinity), -- lower bound of the region checked
UpperLimit => toList(r : -infinity), -- upper bound of the region checked
Result => null })
isComputationDone = method(TypicalValue => Boolean, Options => true)
isComputationDone MultigradedRegularityComputation := Boolean => options multigradedRegularity >> opts -> container -> (
-- this function determines whether we can use the cached result, or further computation is necessary
instance(container.Result, List)
and container.LowerLimit <= min \ transpose{container.LowerLimit, opts.LowerLimit}
and container.UpperLimit >= max \ transpose{container.UpperLimit, opts.UpperLimit})
cacheHit := type -> if debugLevel > 0 then printerr("Cache hit on a ", synonym type, "! 🎉");
cacheComputation = method(TypicalValue => CacheFunction, Options => true)
cacheComputation MultigradedRegularityComputation := CacheFunction => options multigradedRegularity >> opts -> container -> new CacheFunction from (
-- this function takes advantage of FunctionClosures by modifying the container
computation -> (
if isComputationDone(opts, container) then ( cacheHit class container; container.Result ) else
if (result := computation(opts, container)) =!= null then ( container.Result = result )))
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (S,M) = (Ring, Module)
-- OR
----- Input: (X,M) = (NormalToricVariety,Module)
----- Output: A list consisting of the minimal elements of the
----- multigraded regularity of M.
----- Description: This computes the multigraded regularity of a
----- module as defined in Definition 1.1 of [Maclagan, Smith 2004].
----- It returns a list of the minimal elements.
----- Caveat: This assumes M is B-saturated already i.e. H^0_B(M)=0
--------------------------------------------------------------------
--------------------------------------------------------------------
-- TODO: instead of Ring, take the irrelevant ideal
multigradedRegularity(Ring, Ideal) := o -> (S, I) -> multigradedRegularityHelper( , S, I, o)
multigradedRegularity(NormalToricVariety, Ideal) := o -> (X, I) -> multigradedRegularityHelper(X, , I, o)
multigradedRegularity(Ring, Module) := o -> (S, M) -> multigradedRegularityHelper( , S, M, o)
multigradedRegularity(NormalToricVariety, Module) := o -> (X, M) -> multigradedRegularityHelper(X, , M, o)
multigradedRegularityHelper = (X, S, M, opts) -> (
strategy := opts.Strategy;
-- start from module over Cox ring of a NormalToricVariety and add Tate data
if instance(X, NormalToricVariety) then X = normalToricVarietyWithTateData X
-- start from module over productOfProjectiveSpaces and get module over Cox ring of a product of toricProjectiveSpaces
else if S.?TateData then X = normalToricVarietyFromTateData S
-- start from module over multigraded polynomial ring and get module over Cox ring of a product of toricProjectiveSpaces
else X = normalToricVarietyFromTateData imbueRingWithTateData S;
r := regularity M;
n := degreeLength ring M;
-- the multigraded regularity of the zero module is -infinity in every component
-- TODO: use Hilbert polynomial to detect irrelevant modules quickly
if M == 0 then return {toList(n : -infinity)};
opts = opts ++ {
-- from Proposition 3.7 of [BCHS22] we know reg M \subset mindegs + Eff X
LowerLimit => if opts.LowerLimit =!= null then opts.LowerLimit else compMin degrees M,
-- Note: an upper limit that works for all examples isn't known
UpperLimit => if opts.UpperLimit =!= null then opts.UpperLimit else compMax join(degrees M, {toList(n : r)})};
-- store a cached computation object in M
-- MultigradedRegularityOptions{} => MultigradedRegularityComputation{ LowerLimit, UpperLimit, Result }
container := new MultigradedRegularityComputation from M;
-- the strategies are stored as hooks under this key
key := (multigradedRegularity, NormalToricVariety, Module);
-- this function attempts the strategies in reverse order, or only the specified strategy
computation := (opts, container) -> runHooks(key, (X, M, opts ++ {cache => container}), Strategy => strategy);
-- the actual computation of the strategies occurs here
C := (cacheComputation(opts, container)) computation;
if C =!= null then C else if strategy === null
then error("no applicable strategy for ", toString key)
else error("assumptions for computing multigraded regularity with strategy ", toString strategy, " are not met"))
-- This is the old strategy for products of projective spaces.
-- It is based on a direct sheaf cohomology calculation.
-- See [ABLS20]: https://msp.org/jsag/2020/10-1/p06.xhtml
multigradedRegularityCohomologySearchStrategy = (X, M, opts) -> (
S := ring X;
-- TODO: also check that X and S are indeed a product of
-- projective spaces and its Cox ring, otherwise return null
if instance(M, Ideal) then M = comodule M;
if ring M =!= S then M = map(S, ring M, gens S) ** M;
debugInfo := if debugLevel < 1 then identity else printerr;
-- For products of projective space, the dimension is the
-- number of variables minus the rank of the Picard group
d := dim X;
B := ideal X;
r := regularity M;
n := degreeLength S; -- rank of the Picard group
degs := degrees M;
-- element-wise minimum of the multi-degrees of generators of M
mindegs := apply(n, i -> min(degs / (deg -> deg_i)));
debugInfo demark_", " {
"Pic X = ZZ^" | toString n,
"dim X = " | toString d,
"reg M = " | toString r,
"mindegs = " | toString mindegs};
H := hilbertPolynomial(X, M);
debugInfo \ {
"HP M = " | toString H,
"degs = " | toString degs};
(low, high) := (opts.LowerLimit, opts.UpperLimit);
debugInfo("Computing cohomologyHashTable from ", toString low, " to ", toString high);
L := pairs cohomologyHashTable(M, low, high);
--
gt := new MutableHashTable;
debugInfo("Beginning search in Picard group");
-- TODO: rewrite this loop
HP := x -> (map(QQ, ring H, x))(H);
apply(L, ell -> (
-- Check that Hilbert function and Hilbert polynomial match
-- (this imposes a condition on the alternating sum of local cohomology dimensions)
if hilbertFunction(ell_0_0, M) != HP(ell_0_0) then gt#(ell_0_0) = true;
-- Check that higher local cohomology vanishes (i.e., H^i_B(M) = 0 for i > 1)
if ell_1 != 0 and ell_0_1 > 0 then scan(diagonalMultidegrees(ell_0_1, n), j -> gt#(ell_0_0 + j) = true);
));
-- retrieve the container
container := opts.cache;
container.LowerLimit = low;
container.UpperLimit = high;
debugInfo("Calculating minimal generators");
if debugLevel > 0 and n == 2 then plotRegion((i, j) -> not gt#?{i, j}, low, high);
-- Testing whether a degree is in gt is only conclusive (n:d) above the minimum degree given
-- to cohomologyHashTable, and findRegion assumes that the region is closed under translation.
container.Result = findRegion({low + toList(n:d), high}, M, (ell, M) -> not gt#?ell))
-- The default strategy applies to both modules and ideals in a product of projective spaces,
-- but by using hooks we allow better strategies to be added later
addHook((multigradedRegularity, NormalToricVariety, Module), Strategy => "CohomologySearch", multigradedRegularityCohomologySearchStrategy)
-- Faster strategy using LinearTruncations
load "./VirtualResolutions/development.m2"
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Input: (C)=(ChainComplex)
----- Output: A resolution of the tail end of the complex appended
----- to the given complex.
----- Description: This function is not currently being exported,
----- but we hope it will eventually be useful in generating new
----- virtual resolutions. The key is we need a way, like for example
----- module primary decomposition to add irrlevence to a chain
----- complex before we apply resolveTail. (See comment.)
--------------------------------------------------------------------
--------------------------------------------------------------------
--TODO: Finish test
-- Add length limit
resolveTail = method()
resolveTail(ChainComplex) := ChainComplex => C -> (
N := max support C;
M := coker syz C.dd_N;
-- TODO: add some component of the irrelevant ideal to M here.
T := res M;
L1 := for i from min C to max support C - 1 list matrix C.dd_(i+1);
L2 := for i from min T to max support T - 1 list matrix T.dd_(i+1);
chainComplex(L1 | L2)
);
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Beginning of the tests and the documentation
--------------------------------------------------------------------
--------------------------------------------------------------------
load "./VirtualResolutions/tests.m2"
beginDocumentation()
load "./VirtualResolutions/doc.m2"
end--
--------------------------------------------------------------------
--------------------------------------------------------------------
----- Beginning of the development section
--------------------------------------------------------------------
--------------------------------------------------------------------
restart
uninstallPackage "VirtualResolutions"
restart
installPackage("VirtualResolutions", FileName => "VirtualResolutions.m2")
restart
needsPackage("VirtualResolutions", FileName => "VirtualResolutions.m2")
elapsedTime check "VirtualResolutions"
viewHelp "VirtualResolutions"