{
"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
}