def tensorDoubleDD(self, dd_graph1, dd_graph2): """Compute the type DD structure DD1 * CFAA(Id) * DD2.""" assert dd_graph1.tensor_side == 2 and dd_graph2.tensor_side == 1 assert dd_graph1.algebra2.opp() == self.pmc_alg assert dd_graph2.algebra1 == self.pmc_alg ddstr = SimpleDDStructure(F2, dd_graph1.algebra1, dd_graph2.algebra2) # Generators of the type DD structure: for ddgen1, node1 in dd_graph1.ddgen_node.items(): for ddgen2, node2 in dd_graph2.ddgen_node.items(): if node1.idem2 == node2.idem1.opp().comp(): cur_gen = DATensorDDGenerator(ddstr, ddgen1, ddgen2) ddstr.addGenerator(cur_gen) # Search the graphs for type DD operations for gen_start in ddstr.getGenerators(): ddgen1, ddgen2 = gen_start d1_pos = dd_graph1.ddgen_node[ddgen1] d2_pos = dd_graph2.ddgen_node[ddgen2] aa_pos = self.homology_node[ddgen1.idem2.opp()] pos = [(d1_pos, d2_pos, aa_pos)] end_states = self._searchDoubleD(dd_graph1, dd_graph2, pos)[0] for d1_end, d2_end, aa_end in end_states: gen_end = DATensorDDGenerator(ddstr, d1_end.ddgen, d2_end.ddgen) ddstr.addDelta(gen_start, gen_end, d1_end.sd, d2_end.sd, 1) return ddstr
def toDDStructure(self): """Convert this to a type DD structure over algebra1 and cobar of algebra2. """ cobar2 = CobarAlgebra(self.algebra2) ddstr = SimpleDDStructure(self.ring, self.algebra1, cobar2) dagen_to_ddgen_map = dict() for gen in self.generators: ddgen = SimpleDDGenerator(ddstr, gen.idem1, gen.idem2, gen.name) dagen_to_ddgen_map[gen] = ddgen ddstr.addGenerator(ddgen) for (gen_from, coeffs_a), target in self.da_action.items(): for (coeff_d, gen_to), ring_coeff in target.items(): idem = None if len(coeffs_a) == 0: idem = gen_from.idem2 assert idem == gen_to.idem2 cobar_gen = TensorStarGenerator(coeffs_a, cobar2, idem) ddstr.addDelta(dagen_to_ddgen_map[gen_from], dagen_to_ddgen_map[gen_to], coeff_d, cobar_gen, ring_coeff) return ddstr
def tensorDD(self, ddstr): """Compute the box tensor product DA * DD of this bimodule with the given type DD structure. Returns the resulting type DD structure. Uses delta() and deltaPrefix() functions of this type DA structure. """ ddstr_result = SimpleDDStructure(F2, self.algebra1, ddstr.algebra2) # Compute list of generators in the box tensor product for gen_left in self.getGenerators(): for gen_right in ddstr.getGenerators(): if gen_left.idem2 == gen_right.idem1: ddstr_result.addGenerator(DATensorDDGenerator( ddstr_result, gen_left, gen_right)) def search(start_gen, cur_ddgen, cur_algd, 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_ddgen: current location in the type DD structure. - cur_algd: current product algebra outputs on the right side of the DD structure. - cur_coeffs_a: current list of A-side inputs to the type DA structure (or alternatively, list of algebra outputs on the left side of the DD 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(): ddstr_result.addDelta(start_gen, DATensorDDGenerator( ddstr_result, gen_to, cur_ddgen), coeff_d, cur_algd, 1) if self.deltaPrefix(start_dagen, cur_coeffs_a): for (coeff_out1, coeff_out2, dgen_to), ring_coeff in \ ddstr.delta(cur_ddgen).items(): new_algd = cur_algd * coeff_out2 if new_algd != E0: search(start_gen, dgen_to, new_algd.getElt(), cur_coeffs_a + (coeff_out1,)) for x in ddstr_result.getGenerators(): dagen, ddgen = x search(x, ddgen, ddgen.idem2.toAlgElt(ddstr.algebra2), ()) # Add arrows coming from idempotent output on the left DD-side for (coeff_out1, coeff_out2, dgen_to), ring_coeff in \ ddstr.delta(ddgen).items(): if coeff_out1.isIdempotent(): ddstr_result.addDelta( x, DATensorDDGenerator(ddstr_result, dagen, dgen_to), dagen.idem1.toAlgElt(self.algebra1), coeff_out2, 1) # Grading is omitted. return ddstr_result
def getAdmissibleDDStructure(self): """Returns the type DD structure corresponding to the Heegaard diagram created by a finger move of the beta circle to the right. """ alg1 = self.start_pmc.getAlgebra(mult_one = True) alg2 = alg1 ddstr = SimpleDDStructure(F2, alg1, alg2) # Add generators for the non-admissible case - that is, those generators # that do not contain the two intersections created by the finger move. original_idems = self._getIdems() for i in range(len(original_idems)): left_idem, right_idem = original_idems[i] ddstr.addGenerator( SimpleDDGenerator(ddstr, left_idem, right_idem, "0_%d" % i)) # Now add the new generators. These just correspond to the complementary # idempotents with c_pair on the left, repeated twice. left_idems = [idem for idem in self.start_pmc.getIdempotents() if self.c_pair in idem] for i in range(len(left_idems)): left_idem = left_idems[i] right_idem = left_idem.opp().comp() ddstr.addGenerator( SimpleDDGenerator(ddstr, left_idem, right_idem, "1_%d" % i)) ddstr.addGenerator( SimpleDDGenerator(ddstr, left_idem, right_idem, "2_%d" % i)) gen_set = [] for i in range(3): gen_set.append([gen for gen in ddstr.getGenerators() if gen.name[:1] == "%d" % i]) # Enumerate the non-special chords (those that do not dependent on the # idempotent. See the functions themselves for the format of all_chords. if self.is_degenerate: all_chords = self._getAdmissibleNonSpecialChordsDegenerate() else: all_chords = self._getAdmissibleNonSpecialChords() for i, j in itertools.product(range(3), range(3)): all_chords[i][j] = [self._StrandsFromChords(chord1, chord2) for chord1, chord2 in all_chords[i][j]] # Now we emulate the logic in ddstructure.DDStrFromChords, except we # distinguish between ''classes'' of generators, by the first character # of the name of the generator. for i, j in itertools.product(range(3), range(3)): for x, y in itertools.product(gen_set[i], gen_set[j]): for l_chord, r_chord in all_chords[i][j]: if l_chord.idemCompatible(x.idem1, y.idem1) and \ r_chord.idemCompatible(x.idem2, y.idem2): ddstr.addDelta(x, y, StrandDiagram(alg1, x.idem1, l_chord), StrandDiagram(alg2, x.idem2, r_chord), 1) # Special handling for these. From class 2 to class 1, add only if the # c-pair is occupied on the left side (and not on the right). # Non-degenerate cases only. sp_chords = [] if not self.is_degenerate: for x in range(0, self.c1): for y in range(self.c2+1, self.n): sp_chords.append(([(x, y)], [(x, self.u), (self.u, y)])) sp_chords.append(([(x, y)], [(x, self.d), (self.d, y)])) sp_chords.append(([(x, self.d), (self.u, y)], [(x, self.d), (self.u, y)])) sp_chords = [self._StrandsFromChords(chord1, chord2) for chord1, chord2 in sp_chords] for x, y in itertools.product(gen_set[2], gen_set[1]): for l_chord, r_chord in sp_chords: if self.c_pair in x.idem1 and \ l_chord.idemCompatible(x.idem1, y.idem1) and \ r_chord.idemCompatible(x.idem2, y.idem2): assert self.c_pair not in x.idem2.opp() and \ self.c_pair in y.idem1 and \ self.c_pair not in y.idem2.opp() ddstr.addDelta(x, y, StrandDiagram(alg1, x.idem1, l_chord), StrandDiagram(alg2, x.idem2, r_chord), 1) assert ddstr.testDelta() return ddstr
def testDDStructureDelta(self): # Construct type DD structures, and test whether d^2 = 0 holds. # PMC on both sides are genus 1 split PMC. pmc = splitPMC(1) # Strand algebra corresponding to pmc. alg = pmc.getAlgebra() # Initialize type DD structure over field F_2, with (left-left) action # by the genus 1 strand algebra. Intend to make this type DD bimodule # for identity. ddstr1 = SimpleDDStructure(F2, alg, alg) # Initialize the list of generators to add to ddstr1. # The generators have "complementary" idempotents. However, since the # PMCs are in opposite direction on both sides, the vector specifying # idempotents are the same. idems = {"x" : ([0], [0]), "y" : ([1], [1])} gens = {} for name, (idem1, idem2) in idems.items(): gens[name] = SimpleDDGenerator( ddstr1, Idempotent(pmc, idem1), Idempotent(pmc, idem2), name) ddstr1.addGenerator(gens[name]) # Now add delta ddstr1.addDelta(gens["x"], gens["y"], pmc.sd([(0, 1)]), pmc.sd([(2, 3)]), 1) ddstr1.addDelta(gens["y"], gens["x"], pmc.sd([(1, 2)]), pmc.sd([(1, 2)]), 1) ddstr1.addDelta(gens["x"], gens["y"], pmc.sd([(2, 3)]), pmc.sd([(0, 1)]), 1) # This already satisfies d^2 = 0 self.assertTrue(ddstr1.testDelta()) # However, one more arrow to finish the bimodule ddstr1.addDelta(gens["x"], gens["y"], pmc.sd([(0, 3)]), pmc.sd([(0, 3)]), 1) # This is now the identity bimodule, of course satisfying d^2 = 0. self.assertTrue(ddstr1.testDelta()) # Second example, showing failure of testDelta() ddstr2 = SimpleDDStructure(F2, alg, alg) # Add the same generators as before gens = {} for name, (idem1, idem2) in idems.items(): gens[name] = SimpleDDGenerator( ddstr2, Idempotent(pmc, idem1), Idempotent(pmc, idem2), name) ddstr2.addGenerator(gens[name]) # Now add delta ddstr2.addDelta(gens["x"], gens["y"], pmc.sd([(0, 1)]), pmc.sd([(0, 1)]), 1) ddstr2.addDelta(gens["y"], gens["x"], pmc.sd([(1, 2)]), pmc.sd([(1, 2)]), 1) # Prints the type DD structure. Note the code already checks that # idempotent matches in all added arrows (throws an error if they don't # match). print ddstr2 # However, testDelta() fails. Prints a term in d^2(x). self.assertFalse(ddstr2.testDelta())
def testHochchild(self): pmc = splitPMC(1) alg = MinusStrandAlgebra(F2, pmc) ddstr = SimpleDDStructure(F2, alg, alg) # Initialize the list of generators to add to ddstr1. idems = {"x" : ([0], [0]), "y" : ([1], [1])} gens = {} for name, (idem1, idem2) in idems.items(): gens[name] = SimpleDDGenerator( ddstr, Idempotent(pmc, idem1), Idempotent(pmc, idem2), name) ddstr.addGenerator(gens[name]) # Now add delta ddstr.addDelta(gens["x"], gens["y"], minusSD(pmc, [(0, 1)]), minusSD(pmc, [(2, 3)]), 1) ddstr.addDelta(gens["y"], gens["x"], minusSD(pmc, [(1, 2)]), minusSD(pmc, [(1, 2)]), 1) ddstr.addDelta(gens["x"], gens["y"], minusSD(pmc, [(2, 3)]), minusSD(pmc, [(0, 1)]), 1) ddstr.addDelta(gens["y"], gens["x"], minusSD(pmc, [(3, 0)]), minusSD(pmc, [(3, 0)]), 1) print ddstr self.assertTrue(ddstr.testDelta()) dstr = ddstr.toDStructure() print dstr self.assertTrue(dstr.testDelta()) hochchild = dstr.morToD(dstr) print hochchild hochchild.simplify(find_homology_basis = True) print len(hochchild) meaning_len = [len(gen.prev_meaning) for gen in hochchild.getGenerators()] for gen in hochchild.getGenerators(): print gen.prev_meaning