// Computes Heegaard Floer knot homology. // Some speed improvements due to Marc Culler // Compile: g++ -o hfk -O3 hfk-mc.cpp // TO do other knots, edit the global values before compiling #include #include #include #include using std::list; using std::vector; using std::cout; using std::cin; class Generator { public: list out; list in; list nonreduced; int AGrading; bool alive; Generator(); ~Generator(); }; // Globals const int gridsize = 11; // arc-index // Don't waste time computing factorials. Look them up. // Fill in the big ones later since g++ doesn't seem to like big constants long long Factorial[16] = { 1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600, 0,0,0}; //11n31 int white[11] = {9,6,4,5,7,8,3,2,1,10,0}; int black[11] = {2,3,1,8,10,6,7,0,9,4,5}; //11n_17 //int white[13] = {12,2,8,5,9,6,3,4,11,10,1,7,0}; //int black[13] = {8,10,0,1,6,4,5,2,3,7,9,12,11}; // Function Prototypes void GetPerm(long long k, int h []); // Fills h with the k^th permutation (in lexico. order) void NextPerm(short counter[], int h[]); bool RectDotFree(int xll, int yll, int xur, int yur, int which); // Decides whether one of the four rectangles on the torus with corners at(xll,yll) and (xur,yur) contains no white or black dots /* 1 | 2 | 1 ---+---+--- 3 | 0 | 3 ---+---+--- 1 | 2 | 1 */ bool RectWhiteFree(int xll, int yll, int xur, int yur, int which); long long Index(int y []); // Returns the number of permutations appearing before y lexicographically int WindingNumber(int x, int y); // Return winding number of the knot projection around (x,y) int MaslovGrading(int y []); bool ValidGrid(); int Find(vector & V, long long x); // Returns i if V[i]=x or -1 if x isn't V[i] for any i // Main int main(int argc, char *argv[]){ Factorial[13] = 13*Factorial[12]; Factorial[14] = 14*Factorial[13]; Factorial[15] = 15*Factorial[14]; int amin=-1; int amax=20; if(!ValidGrid()) {cout << "Invalid grid!!\n"; return 0;} // Check that the grid is valid time_t starttime = time(NULL); // Used to record how long this takes // Record winding numbers around grid points for Alexander grading computations // Also record the Alexander grading shift // Want this to be non-positive; if it isn't, exchange the white and black dots, // multiply all winding numbers by -1 and try again. int WN[gridsize][gridsize]; for(int x=0; x label; // label[i] will hold the number of perms lexicographically before the i^th generator for(int i=0; i<60; i++) NumGenByAGrading[i]=0; int g[gridsize]; //cout << "Iterating through " << Factorial[gridsize] << " generators to compute Alexander gradings...\n"; long long count=0; // Loop through generators... change the loop for different gridsize // This array is a factorial base counter used for counting through // permutations. - MC short counter[gridsize-1]; for(int i=0; i= amin && AGrading <= amax) { label.push_back(count); NumGenByAGrading[AGrading+30]++; } } /* for(int i=0;i<60;i++) { if(NumGenByAGrading[i]>0) cout << "Number of generators in Alexander grading " << (i-30) << ": " << NumGenByAGrading[i] << "\n"; } cout << "Total generators: " << label.size() << "\n"; */ vector Graph( label.size() ); // Will hold boundary data. for(int i=0; i g[j]) secondrect=0; } for(int k=j+1; k g[j]) secondrect=0; } } if(g[j] g[i]) firstrect=0; } secondrect = Rectangles[i][g[j]][j][g[i]][3]; for(int k=0; kg[j] && g[k]g[j] && g[k]::iterator j = Graph[i].out.begin(); j != Graph[i].out.end(); j++) cout << (*j) << "\n"; cout << "-1\n"; for(list::iterator j = Graph[i].in.begin(); j != Graph[i].in.end(); j++) cout << (*j) << "\n"; if( i==Graph.size()-1) cout << "-9999\n"; else cout << "-999\n"; } //cout << "Killing edges in the graph...\n"; for(int i=0; i 0) cout << "Finished " << i << " generators.\n"; if( (!Graph[i].alive) || Graph[i].out.size()==0) continue; int target = Graph[i].out.front(); // We plan to delete the edge from i to target... // For every m with i in dm, remove i from dm for(list::iterator j=Graph[i].in.begin(); j!=Graph[i].in.end(); j++) { if(Graph[*j].alive) Graph[*j].out.remove(i); } Graph[i].alive = 0; // For every m with target in dm adjust dm appropriately for(list::iterator j= Graph[ target ].in.begin(); j != Graph[ target ].in.end(); j++) { if( !Graph[*j].alive ) continue; // Replace Graph[*j].nonreduced with the symmetric difference of // Graph[*j].nonreduced and Graph[i].nonreduced for(list::iterator l = Graph[i].nonreduced.begin(); l != Graph[i].nonreduced.end(); l++) { list::iterator look = find( Graph[*j].nonreduced.begin(), Graph[*j].nonreduced.end(), *l); if(look != Graph[*j].nonreduced.end()) Graph[*j].nonreduced.erase(look); else { Graph[*j].nonreduced.push_back(*l); //if( Graph[*j].AGrading != Graph[*l].AGrading ) {cout << "Error!!!\n"; return 0;} } } for(list::iterator k = Graph[i].out.begin(); k != Graph[i].out.end(); k++) { // Search for *k in the boundary of *j // If found, remove it; if not, add it to the boundary of *j list::iterator search = find( Graph[*j].out.begin(), Graph[*j].out.end(), *k); if( search != Graph[*j].out.end() ) { Graph[ *j ].out.erase( search ); if( *k != target) Graph[ *k ].in.remove( *j ); } else { Graph[*j].out.push_back(*k); Graph[*k].in.push_back(*j); } } } // For each a in di, remove i from the in list of a for(list::iterator j=Graph[i].out.begin(); j != Graph[i].out.end(); j++) Graph[*j].in.remove(i); Graph[target].alive = 0; Graph[target].out.clear(); Graph[target].in.clear(); Graph[target].nonreduced.clear(); Graph[i].nonreduced.clear(); Graph[i].out.clear(); Graph[i].in.clear(); } vector E1Homology; for(int i=0; i amin) { Graph[i].out.clear(); E1Homology.push_back( Graph[i] ); } } // Calculate the boundaries of the generators in one lower Alexander grading //cout << "Calculating d^1 boundaries of generators in the E_1 term:\n"; for(int index=0; index < E1Homology.size(); index++) { for(list::iterator actual = E1Homology[index].nonreduced.begin(); actual != E1Homology[index].nonreduced.end(); actual++) { GetPerm(label[ *actual ],g); bool firstrect; bool secondrect; for(int i=0; i g[j]) secondrect=0; } for(int k=j+1; k g[j]) secondrect=0; } } if(g[j] g[i]) firstrect=0; } secondrect = Rectangles[i][g[j]][j][g[i]][3]; for(int k=0; kg[j] && g[k]g[j] && g[k]::iterator search = find( E1Homology[index].out.begin(), E1Homology[index].out.end(), indexgij); if (search != E1Homology[index].out.end()) E1Homology[index].out.erase(search); else { E1Homology[index].out.push_back( indexgij ); //cout << "Added " << indexgij << " to the boundary of " << i << "\n"; } } } } } } } // Check that each entry of E1Homology is actually closed in F_i/F_{i-1} //cout << "Checking that each E1 generator is actually closed in F_i/F_{i-1}...\n"; for(int i=0; i < E1Homology.size(); i++) { for(list::iterator j = E1Homology[i].out.begin(); j != E1Homology[i].out.end(); j++) { if( E1Homology[i].AGrading != Graph[ *j ].AGrading+1) { cout << "Error: the " << i << "th generator (Alexander grading " << E1Homology[i].AGrading << ") seems to have boundary in "; cout << "Alexander grading " << Graph[ *j ].AGrading << "\n"; return 0; } } } //cout << "Outputting E1 boundary data....\n"; for(int i=0; i::iterator k = E1Homology[i].out.begin(); k != E1Homology[i].out.end(); k++) cout << (*k) << "\n"; cout << "-999\n"; } cout << "-9999\n"; return 1; } // Class Functions Generator::Generator(){alive=1;}; Generator::~Generator(){}; // Actual Functions int Find(vector & V, long long x) { int above=V.size()-1; int below=0; while(above - below > 1) { if (x >= V[below+(above-below)/2]) below += (above-below)/2; else above = below+(above-below)/2; } if (V[below] == x) return below; if (V[above] == x) return above; return -1; } int WindingNumber(int x, int y){ // Return winding number around (x,y) int ret=0; for(int i=0; i= y) && (white[i] < y)) ret++; if ((white[i] >= y) && (black[i] < y)) ret--; } return ret; } int MaslovGrading(int y []) { // Use the formula: // 4M(y) = 4M(white)+4P_y(R_{y, white})+4P_{white}(R_{y, white})-8W(R_{y, white}) // = 4-4*gridsize+4P_y(R_{y, white})+4P_{x_0}(R_{y, white})-8W(R_{y, white}) int P=4-4*gridsize; // Four times the Maslov grading for(int i=0; i white[i]) && (y[j] <= white[i])) P-=7; // because of the -8W(R_{y, white}) contribution if ((y[j] > white[i]) && (white[j] <= white[i])) P+=7; if ((white[j] > y[i]) && (y[j] <= y[i])) P++; if ((y[j] > y[i]) && (white[j] <= y[i])) P--; } for(int j=0; j<=((i-1)% gridsize); j++) { // Squares whose BR corners are (i,white[i]) and (i,y[i]) (mod gridsize) if ((white[j] > white[i]) && (y[j] <= white[i])) P++; if ((y[j] > white[i]) && (white[j] <= white[i])) P--; if ((white[j] > y[i]) && (y[j] <= y[i])) P++; if ((y[j] > y[i]) && (white[j] <= y[i])) P--; } for(int j=0; j<=((i-1) % gridsize); j++) { // Squares whose TR corners are... if ((white[j] > ((white[i]-1) % gridsize)) && (y[j] <= ((white[i]-1) % gridsize))) P++; if ((y[j] > ((white[i]-1) % gridsize) ) && (white[j] <= ((white[i]-1) % gridsize))) P--; if ((white[j] > ((y[i]-1) % gridsize)) && (y[j] <= ((y[i]-1) % gridsize))) P++; if ((y[j] > ((y[i]-1) % gridsize) ) && (white[j] <= ((y[i]-1) % gridsize))) P--; } for(int j=0; j<=i; j++) { // Squares whose TL corners are... if ((white[j] > ((white[i]-1) % gridsize)) && (y[j] <= ((white[i]-1) % gridsize))) P++; if ((y[j] > ((white[i]-1) % gridsize) ) && (white[j] <= ((white[i]-1) % gridsize))) P--; if ((white[j] > ((y[i]-1) % gridsize)) && (y[j] <= ((y[i]-1) % gridsize))) P++; if ((y[j] > ((y[i]-1) % gridsize) ) && (white[j] <= ((y[i]-1) % gridsize))) P--; } } return (P/4); } bool RectDotFree(int xll, int yll, int xur, int yur, int which) { bool dotfree = 1; switch (which) { case 0: for(int x=xll; x= yll && white[x] < yur) dotfree = 0; if (black[x] >= yll && black[x] < yur) dotfree = 0; } return dotfree; case 1: for(int x=0; x= yur) dotfree = 0; if (black[x] < yll || black[x] >= yur) dotfree = 0; } for(int x=xur; x= yur) dotfree = 0; if (black[x] < yll || black[x] >= yur) dotfree = 0; } return dotfree; case 2: for(int x=xll; x= yur) dotfree = 0; if (black[x] < yll || black[x] >= yur) dotfree = 0; } return dotfree; case 3: for(int x=0; x= yll && white[x] < yur) dotfree = 0; if (black[x] >= yll && black[x] < yur) dotfree = 0; } for(int x=xur; x= yll && white[x] < yur) dotfree = 0; if (black[x] >= yll && black[x] < yur) dotfree = 0; } return dotfree; } return 0; //Error! } bool RectWhiteFree(int xll, int yll, int xur, int yur, int which) { bool dotfree = 1; switch (which) { case 0: for(int x=xll; x= yll && white[x] < yur) dotfree = 0; } return dotfree; case 1: for(int x=0; x= yur) dotfree = 0; } for(int x=xur; x= yur) dotfree = 0; } return dotfree; case 2: for(int x=xll; x= yur) dotfree = 0; } return dotfree; case 3: for(int x=0; x= yll && white[x] < yur) dotfree = 0; } for(int x=xur; x= yll && white[x] < yur) dotfree = 0; } return dotfree; } return 0; //Error! } bool ValidGrid() { int numwhite=0; int numblack=0; for(int i=0; i 0){ for (m=0; m < r; m++){ if (r - P[m] == 1) break; } index = index*(r) + m; r -= 1; temp = P[r]; P[r] = P[m]; P[m] = temp; } return index; } // Inverse mapping, from integers < n! to permutations of size n // Writes the permutation corresponding to N into the array P. void GetPerm(long long N, int P []) { int r, m, temp; for(int i=0; i