-
Notifications
You must be signed in to change notification settings - Fork 2
/
blow.lib
executable file
·4205 lines (3530 loc) · 126 KB
/
blow.lib
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
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
version="1.0";
category="Miscellaneous";
info="
LIBRARY: blow.lib Pushforwards of matrix factorisations
AUTHOR: Nils Carqueville, Daniel Murfet
KEYWORDS: matrix factorisation
PROCEDURES:
";
// NOTE: We include a version of matrix.lib which suppresses some
// unnecessary output from the procedure "rowred"
LIB "linalg.lib";
LIB "matrix.lib";
LIB "ring.lib";
LIB "qmatrix.lib";
LIB "control.lib";
////////////////////////////////////////////////////////////////////
// USAGE GUIDE
//
// We expect our ambient ring to be of one of the types
//
// 0,(x(1..t),y(1..s)),dp OR (0,r),(x(1..t),y(1..s)),dp
//
// for some integers t and s. The x-variables are the "internal" variables.
// We always expect "r" to be the param defining an extension ring.
//
// In the second case where we define a ring extension, in addition to defining
// the minpoly we expect that before using this library an additional variable
// "minblowpoly" is defined, which is the minimum polynomial of r over Q expressed
// in terms of the variable x(1). For example
//
// ring rr=(0,r),(x(1..t),y(1..s)),dp;
// minpoly = r^2 + 1;
// poly minpolyblow = x(1)^2 + 1;
//
// If minpolyblow or r is undefined we proceed by ignoring the ring extension.
//
// We assume currently in dQ, deltaQ and related routines that the polynomial
// we are passed is a sum of all the x-variables to some specific power.
//
// NOTE: With Singular 4 the way minimum polynomials are handled has been changed,
// see http://www.singular.uni-kl.de/Manual/4-0-1/sing_2235.htm#SEC2313.
////////////////////////////////////////////////////////////////////
// GRADED MATRIX FACTORISATIONS
//
// IMPORTANT: Following KR we make use of the grading on our polynomial rings where each
// variable has degree 2. This is NOT imposed on the level of Singular code, it just affects
// our convention for grading vectors (which terminology will be explained presently). Given
// a polynomial p we write deg(p) for the usual degree, as understood by Singular, and |p| for
// the doubled grading, so |p| = 2 * deg(p). Given a graded module M, M{1} denotes the module
// with grading M{1}_i = M_{i-1}.
//
// The doubled grading is adopted for the following reason: let R be a polynomial ring
// with this grading, and W an element of R with deg(W) = n+1. If W = fg for homogeneous f,g
// then we can write W: R -> R as a composite of two maps g: R -> R{n+1-|g|} and
// f: R{n+1-|g|} -> R of graded R-modules of degree n+1.
//
// A matrix factorisation is represented by an odd supermatrix A giving the differential
// on some Z/2-graded free module X (over a polynomial ring). A _graded_ matrix factorisation
// is this differential together with an intvec g, whose length is equal to the number of
// columns in A, giving the "grading shift" on each free module in X. We require that the
// components a0 and a1 of A are then morphisms of graded modules of degree n+1 where the
// potential is of degree 2(n+1).
//
// For example, if X = X0 + X1 is a free module of rank 4, then g = (3 3 2 1) would express
// that as a graded module X0 = R{3} + R{3} and X1 = R{2} + R{1} where R is the polynomial
// ring with the doubled grading. Suppose that the potential W has |W| = 4, so n = 1. Then
// the differential A = (0, a1 newline a0, 0) would have to consist of a morphism
// a0: R{3}+R{3} -> R{2}+R{1} of degree n+1 = 2, so
// |a0[1,1]| = 3, (i.e. this entry would have to be zero, because there are no odd degrees)
// |a0[1,2]| = 3,
// |a0[2,1]| = 4 (i.e. a polynomial f with deg(f) = 2)
// |a0[2,2]| = 4
//
// NOTE: All operations on graded MFs assume that A is square (i.e. both degrees have
// the same rank).
//
// NOTE: Bigradings
//
// In the case of bigradings (for HOMFLY homology) the first ring variable (call it "a")
// has bidegree (2,0) and the rest have bidegree (0,2). The grading shift on a free module of
// rank M is described by a list of size M (even if M = 1) whose entries are intvecs of size
// 2. So R{a,b} + R{c,d} is described by list(invec(a,b),intvec(c,d)).
//////////////////////////////////////////////////
// blowFLags
//
// Functions as a list of #define's.
// Change the return value, say of sanity_checks, to turn off sanity checks in all routines.
//
// NOTE: Singular's evaluation of a && b does not use shortcuts, it evaluates both a and
// b before doing the logical AND, so if one uses flags to avoid computation, one has
// to nest ifs.
proc blowFlags(string s)
{
// Throughout the code, there are various checks on the integrity of data
// (that certain things are morphisms, that MFs factorise the potential they
// should, and so on). These can slow down the code dramatically, but help
// locate bugs. Turn off for large computations.
if( s == "sanity_checks" )
{
if( defined(blow_flag_sanity_checks) )
{
return(1);
}
else
{
return(0); // default is 0
}
}
// Turn on this flag if you want to optimise for small coefficients (of monomials)
// rather than speed, in for example mfReduce.
if( s == "small_coeffs" )
{
return(0); // default is 0
}
// DEBUG: As of Singular 4, the routine findConstantMin has a bug which
// causes the interpreter to crash with a Segmentation fault. So until this
// is fixed, DO NOT USE small_coeffs
// Enables some checks only relevant if the calculations involved
// are for link homology (e.g. maps in webCompileMorphism should
// be degree +1)
if( s == "link_homology_checks" )
{
return(0); // default is 0
}
if( s == "minbase_cutoff" )
{
return(5); // default is 5
}
// We make use of two storage options: ASCII and MPFILE. The flag use_mpfile
// controls which one is used (some operating systems only support ASCII).
// The default is to use ASCII since it is more compatible, but MPFILE is
// much faster.
if( s == "use_mpfile" )
{
if( defined(blow_flag_use_mpfile) )
{
return(1);
}
else
{
return(0); // default is 0
}
}
// Cutoff for how high to look for a power of ring variables belonging
// to the Jacobi ideal
if( s == "power_cutoff_jacobi" )
{
return(1000); // default is 1000
}
if( s == "factor_out_content" )
{
return(0); // default is 0
}
// We did not recognise this flag
print("[blowFlags] Flag not recognised, returning zero.");
return(0);
}
//////////////////////////////////////////////////////////////////////////////////
// numXVars - Returns the number of x variables (i.e. "nx")
//
// We assume that the ring is structured as described at the beginning of this document,
// so that the variables are x(1),..,x(t),y(1),...,y(s) for some integers t and s. This
// routine returns the integer t (possibly zero).
//////////////////////////////////////////////////////////////////////////////////
proc numXVars()
{
list varNames = ringlist(basering)[2];
int num = 0;
int i;
for(i=1;i<=size(varNames);i++)
{
if( varNames[i][1] == "x" )
{
num++;
}
}
return(num);
}
//////////////////////////////////////////////////////////////////////////////////
// numYVars - Returns the number of y variables (i.e. "ny")
//
// We assume that the ring is structured as described at the beginning of this document,
// so that the variables are x(1),..,x(t),y(1),...,y(s) for some integers t and s. This
// routine returns the integer s (possibly zero).
//////////////////////////////////////////////////////////////////////////////////
proc numYVars()
{
list varNames = ringlist(basering)[2];
int num = 0;
int i;
for(i=1;i<=size(varNames);i++)
{
if( varNames[i][1] == "y" )
{
num++;
}
}
return(num);
}
//////////////////////////////////////////////////////////////////////////////////
// "ringwithoutyvars" returns the ambient ring with y-variables removed
// NOTE: We just return the ring, we do not change the current basering
// NOTE: This assumes our only ring variables are xs and ys
// NOTE: This does get called by linkhom.lib with numY = 0, i.e. nothing to do.
//////////////////////////////////////////////////////////////////////////////////
proc ringWithoutYVars()
{
def RRR = basering;
int numX = numXVars();
int numY = numYVars();
if( numX == 0 )
{
print("[ringWithoutYVars] Cannot create a ring with no variables, failing.");
return();
}
// Define new ring -- exactly the same as RRR, but without the y-variables:
// ringlist(RRR)[1] will be the characteristic followed by (possibly) the names of params.
if(size(ringlist(RRR)[1]) > 1)
{
int i,j,k;
list L = ringlist(RRR);
list newVars;
for(i=1;i<=numX;i++)
{
string nv = "x(" + string(i) + ")";
newVars = newVars + list(nv);
kill nv;
}
L[2] = newVars;
kill newVars;
intvec kk = (1..numX);
for(i=1; i<=numX; i++)
{
kk[i] = 1;
}
L[3][1][2] = kk;
L[1][4][1] = 0; // set minpoly to zero, put it back to the right value below...
def nR = ring(L);
// Now complete the correct definition of nR by specifying the right minpoly:
if( defined(minpolyblow) && defined(r) )
{
setring nR;
poly minpolyblow = fetch(RRR,minpolyblow); // Use fetch so the minpoly stays using var(1)
poly z = subst(minpolyblow,var(1),r);
number nu = leadcoef(z);
minpoly = nu;
poly minpolyblow = fetch(RRR,minpolyblow);
export(minpolyblow);
// NOTE: The double definition of minpolyblow is because Singular nukes
// all variables in our ring when we set minpoly
}
else
{
print("[ringWithoutYVars] Ring param other than r, or unspecified minpolyblow. Please see the Usage Guide.");
}
}
else
{
ring nR = char(RRR), x(1..numX), dp;
}
def newRing = basering;
// Before returning the new ring, set the ambient ring as current:
setring RRR;
return(newRing);
}
//////////////////////////////////////////////////////////////////////////////////
// "ringWithoutXVars" returns the ambient ring with x-variables removed
// NOTE: We just return the ring, we do not change the current basering
//////////////////////////////////////////////////////////////////////////////////
proc ringWithoutXVars()
{
def RRR = basering;
int numX = numXVars();
int numY = numYVars();
if( numY == 0 )
{
print("[ringWithoutXVars] Cannot create a ring with no variables, failing.");
return();
}
// Define new ring -- exactly the same as RRR, but without the x-variables:
// ringlist(RRR)[1] will be the characteristic followed by (possibly) the names of params.
if(size(ringlist(RRR)[1]) > 1)
{
int i,j,k;
list L = ringlist(RRR);
list newVars;
for(i=1;i<=numY;i++)
{
string nv = "y(" + string(i) + ")";
newVars = newVars + list(nv);
kill nv;
}
L[2] = newVars;
kill newVars;
intvec kk = (1..numY);
for(i=1; i<=numY; i++)
{
kk[i] = 1;
}
L[3][1][2] = kk;
L[1][4][1] = 0; // set minpoly to zero, put it back to the right value below...
def nR = ring(L);
// Now complete the correct definition of nR by specifying the right minpoly:
if( defined(minpolyblow) && defined(r) )
{
setring nR;
poly minpolyblow = fetch(RRR,minpolyblow);
poly z = subst(minpolyblow,var(1),r);
number nu = leadcoef(z);
minpoly = nu;
poly minpolyblow = fetch(RRR,minpolyblow);
export(minpolyblow);
// NOTE: The double definition of minpolyblow is because Singular nukes
// all variables in our ring when we set minpoly
}
else
{
print("[ringWithoutXVars] Ring param other than r, or unspecified minpolyblow. Please see the Usage Guide.");
}
}
else
{
ring nR = char(RRR), y(1..numY), dp;
}
def newRing = basering;
// Before returning the new ring, set the ambient ring as current:
setring RRR;
return(newRing);
}
//////////////////////////////////////////////////////////////////////////////////
// "dimAlgebraOverInternalVariables" Returns the dimension of the quotient of the
// polynomial ring in the internal variables (as returned by ringWithoutYVars) by the
// specified ideal (given as an ideal in the basering).
//////////////////////////////////////////////////////////////////////////////////
proc dimAlgebraOverInternalVariables(ideal J)
{
def RRR = basering;
def nR = ringWithoutYVars();
setring nR;
ideal J = imap(RRR,J);
ideal Jstd = std(J);
ideal ba = kbase(Jstd);
int n = size(ba);
setring RRR;
return(n);
}
//////////////////////////////////////////////////////////////////////////////////
// "deltaInflationList" Returns a list containing, in order, the matrix representing
// the operator [g_i,x(i)^b] for b = 1,...,2*exponent - 1.
//////////////////////////////////////////////////////////////////////////////////
proc deltaInflationList(int i, int exponent, ideal J)
{
int prl = printlevel;
// Compute a k-basis of J:
def RRR = basering;
def nR = ringWithoutYVars();
setring nR;
ideal J = imap(RRR,J);
ideal Jstd = std(J);
ideal basis = kbase(Jstd);
module BB = reduce(basis,Jstd);
int jdim = size(basis);
int b, k;
list deltaActions;
for(b=1; b<= 2*exponent - 1; b++)
{
// Compute the matrix representing the operator [g_i, x(i)^b] on I = nR/J:
list L;
for(k=1; k<=jdim; k++)
{
// First compute g_i( x(i)^b * - ) on our basis element:
poly f1 = ( x(i)^b * basis[k] - reduce(x(i)^b * basis[k],std(x(i)^exponent)) )/(x(i)^exponent);
// Next compute x(i)^b * g_i(-):
poly f2 = x(i)^b * ( basis[k] - reduce(basis[k],std(x(i)^exponent)) )/(x(i)^exponent);
// To our output matrix we add the expression of the commutator f1 - f2 in the
// chosen basis of the algebra I:
module ff = reduce(f1 - f2,Jstd);
matrix MM = matrix(reduce(lift(BB,ff),std(syz(BB))));
L = L + list(MM);
kill f1,f2,ff,MM;
}
matrix U = L[1];
for(k=2; k<=jdim; k++)
{
U=concat(U,L[k]);
}
deltaActions = deltaActions + list(U);
kill U, L;
}
setring RRR;
list deltaActions = imap(nR,deltaActions);
return(deltaActions);
}
//////////////////////////////////////////////////////////////////////////////////
// "variableInflationList" Returns a list containing, in order, the matrix representing
// the action of each of the internal variables on k[x]/J (the internal algebra).
//////////////////////////////////////////////////////////////////////////////////
proc variableInflationList(ideal J)
{
int prl = printlevel;
def RRR = basering;
def nR = ringWithoutYVars();
setring nR;
ideal Jx = std(imap(RRR,J));
ideal basis = kbase(Jx);
int jdim = size(basis);
if( jdim == 0 )
{
print("[variableInflationList] Internal algebra is zero-dimensional, exiting.");
return();
}
module BB = reduce(basis,Jx);
module syzBB = std(syz(BB));
int i, k;
list variableActions;
int numX = nvars(nR);
for(i=1; i<=numX; i++)
{
list L;
for(k=1; k<=jdim; k++)
{
module ff = reduce(x(i)*basis[k],Jx);
matrix MM = matrix(reduce(lift(BB,ff), syzBB));
L = L + list(MM);
}
matrix U = L[1];
for(k=2; k<=jdim; k++)
{
U=concat(U,L[k]);
}
variableActions = variableActions + list(U);
kill U, L;
}
setring RRR;
list variableActions = imap(nR,variableActions);
return(variableActions);
}
//////////////////////////////////////////////////////////////////////////////////
// "poly2matrix" blows up a polynomial into a matrix: x-monomials are replaced by
// the matrices that represent the former's action on the algebra k[x-variables]/J.
//
// NOTE: We assume that the algebra k[x-variables]/J is finite-dimensional.
//
// We must be passed a list "variableActions" which gives, in order, the matrices
// representing the action of multiplication by each internal variable on the
// internal algebra (as given by variableInflationList).
//
//////////////////////////////////////////////////////////////////////////////////
proc poly2matrix(poly tepo, list variableActions)
{
// First compute the x-monomials and their coefficients in tepo:
int i;
poly xprod = 1;
int numX = numXVars();
for(i=1; i<=numX; i++)
{
xprod = xprod * x(i);
}
matrix koffer = coef(tepo, xprod);
int u,k;
int jdim = ncols(variableActions[1]);
matrix inflation[jdim][jdim];
for(u=1;u<=ncols(koffer);u++)
{
// Each column of koffer represents an x-monomial, let us now factorise this.
// The list powers contains, in order, the power of each internal variable
// in monom + 1 (since we multiply by xprod to make sure all vars appear).
poly monom = koffer[1,u];
intvec powers = factorize(monom*xprod,2)[2];
matrix monomAction = unitmat(jdim);
for(k=1;k<=numX;k++)
{
monomAction = monomAction * power(variableActions[k],powers[k]-1);
}
inflation = inflation + koffer[2,u] * monomAction;
kill monom, powers, monomAction;
}
return(inflation);
}
////////////////////////////////////////////////////////////////////
// mfInflate
//
// We are given a matrix A interpreted as the differential on a matrix factorisation X
// of a potential W in our ring, together with a ring variable intvar and a power N.
// We assume that W is a polynomial in the set of variables with intvar removed, and
// we return the differential on the tensor product X otimes Q[intvar]/(intvar^N).
proc mfInflate(matrix A, poly intvar, int N)
{
def RRR = basering;
// Convert everything into a more suitable ring. We go through the original
// list of ring variables, rename everything apart from intvar to y(i)'s (in
// ascending order) and rename intvar to x(1).
list rlist = ringlist(RRR);
list varlist = rlist[2];
// Create the new list of variables, where intvar is renamed to x(1)
// and the other variables are enumerated as y(i)'s.
list newvar;
int i;
int ycount;
for(i=1;i<=size(varlist);i++)
{
if( string(intvar) == varlist[i] )
{
newvar = newvar + list("x(1)");
}
else
{
ycount++;
string s = "y(" + string(ycount) + ")";
newvar = newvar + list(s);
kill s;
}
}
list newringList;
newringList[1] = rlist[1];
newringList[2] = newvar;
newringList[3] = rlist[3];
newringList[4] = rlist[4];
kill rlist;
// Fix the variable weighting:
intvec kk = (1..size(newvar));
for(i=1; i<=size(newvar); i++)
{
kk[i] = 1;
}
newringList[3][1][2] = kk;
kill newvar, kk;
// Create our new ring:
def nR = ring(newringList);
kill newringList;
setring nR;
// Now we can call mablow:
matrix A = fetch(RRR,A);
ideal J = x(1)^N;
matrix Ablow = mablow(A,J);
setring RRR;
matrix final = fetch(nR,Ablow);
return(final);
}
//////////////////////////////////////////////////////////////////////////////////
// "mablow" blows up a matrix by blowing up all its entries using poly2matrix.
// The matrix M may be non-square.
//////////////////////////////////////////////////////////////////////////////////
proc mablow(matrix M, ideal J)
{
int benchmark = 1; // Set to 1 to output benchmarking data
// Compute dimension of the algebra k[x-vars]/J:
int n = dimAlgebraOverInternalVariables(J);
// Roughly speaking mablow takes "difficulty" ms to complete. We only give
// debugging output if this is likely to take > 10 seconds.
int difficulty = (nrows(M) * ncols(M) * n) div 3;
if( difficulty > 10000 )
{
if( benchmark )
{
system("--ticks-per-sec",1000);
int timeElapsed = timer;
}
dbprint(printlevel, "[mablow] Inflating " + string(nrows(M)) + "x" + string(ncols(M)) + " matrix by " + string(n) + "-dim algebra");
}
// Compute the inflation of individual variables:
list variableActions = variableInflationList(J);
// Define L to be an appropriately indexed list of blown-up matrices:
int i1,j1,i2,j2,i;
int ncolsM = ncols(M);
int nrowsM = nrows(M);
list e,L;
for(i=1; i<=nrowsM; i++)
{
L[i] = e;
}
for(i1=1; i1<=nrowsM; i1++) // row
{
for(j1=1; j1<=ncolsM; j1++) // column
{
matrix PM = poly2matrix(M[i1,j1], variableActions);
L[i1][j1] = PM;
kill PM;
}
}
matrix A[nrowsM*n][ncolsM*n];
for(i1=1; i1<=nrowsM; i1++)
{
for(j1=1; j1<=n; j1++)
{
for(i2=1; i2<=ncolsM; i2++)
{
for(j2=1; j2<=n; j2++)
{
A[(i1-1)*n + j1, (i2-1)*n + j2] = L[i1][i2][j1,j2];
}
}
}
}
if( benchmark && difficulty > 10000 )
{
timeElapsed = timer - timeElapsed;
dbprint(printlevel, "[mablow] elapsed time " + string(timeElapsed) + "ms.");
}
return(A);
}
//////////////////////////////////////////////////////////////////////////////////
// "mablowGrading" returns the grading vector for an inflated MF, given the grading
// vector of the original MF and the ideal to inflate with. We use the basis for
// R/J given by reduce(kbase(std(J)),std(J)).
//
// The underlying graded free module of the MF is R{g[1]} + R{g[2]} + ... and
// the underlying graded free module of the inflation is a direct sum of modules
// of the form R{g[i]} x R/J which has the usual grading. Obviously this only makes
// sense if J is a graded ideal.
//////////////////////////////////////////////////////////////////////////////////
proc mablowGrading(intvec g, ideal J, int N)
{
def RRR = basering;
def nR = ringWithoutYVars();
setring nR;
ideal J = imap(RRR,J);
ideal Jstd = std(J);
ideal basis = kbase(Jstd);
int jdim = size(basis);
module BB = reduce(basis,Jstd);
intvec r;
// There is an overall grading shift given by the sum of the degrees of
// the generators of J, plus an additional N + 1 for each generator.
int k;
int E;
for(k=1;k <= size(J);k++)
{
E = E - 2 * deg(J[k]) + N + 1;
}
int i,j;
for(i=1;i <= size(g); i++)
{
for(j=1;j<=jdim;j++)
{
r[(i-1)*jdim + j] = g[i] + 2 * deg(BB[j]) + E;
}
}
setring RRR;
return(r);
}
//////////////////////////////////////////////////////////////////////////////////
// "poly2matrix_delta"
//
// Let us write nR for the basering without its y-variables.
//
// Given a polynomial in the x- and y-variables and an integer i, we return a matrix
// in only the y-variables, where the x-monomials are "inflated" by their action on
// the algebra I = nR/J.
//////////////////////////////////////////////////////////////////////////////////
proc poly2matrix_delta(poly tepo, int i, int exponent, list variableActions, list deltaActions)
{
// First compute the x-monomials and their coefficients in tepo:
int t;
poly xprod = 1;
int numX = numXVars();
for(t=1; t<=numX; t++)
{
xprod = xprod * x(t);
}
matrix koffer = coef(tepo, xprod);
int u,k;
int jdim = ncols(variableActions[1]);
matrix inflation[jdim][jdim];
for(u=1;u<=ncols(koffer);u++)
{
// Each column of koffer represents an x-monomial, let us now factorise this.
// The list powers contains, in order, the power of each internal variable
// in monom + 1 (since we multiply by xprod to make sure all vars appear).
poly monom = koffer[1,u];
intvec powers = factorize(monom*xprod,2)[2];
matrix monomAction = unitmat(jdim);
for(k=1;k<=numX;k++)
{
// If k is not equal to i, then we just take the usual inflation,
// but for k = i we do the "delta" inflation:
if( k != i )
{
monomAction = monomAction * power(variableActions[k],powers[k]-1);
}
else
{
// We have to multiply by a factor corresponding to x(i)^(powers[k]-1),
// which is the action on the internal algebra of the operator
// [g_i,x(i)^(powers[k]-1)], as recorded in deltaActions. If the exponent
// is between 1 and 2 * exponent - 1 we use the array. Otherwise the
// operator is zero, so multiply by zero.
if( powers[k] - 1 >= 1 && powers[k] - 1 <= 2*exponent - 1)
{
monomAction = monomAction * deltaActions[powers[k]-1];
}
else
{
monomAction = 0 * monomAction;
}
}
}
inflation = inflation + koffer[2,u] * monomAction;
kill monom, powers, monomAction;
}
return(inflation);
}
/////////////////////////////////////////////////////////////////////////////////////////
// "mablow_delta" blows up a matrix by blowing up all its entries using poly2matrix_delta.
//
// exponent is the integer such that g_i is division without remainder by x(i)^exponent.
/////////////////////////////////////////////////////////////////////////////////////////
proc mablow_delta(matrix M, int i, int exponent, ideal J)
{
// Compute dimension of the algebra k[x-vars]/J:
int n = dimAlgebraOverInternalVariables(J);
// Compute the ordinary inflation of individual variables:
list variableActions = variableInflationList(J);
// Compute the delta inflation [g_i,x(i)^b] for all integers b:
list deltaActions = deltaInflationList(i,exponent,J);
// Define L to be an appropriately indexed list of blown-up matrices:
int i1,j1,i2,j2,t;
int s = ncols(M);
list e,L;
for(t=1; t<=s; t++)
{
L[t] = e;
}
for(i1=1; i1<=s; i1++)
{
for(j1=1; j1<=s; j1++)
{
L[i1] = insert(L[i1], poly2matrix_delta(M[i1,j1], i, exponent, variableActions, deltaActions),j1-1);
}
}
matrix A[s*n][s*n];
for(i1=1; i1<=s; i1++)
{
for(j1=1; j1<=n; j1++)
{
for(i2=1; i2<=s; i2++)
{
for(j2=1; j2<=n; j2++)
{
A[(i1-1)*n + j1, (i2-1)*n + j2] = L[i1][i2][j1,j2];
}
}
}
}
return(A);
}
/////////////////////////////////////////////////////////////////////////////////////
// "SGroupintvecs" produces the n! permutations of (1,...,n) as a list of intvecs.
/////////////////////////////////////////////////////////////////////////////////////
proc SGroupintvecs(int n)
{
list L;
int i;
intmat M = SymGroup(n);
for(i=1; i<=nrows(M); i++)
{
intvec c = M[i,1..n];
L[i] = c;
}
return(L);
}
/////////////////////////////////////////////////////////////////////////////////////
// "deltaQ" is delta Q^{wedge n} (where below we have F=Q).
//
// q is an intvec containing the exponents responsible for defining the operators g_i,
// so that g_i is division by x(i)^q[i] without remainder.
/////////////////////////////////////////////////////////////////////////////////////
proc deltaQ(matrix F, intvec q)
{
//LIB "matrix.lib";
// The ideal whose quotient gives the algebra I is generated by the internal
// variables to the powers given by q:
int i;
ideal J;
int numX = numXVars();
for( i = 1; i <= numX; i++ )
{
J[i] = x(i)^(q[i]);
}
int n = dimAlgebraOverInternalVariables(J);
int prl = printlevel;
// The blown up matrix will be of dimension n x ncols(f):
int gg = ncols(F) * n;
list S = SGroupintvecs(numX);
int j;
matrix Mi[gg][gg];
// Precompute all the deltas:
list deltas;
for(j = 1; j <= numX; j++)
{
deltas[j] = mablow_delta(F, j, q[j], J);
}
for(i=1; i<=size(S); i++)
{
intvec perm = S[i];
matrix Ma = (-1)^(LengthSymElement(perm)) * unitmat(gg);
for(j=1; j<=numX; j++)
{
Ma = Ma * deltas[perm[j]];
}
Mi = Mi + Ma;
}
// Multiply by the scaling factor:
number ffac = 1;
for(i=1; i<=numX; i++)
{
ffac = ffac / i;
}
Mi = ffac * Mi;
return(Mi);
}
/////////////////////////////////////////////////////////////////////////////////////
// "dQ" is the symmetrised product of null homotopies in the expression
// for the idempotent. The matrix f is the differential of the matrix factorisation
// and q, C refer to the reduction to null-homotopies with respect to powers of
// variables, see "Computing Khovanov-Rozansky homology and defect fusion".
/////////////////////////////////////////////////////////////////////////////////////
proc dQ(matrix f, intvec q, matrix C)
{
//LIB "matrix.lib";
poly detC = det(C);
// The ideal whose quotient gives the algebra I is generated by the internal
// variables to the powers given by q:
int i;
ideal J;
int numX = numXVars();
for( i = 1; i <= numX; i++ )
{
J[i] = x(i)^(q[i]);
}
int n = dimAlgebraOverInternalVariables(J);
// The blown up matrix will be of dimension n x ncols(f):
int gg = ncols(f) * n;
list S = SGroupintvecs(numX);
int j;
matrix Mi[gg][gg];
// Precompute all the mablows: