{ "cells": [ { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "#The following code computes involutive correction terms of iota complexes, \n", "#and of iota_K complexes, and also takes tensor products\n", "#and also duals.\n", "#examples of usage are in the subsequent cells.\n", "\n", "#The main functionalities are\n", "# CFI_tensor([C1,C2,...Cn]) tensors a list of CFI complexes together and returns a CFI complex\n", "# CFKI_tensor([C1,C2,...Cn]) tensors a list of CFKI complexes together and returns a CFKI complex\n", "# C.dual() dualizes either a CFI complex or a CFKI complex C.\n", "#inv_corr_terms(C). Gives the involutive correction terms of CFI complex\n", "#V0_inv(C) gives V0-upper and lower of a CFKi complex\n", "#AI_complex(C) input is a CFKI complex, output is AI0 as a CFI complex\n", "\n", " #The following class represents a complex over F[U]\n", " #gens should be a list of Maslov gradings (of the generators over F[U])\n", " #diff is a list of lists, of the same length as gens.\n", " #e.g. [[],[1,2],[3],[]]. in diff[i] we put all of the indices of the intersection points such that there is \n", " # a nonzero differential from i to j (the U-powers are filled in later).\n", " # We assume that the complex inputted has HF^infty equal to one tower,\n", " # supported in even gradings\n", "class CF(object):\n", " def __init__(self,gens,diff):\n", " self.gens=gens\n", " self.diff=diff\n", " self.rank=len(gens)\n", "\n", "\n", "\n", " #The following class represents an iota-complex\n", " #gens should be a list of Maslov gradings (of the generators over F[U])\n", " #diff is a list of lists, of the same length as gen.\n", " #e.g. [[],[1,2],[3],[]]. in diff[i] we put all of the indices of the intersection points such that there is \n", " # a nonzero differential from i to j (the U-powers are filled in later).\n", " # We assume the complex has either one or two towers\n", " #(and if two, then they are supported in)\n", " # iota is a list of the same length as diff and gens, and the same format\n", "\n", " \n", " \n", "class CFI(object):\n", " def __init__(self,gens,diff,iota):\n", " self.gens=gens\n", " self.diff=diff\n", " self.rank=len(gens)\n", " self.iota=iota\n", " \n", "\n", " #takes the CFI complex and returns the dual.\n", " def dual(self):\n", " new_gens=[-x for x in self.gens]\n", " new_diff=[[] for i in range(self.rank)]\n", " new_iota=[[] for i in range(self.rank)]\n", " for i in range(self.rank):\n", " for j in self.diff[i]:\n", " new_diff[j].append(i)\n", " for i in range(self.rank):\n", " for j in self.iota[i]:\n", " new_iota[j].append(i)\n", " return CFI(new_gens,new_diff,new_iota)\n", "\n", "#\n", "#gens should be a list of 3 element lists of the form [gr,i,j] represent the generators of CFK^infty.\n", "#An element [gr,i,j] represents x u^i v^j (so i and j are opposite from Ozsvath and Szabo's convention)\n", "#these are generators of the Alexander grading 0 version, so we assume that A(x)+j-i=0.\n", "#Here, gr is the Maslov (or homological) grading.\n", "#They can be any generators, so, e.g., incrementing i and j both by 1 is ok and has no effect.\n", "#diff is a list of lists, of the same length as gens.\n", "#diff[i] is a list of integers, and j is in diff[i] if and only if there is an arrow from i to j (with some weighting)\n", "#(The weighting need not be entered, since it is determined by the grading)\n", "#length of diff and gens should be equal.\n", "#iota_K is a list like diff\n", "class CFKI(object):\n", " def __init__(self,gens,diff,iota_K):\n", " self.gens=gens\n", " self.diff=diff\n", " self.rank=len(gens) \n", " self.iota_K=iota_K\n", " self.phi=[]\n", " self.psi=[]\n", " for i in range(self.rank):\n", " x=self.gens[i]\n", " phi_x=[]\n", " psi_x=[]\n", " for j in self.diff[i]:\n", " y=self.gens[j]\n", " if ((y[0]-2*y[1]-x[0]+2*x[1]+1)/2)%2==1:\n", " phi_x.append(j)\n", " if ((y[0]-2*y[2]-x[0]+2*x[2]+1)/2)%2==1:\n", " psi_x.append(j)\n", " self.phi.append(phi_x)\n", " self.psi.append(psi_x) \n", " def dual(self):\n", " new_gens=[[-x[0],-x[1],-x[2]] for x in self.gens]\n", " new_diff=[[] for i in range(self.rank)]\n", " new_iota=[[] for i in range(self.rank)]\n", " for i in range(self.rank):\n", " for j in self.diff[i]:\n", " new_diff[j].append(i)\n", " for i in range(self.rank):\n", " for j in self.iota_K[i]:\n", " new_iota[j].append(i)\n", " return CFKI(new_gens,new_diff,new_iota)\n", " \n", " \n", "#input is a pair of CFI complexes. Output is their involutive tensor product\n", "#Note that CFI_tensor (a later function) allows for a list of input complexes\n", "def CFI_tensor2(C1,C2):\n", " gens1=C1.gens\n", " gens2=C2.gens\n", " diff1=C1.diff\n", " diff2=C2.diff\n", " rank1=C1.rank\n", " rank2=C2.rank\n", " iota1=C1.iota\n", " iota2=C2.iota\n", " new_gens=[]\n", " for i in range(rank1):\n", " for j in range(rank2):\n", " new_gens.append(gens1[i]+gens2[j])\n", " diff1_x_id=tensor_maps(diff1,identity_map(rank2))\n", " id_x_diff2=tensor_maps(identity_map(rank1),diff2)\n", " new_diff=sum_maps(diff1_x_id,id_x_diff2)\n", " new_iota=tensor_maps(iota1,iota2) \n", " return CFI(new_gens,new_diff,new_iota)\n", "\n", "#CFI_tensor takes a list of objects of type CFI and returns their involutive tensor product\n", "#assumes there is at least one element of the list\n", "def CFI_tensor(complex_list):\n", " new_complex=complex_list.pop(0)\n", " for remaining in complex_list:\n", " new_complex=CFI_tensor2(new_complex,remaining)\n", " return new_complex\n", " \n", "\n", "#The following gives the list [[0],[1],[2],...[n-1]]\n", "def identity_map(n):\n", " new_map=[]\n", " for i in range(n):\n", " new_map.append([i])\n", " return new_map\n", " \n", "\n", "#SumMaps takes two square \"matrices\"\n", "#(i.e. lists of non-zero entries, corresponding to maps with equal dim of domain and codomain)\n", "#and returns their sum.\n", "def sum_maps(F,G):\n", " new_map=[]\n", " for i in range(len(F)):\n", " new_term=[]\n", " new_term.extend(F[i])\n", " new_term.extend(G[i])\n", " new_term=mod2(new_term)\n", " new_map.append(new_term)\n", " return new_map\n", "\n", "#the following tensors two maps together\n", "#We assume both maps F and G are lists\n", "#and are square, i.e. have dimensions of domain and codomain \n", "#(i.e. correspond to square matrices)\n", "def tensor_maps(F,G):\n", " rankG=len(G)\n", " new_map=[]\n", " for x1 in F:\n", " for x2 in G:\n", " T=[]\n", " for y1 in x1:\n", " for y2 in x2:\n", " T.append(y1*rankG+y2)\n", " new_map.append(T)\n", " return new_map\n", "\n", "\n", "#takes two lists, viewed as functions, and returns the list of their composition\n", "#This gives G \\circ F.\n", "def compose_maps(G,F):\n", " new_map=[]\n", " for x in F:\n", " L=[]\n", " for y in x:\n", " L.extend(G[y])\n", " L=mod2(L) \n", " new_map.append(L)\n", " return new_map\n", "\n", "\n", "\n", "\n", "# The following takes an object of class CFI and returns Cone(1+iota),\n", "#which is of an object of class CF\n", "def cone_omega(CI):\n", " r=CI.rank\n", " new_gens=deepcopy(CI.gens)\n", " for x in CI.gens:\n", " new_gens.append(x-1)\n", " new_diff=deepcopy(CI.diff)\n", " for x in CI.diff:\n", " diff_xr=[]\n", " for y in x:\n", " diff_xr.append(y+r)\n", " new_diff.append(diff_xr)\n", " for x in range(r):\n", " omega_x=[y+r for y in CI.iota[x]]\n", " omega_x.append(x+r)\n", " omega_x=mod2(omega_x)\n", " new_diff[x]=new_diff[x]+omega_x\n", " return CF(new_gens,new_diff)\n", " \n", " \n", "#The following is a helper function:\n", "#takes a list and deletes elements that\n", "#appear twice (and leaves one if they appear an odd number of times)\n", "#note that this modifies L\n", "def mod2(L):\n", " K=deepcopy(L)\n", " for x in K:\n", " if L.count(x)>1:\n", " L.remove(x)\n", " L.remove(x)\n", " return L\n", "\n", "\n", "\n", "\n", "#The following is a helper function.\n", "#We assume E is a map from C to C (i.e. an endomorphism)\n", "#Input is old map (e.g. the differential)\n", "#outputs map in new basis (e.g. new differential)\n", "#note, this changes the old map E (and returns the map E)\n", "#We assume that x_i and x_j have the same parity\n", "#We assume g(x_j)>g(x_i)\n", "#The change of basis is that x_i is replaced by x_i+U^k x_j\n", "#x_j is left the same\n", "def basis_change(E,i,j):\n", " #first changes E summands going to i \n", " for x in E:\n", " if i in x:\n", " x.append(j)\n", " mod2(x)\n", " #then changes terms going from j\n", " for y in E[j]:\n", " E[i].append(y)\n", " mod2(E[i])\n", " return E \n", "\n", "\n", "\n", "\n", "\n", "\n", "#The following is a helper function:\n", "#The following deletes all arrows with a power of U^i, where i=power\n", "# It does this via a change of basis, and then deleting 2 step complexes\n", "#Note, the program assumes that there are no arrows weighted by U^n for n1:\n", " basis_change(diff, y_special,diff[x][0])\n", " for x_other in range(rank):\n", " if y_special in diff[x_other] and not x_other==x:\n", " basis_change(diff, x_other,x)\n", " to_delete.append(y_special)\n", " to_delete.append(x)\n", " to_delete.sort(reverse=True)\n", " # deletes all the entries of to_delete, and shifts diff correctly each time\n", " for i in to_delete:\n", " del diff[i]\n", " del gens[i]\n", " for Dx in diff:\n", " for j in range(len(Dx)):\n", " if Dx[j]>i:\n", " Dx[j]=Dx[j]-1\n", "\n", " \n", "#is_zero checks whether a list is of the form [[],dots[]]\n", "def is_zero(L):\n", " is_zero=true\n", " for x in L:\n", " if x!=[]:\n", " is_zero=false\n", " break\n", " return is_zero\n", "\n", "\n", "#input is a CF complex with some number of towers\n", "#output is a LIST of the gradings of the towers (one entry for each tower generator)\n", "def d_list(C):\n", " diff_copy=deepcopy(C.diff)\n", " gens_copy=deepcopy(C.gens)\n", " power=0\n", " while(not is_zero(diff_copy)):\n", " delete_arrows(diff_copy,gens_copy,power)\n", " power=power+1\n", " return gens_copy\n", "\n", "\n", "\n", "\n", "#input is an object of type CFI\n", "#output are the involutive correction terms,as [d-lower,d-upper]\n", "\n", "def inv_corr_terms(C):\n", " corr_terms=d_list(cone_omega(C))\n", " if corr_terms[0]%2==0:\n", " corr_terms[1]=corr_terms[1]+1\n", " return corr_terms\n", " if corr_terms[0]%2==1:\n", " corr_terms.reverse()\n", " corr_terms[1]=corr_terms[1]+1\n", " return corr_terms \n", " \n", " \n", "\n", "# input is a pair of CFKI objects, and the output is their tensor product\n", "def CFKI_tensor2(C1,C2):\n", " gens1=C1.gens\n", " gens2=C2.gens\n", " diff1=C1.diff\n", " diff2=C2.diff\n", " rank1=C1.rank\n", " rank2=C2.rank\n", " iota_K1=C1.iota_K\n", " iota_K2=C2.iota_K\n", " phi1=C1.phi\n", " psi2=C2.psi\n", " new_gens=[]\n", " for i in range(rank1):\n", " for j in range(rank2):\n", " new_gens.append([gens1[i][0]+gens2[j][0],gens1[i][1]+gens2[j][1],gens1[i][2]+gens2[j][2]])\n", " diff1_x_id=tensor_maps(diff1,identity_map(rank2))\n", " id_x_diff2=tensor_maps(identity_map(rank1),diff2)\n", " new_diff=sum_maps(diff1_x_id,id_x_diff2)\n", " iota_tensor=tensor_maps(iota_K1,iota_K2)\n", " phi_x_psi=tensor_maps(phi1,psi2)\n", " new_iota=sum_maps(iota_tensor,compose_maps(iota_tensor,phi_x_psi)) \n", " return CFKI(new_gens,new_diff,new_iota)\n", "\n", "#CFKI_tensor takes a list of objects of type CFI and returns their involutive tensor product\n", "#assumes there is at least one element of the list\n", "def CFKI_tensor(complex_list):\n", " new_complex=complex_list.pop(0)\n", " for remaining_complex in complex_list:\n", " new_complex=CFKI_tensor2(new_complex,remaining_complex)\n", " return new_complex\n", "\n", "\n", "#input is a CFKI object C, and output is a CFI object\n", "#sends (CFK^infty,iota_K) to (A_0(K),iota_K)\n", "def AI_complex(C):\n", " old_gens=C.gens\n", " new_gens=[]\n", " for x in old_gens:\n", " old_grading=x[0]\n", " index_i=x[1]\n", " index_j=x[2]\n", " new_grading=old_grading+2*min(index_i,index_j)\n", " new_gens.append(new_grading)\n", " return CFI(new_gens,deepcopy(C.diff), deepcopy(C.iota_K))\n", "\n", "\n", "\n", "#input is a CFKI object, output is the pair [V_0_lower, V_0_upper]\n", "def V0_inv(C):\n", " A0_C=AI_complex(C)\n", " unnormalized=inv_corr_terms(A0_C)\n", " return [-unnormalized[1]/2, -unnormalized[0]/2]" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "T23_gens=[[-2,0,1],[-1,0,0],[-2,1,0]]\n", "T23_diff=[[],[0,2],[]]\n", "T23_iota=[[2],[1],[0]]\n", "T23=CFKI(T23_gens,T23_diff,T23_iota)\n", "\n", "T38_gens=[[-14,7,0],[-13,6,0],[-14,6,2],[-13,5,2],[-14,5,4],[-13,4,4],[-14,4,5],[-13,2,5],[-14,2,6],[-13,0,6],[-14,0,7]]\n", "T38_diff=[[],[0,2],[],[2,4],[],[4,6],[],[6,8],[],[8,10],[]]\n", "T38_iota=[[10],[9],[8],[7],[6],[5],[4],[3],[2],[1],[0]]\n", "T38=CFKI(T38_gens,T38_diff,T38_iota)\n", "\n", "T213_gens=[[-12,6,0],[-11,5,0],[-12,5,1],[-11,4,1],[-12,4,2],[-11,3,2],[-12,3,3],[-11,2,3],[-12,2,4],[-11,1,4],[-12,1,5],[-11,0,5],[-12,0,6]]\n", "T213_diff=[[],[0,2],[],[2,4],[],[4,6],[],[6,8],[],[8,10],[],[10,12],[]]\n", "T213_iota=[[12],[11],[10],[9],[8],[7],[6],[5],[4],[3],[2],[1],[0]]\n", "T213=CFKI(T213_gens,T213_diff,T213_iota)\n", "\n", "\n", "T45_gens=[[-12,0,6],[-11,0,5],[-12,3,5],[-11,3,3],[-12,5,3],[-11,5,0],[-12,6,0]]\n", "T45_diff=[[],[0,2],[],[2,4],[],[4,6],[]]\n", "T45_iota=[[6],[5],[4],[3],[2],[1],[0]]\n", "T45=CFKI(T45_gens,T45_diff,T45_iota)\n", "\n", "T34_gens=[[-6,0,3],[-5,0,2],[-6,2,2],[-5,2,0],[-6,3,0]] \n", "T34_diff=[[],[0,2],[],[2,4],[]]\n", "T34_iota=[[4],[3],[2],[1],[0]]\n", "T34=CFKI(T34_gens,T34_diff,T34_iota)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "V0_inv(CFKI_tensor([T23,T23]))" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "V0_inv(CFKI_tensor([T213.dual(),T38]))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 9.1", "language": "sage", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }