def tensorDandDD(self, d_graph, dd_graph): """Computes the type D structure D1 * CFAA(Id) * DD2, where D1 is a type D structure with graph d_graph, CFAA(Id) is represented by this graph, and DD2 is a type DD structure with graph dd_graph. """ assert dd_graph.tensor_side == 1 assert d_graph.algebra.opp() == self.pmc_alg assert dd_graph.algebra1 == self.pmc_alg dstr = SimpleDStructure(F2, dd_graph.algebra2) # Generators of the type D structure: for node1 in d_graph.getNodes(): for ddgen, node2 in dd_graph.ddgen_node.items(): if node1.idem == node2.idem1.opp().comp(): cur_gen = ATensorDDGenerator(dstr, node1.dgen, ddgen) dstr.addGenerator(cur_gen) # Search the graphs for type D operations for gen_start in dstr.getGenerators(): dgen, ddgen = gen_start d1_pos = d_graph.graph_node[dgen] d2_pos = dd_graph.ddgen_node[ddgen] aa_pos = self.homology_node[dgen.idem.opp()] pos = [(d1_pos, d2_pos, aa_pos)] end_states = self._searchDoubleD(d_graph, dd_graph, pos)[0] for d1_end, d2_end, aa_end in end_states: gen_end = ATensorDDGenerator(dstr, d1_end.dgen, d2_end.ddgen) dstr.addDelta(gen_start, gen_end, d2_end.sd, 1) return dstr
def toDStructure(self): """Convert this type DD structure into a type D structure over the tensor product of two algebras. """ bialgebra = TensorDGAlgebra((self.algebra1, self.algebra2)) dstr = SimpleDStructure(self.ring, bialgebra, ACTION_LEFT) gen_map = dict() for gen in self.generators: new_gen = gen.toDGenerator(dstr) gen_map[gen] = new_gen dstr.addGenerator(new_gen) for gen_from in self.generators: for (a1, a2, gen_to), coeff in self.delta_map[gen_from].items(): dstr.addDelta(gen_map[gen_from], gen_map[gen_to], TensorGenerator((a1, a2), bialgebra), coeff) return dstr
def mappingConeD(f, returnDicts = False): "Return the mapping cone of a morphism f (Element class) from one SimpleDStructure to another." #Extract some basic info from f for f0 in f.keys(): P = f0.source.parent #Source of f Q = f0.target.parent #Target of f answer = SimpleDStructure(F2,P.algebra) from_to_new = dict() to_to_new = dict() new_to_old = dict() #Add the generators for x in P.getGenerators(): newx = DGenerator(answer, x.idem) from_to_new[x] = newx new_to_old[newx] = x answer.addGenerator(newx) for x in Q.getGenerators(): newx = DGenerator(answer, x.idem) to_to_new[x] = newx new_to_old[newx] = x answer.addGenerator(newx) #Add the differential on P for x in P.getGenerators(): dx = P.delta(x) for ay in dx.keys(): answer.addDelta(from_to_new[x],from_to_new[ay[1]],ay[0],dx[ay]) for x in Q.getGenerators(): dx = Q.delta(x) for ay in dx.keys(): answer.addDelta(to_to_new[x],to_to_new[ay[1]],ay[0],dx[ay]) for f0 in f.keys(): answer.addDelta(from_to_new[f0.source],to_to_new[f0.target],f0.coeff,f[f0]) if returnDicts: return (answer, from_to_new, to_to_new, new_to_old) return answer
def tensorD(self, dstr): """Compute the box tensor product DA * D of this bimodule with the given type D structure. Returns the resulting type D structure. Uses delta() and deltaPrefix() functions of this type DA structure. """ dstr_result = SimpleDStructure(F2, self.algebra1) # Compute list of generators in the box tensor product for gen_left in self.getGenerators(): for gen_right in dstr.getGenerators(): if gen_left.idem2 == gen_right.idem: dstr_result.addGenerator(DATensorDGenerator( dstr_result, gen_left, gen_right)) def search(start_gen, cur_dgen, cur_coeffs_a): """Searching for an arrow in the box tensor product. - start_gen: starting generator in the box tensor product. The resulting arrow will start from here. - cur_dgen: current location in the type D structure. - cur_coeffs_a: current list of A-side inputs to the type DA structure (or alternatively, list of algebra outputs produced by the existing path through the type D structure). """ start_dagen, start_dgen = start_gen cur_delta = self.delta(start_dagen, cur_coeffs_a) for (coeff_d, gen_to), ring_coeff in cur_delta.items(): dstr_result.addDelta(start_gen, DATensorDGenerator( dstr_result, gen_to, cur_dgen), coeff_d, 1) if self.deltaPrefix(start_dagen, cur_coeffs_a): for (coeff_out, dgen_to), ring_coeff in \ dstr.delta(cur_dgen).items(): search(start_gen, dgen_to, cur_coeffs_a + (coeff_out,)) for x in dstr_result.getGenerators(): dagen, dgen = x search(x, dgen, ()) # Add arrows coming from idempotent output on the D-side for (coeff_out, dgen_to), ring_coeff in dstr.delta(dgen).items(): if coeff_out.isIdempotent(): dstr_result.addDelta( x, DATensorDGenerator(dstr_result, dagen, dgen_to), dagen.idem1.toAlgElt(self.algebra1), 1) # Find grading set if available on both components def tensorGradingSet(): """Find the grading set of the new type D structure.""" return GeneralGradingSet([self.gr_set, dstr.gr_set]) def tensorGrading(gr_set, dagen, dgen): """Find the grading of the generator (x, y) in the tensor type D structure. The grading set need to be provided as gr_set. """ return GeneralGradingSetElement( gr_set, [self.grading[dagen], dstr.grading[dgen]]) if hasattr(self, "gr_set") and hasattr(dstr, "gr_set"): dstr_result.gr_set = tensorGradingSet() dstr_result.grading = dict() for x in dstr_result.getGenerators(): dagen, dgen = x dstr_result.grading[x] = tensorGrading( dstr_result.gr_set, dagen, dgen) return dstr_result
def morToD(self, other): """Compute the type D structure of morphisms from self to other. Note ``other`` must be a type D structure. """ assert self.algebra1 == other.algebra alg_gens = self.algebra1.getGenerators() xlist = self.getGenerators() ylist = other.getGenerators() gens = list() dstr = SimpleDStructure(F2, self.algebra2.opp()) genType = MorDDtoDGenerator def morGradingSet(): """Find the grading set of the new type D structure.""" lr_domains = [(d1, d2.opp()) for d1, d2 in self.gr_set.periodic_domains] self.lr_set = SimpleDbGradingSet( self.gr_set.gr_group1, ACTION_LEFT, self.gr_set.gr_group2.opp(), ACTION_RIGHT, lr_domains) return GeneralGradingSet([self.lr_set.inverse(), other.gr_set]) def morGrading(gr_set, x, a, y): """Find the grading of the generator x -> ay in the morphism type D structure. The grading set need to be provided as gr_set. """ gr_x1, gr_x2 = self.grading[x].data gr_x_lr = SimpleDbGradingSetElement(self.lr_set, (gr_x1, gr_x2.opp())) gr = [gr_x_lr.inverse(), other.grading[y] * a.getGrading()] return GeneralGradingSetElement(gr_set, gr) # Prepare rev_delta for the last step in computing differentials rev_delta = self.getReverseDelta() # Get the list of generators for x in xlist: for a in alg_gens: for y in ylist: if x.idem1 == a.getLeftIdem() and \ y.idem == a.getRightIdem(): gens.append(genType(dstr, x, a, y)) for gen in gens: dstr.addGenerator(gen) # Get the type D structure maps for gen in gens: # Differential of y in (x -> ay) x, a, y = gen.source, gen.coeff, gen.target ady = a * y.delta() for (b, q), coeff in ady.items(): dstr.addDelta(gen, genType(dstr, x, b, q), None, coeff) # Differential of a for da_gen, coeff in a.diff().items(): dstr.addDelta(gen, genType(dstr, x, da_gen, y), None, coeff) # For each p such that (b1,b2)*x is in dp, add opp(b2)*(p->(b1*a)y) for (b1, b2, p), coeff1 in rev_delta[x]: for b1a_gen, coeff2 in (b1*a).items(): dstr.addDelta(gen, genType(dstr, p, b1a_gen, y), b2.opp(), coeff1*coeff2) # Find grading set and grading of elements if hasattr(self, "gr_set") and hasattr(other, "gr_set"): dstr.gr_set = morGradingSet() dstr.grading = dict() for gen in gens: dstr.grading[gen] = morGrading( dstr.gr_set, gen.source, gen.coeff, gen.target) return dstr
def testTrefoilSurgery(self): """Computes HF for +1 and -1 surgery on left-handed trefoil. """ # Everything is over the PMC of genus 1 pmc = splitPMC(1) algebra = pmc.getAlgebra() # Two idempotents i0 = pmc.idem([0]) i1 = pmc.idem([1]) # Some algebra elements rho1 = pmc.sd([(0,1)]) rho2 = pmc.sd([(1,2)]) rho3 = pmc.sd([(2,3)]) rho23 = pmc.sd([(1,3)]) rho123 = pmc.sd([(0,3)]) # Now CFD(H_+1) d_p1 = SimpleDStructure(F2, algebra) a = SimpleDGenerator(d_p1, i1, "a") b = SimpleDGenerator(d_p1, i0, "b") d_p1.addGenerator(a) d_p1.addGenerator(b) d_p1.addDelta(a, b, rho2, 1) d_p1.addDelta(b, a, rho123, 1) print "CFD(H_+1): ", d_p1 # and CFD(H_-1) d_p2 = SimpleDStructure(F2, algebra) a = SimpleDGenerator(d_p2, i1, "a") b = SimpleDGenerator(d_p2, i0, "b") d_p2.addGenerator(a) d_p2.addGenerator(b) d_p2.addDelta(b, a, rho1, 1) d_p2.addDelta(b, a, rho3, 1) print "CFD(H_-1): ", d_p2 # CFD(trefoil) d_trefoil = SimpleDStructure(F2, algebra) x = SimpleDGenerator(d_trefoil, i0, "x") y = SimpleDGenerator(d_trefoil, i0, "y") z = SimpleDGenerator(d_trefoil, i0, "z") k = SimpleDGenerator(d_trefoil, i1, "k") l = SimpleDGenerator(d_trefoil, i1, "l") mu1 = SimpleDGenerator(d_trefoil, i1, "mu1") mu2 = SimpleDGenerator(d_trefoil, i1, "mu2") for gen in [x, y, z, k, l, mu1, mu2]: d_trefoil.addGenerator(gen) d_trefoil.addDelta(x, k, rho1, 1) d_trefoil.addDelta(y, k, rho123, 1) d_trefoil.addDelta(mu2, x, rho2, 1) d_trefoil.addDelta(mu1, mu2, rho23, 1) d_trefoil.addDelta(z, mu1, rho123, 1) d_trefoil.addDelta(l, y, rho2, 1) d_trefoil.addDelta(z, l, rho3, 1) print "CFD(trefoil): ", d_trefoil # Compute the Mor complexes cx1 = d_p1.morToD(d_trefoil) # cx1 = computeATensorD(d_p1, d_trefoil) cx1.simplify() print "First result: ", cx1 cx2 = d_p2.morToD(d_trefoil) # cx2 = computeATensorD(d_p2, d_trefoil) cx2.simplify() print "Second result: ", cx2
def tensorD(self, dstr): """Compute the box tensor product DA * D of this bimodule with the given type D structure. Returns the resulting type D structure. Uses delta() and deltaPrefix() functions of this type DA structure. """ dstr_result = SimpleDStructure(F2, self.algebra1) # Compute list of generators in the box tensor product for gen_left in self.getGenerators(): for gen_right in dstr.getGenerators(): if gen_left.idem2 == gen_right.idem: dstr_result.addGenerator(DATensorDGenerator( dstr_result, gen_left, gen_right)) def search(start_gen, cur_dgen, algs, last_assign, algs_local, last_prod_d): """Searching for an arrow in the box tensor product. - start_gen: starting generator in the box tensor product. The resulting arrow will start from here. - cur_dgen: current location in the type D structure. - algs: current list of A-side inputs to the type DA structure (or alternatively, list of algebra outputs produced by the existing path through the type D structure). - algs_local: current list of local restrictions of algs. - last_assign: a list of length self.num_singles. For each split idempotent, specify the single assignments at the last algebra input. - prod_d: product of the outer restrictions, except for the last algebra input. """ start_dagen, start_dgen = start_gen local_MGen = start_dagen.local_gen # Preliminary tests if len(algs) > 0: assert algs[0].left_idem == start_dagen.idem2 for i in range(len(algs)-1): assert algs[i].right_idem == algs[i+1].left_idem if any(alg.isIdempotent() for alg in algs): return # First, adjust local module generator, and check for delta. if len(algs_local) > 0: local_MGen = self.adjustLocalMGen(local_MGen, algs_local[0]) if local_MGen is None: return local_delta = self.local_da.delta(local_MGen, tuple(algs_local)) has_delta = (local_delta != E0) # Second, check for delta prefix. has_delta_prefix = False if len(algs) == 0: has_delta_prefix = True else: dbls = [self.single_idems2[i] for i in range(self.num_singles) if last_assign[i] == self.DOUBLE] for to_remove in subset(dbls): if len(to_remove) != 0: cur_algs_local = tuple([alg.removeSingleHor(to_remove) for alg in algs_local]) else: cur_algs_local = algs_local if self.testPrefix(local_MGen, cur_algs_local): has_delta_prefix = True break if (not has_delta) and (not has_delta_prefix): return # Now, compute new prod_d. if len(algs) > 0: prod_d = self.getNewProdD(last_assign, algs[-1], last_prod_d) else: prod_d = last_prod_d if prod_d is None: return # If has_delta is True, add to delta for (local_d, local_y), ring_coeff in local_delta.items(): alg_d, y = self.joinOutput(local_d, local_y, prod_d) if alg_d is not None: dstr_result.addDelta(start_gen, DATensorDGenerator( dstr_result, y, cur_dgen), alg_d, 1) if not has_delta_prefix: return for (new_alg, dgen_to), ring_coeff in dstr.delta(cur_dgen).items(): new_assign, new_local, last_prod_d = self.extendRestrictions( last_assign, algs_local, prod_d, new_alg) if new_assign is not None: search(start_gen, dgen_to, algs + [new_alg], new_assign, new_local, last_prod_d) # Perform search for each generator in dstr_result. for x in dstr_result.getGenerators(): dagen, dgen = x prod_d = \ self.splitting2.restrictIdempotentOuter(dagen.idem2).toAlgElt() prod_d = prod_d.removeSingleHor() # always goes to LOCAL search(x, dgen, [], [self.DOUBLE] * self.num_singles, [], prod_d) # Add arrows coming from idempotent output on the D-side for (coeff_out, dgen_to), ring_coeff in dstr.delta(dgen).items(): if coeff_out.isIdempotent(): dstr_result.addDelta( x, DATensorDGenerator(dstr_result, dagen, dgen_to), dagen.idem1.toAlgElt(self.algebra1), 1) # Find grading set if available on both components def tensorGradingSet(): """Find the grading set of the new type D structure.""" return GeneralGradingSet([self.gr_set, dstr.gr_set]) def tensorGrading(gr_set, dagen, dgen): """Find the grading of the generator (x, y) in the tensor type D structure. The grading set need to be provided as gr_set. """ return GeneralGradingSetElement( gr_set, [self.grading[dagen], dstr.grading[dgen]]) if hasattr(self, "gr_set") and hasattr(dstr, "gr_set"): dstr_result.gr_set = tensorGradingSet() dstr_result.grading = dict() for x in dstr_result.getGenerators(): dagen, dgen = x dstr_result.grading[x] = tensorGrading( dstr_result.gr_set, dagen, dgen) return dstr_result