def delta_ell(module: Module, x: ETangleStrands) -> Module.TensorElement: out = module.zero() unoccupied = set(x.etangle.left_points()) - set(x.left_strands.keys()) for a1 in unoccupied: for a2 in unoccupied: if a1 < a2: out += delta_ell_case_1(module, x, a1, a2) for a1 in x.left_strands.keys(): for a2 in x.left_strands.keys(): if a1 < a2 and x.left_strands[a1] > x.left_strands[a2]: out += delta_ell_case_2(module, x, a1, a2) for a1 in unoccupied: for a2 in x.left_strands.keys(): if a1 < a2: out += delta_ell_case_3(module, x, a1, a2) for a1 in x.left_strands.keys(): for a2 in unoccupied: if a1 < a2: out += delta_ell_case_4(module, x, a1, a2) return out
def introduce_left_crossing(module: Module, x: ETangleStrands, b1: int, b2: int) -> Module.TensorElement: a1 = x.left_y_pos(b1) a2 = x.left_y_pos(b2) crossing_range_1 = range(a1, b2 + 1) if a1 < b2 else range(b2, a1 + 1) crossing_range_2 = range(a2, b1 + 1) if a2 < b1 else range(b1, a2 + 1) possible_crossings = list(set(crossing_range_1) & set(crossing_range_2)) sd = introduce_left_crossing(x, b1, b2, possible_crossings[0]) for crossing in possible_crossings[1:]: new_sd = introduce_left_crossing(x, b1, b2, crossing) if new_sd.num_orange_black_crossings() < sd.num_orange_black_crossings( ): sd = new_sd c = x.etangle.ring.one() powers = sd.figure_7_relations() if powers is None: return module.zero() for orange, power in powers.items(): c *= x.etangle.strand_index_to_variable(orange)**power new_left_strands = swap_values(x.left_strands, a1, a2) x_out = ETangleStrands(x.etangle, new_left_strands, x.right_strands) return c * x_out.to_generator(module)
def d_mixed(module: Module, x: ETangleStrands) -> Module.TensorElement: out = module.zero() for b1 in x.right_strands.keys(): for b2 in x.right_strands.keys(): # if two black strands don't cross on the right if b1 < b2 and x.right_y_pos(b1) < x.right_y_pos(b2): out += d_mixed_case_1(module, x, b1, b2) for b1 in x.left_strands.values(): for b2 in x.left_strands.values(): # if two black strands cross on the left if b1 < b2 and x.left_y_pos(b1) > x.left_y_pos(b2): out += d_mixed_case_2(module, x, b1, b2) for b1 in x.right_strands.keys(): for b2 in x.left_strands.values(): if b1 < b2: out += d_mixed_case_3(module, x, b1, b2) for b1 in x.left_strands.values(): for b2 in x.right_strands.keys(): if b1 < b2: out += d_mixed_case_4(module, x, b1, b2) return out
def __pow__(self, other: TypeDA) -> TypeDA: assert self.right_algebra == other.left_algebra left_right_iso = Z2PolynomialRing.Map.identity(other.left_algebra.ring, self.right_algebra.ring) in_m, in_n = self.right_scalar_action.compose( left_right_iso).pushout_inclusions(other.left_scalar_action) out = TypeDA(in_m.target, self.left_algebra, other.right_algebra, in_m.compose(self.left_scalar_action), in_n.compose(other.right_scalar_action)) for x_m, x_m_data in self.graph.nodes(data=True): for x_n, x_n_data in other.graph.nodes(data=True): x_m_grading = x_m_data['grading'] x_n_grading = x_n_data['grading'] if x_m.right_idempotent == x_n.left_idempotent: out.add_generator( Module.TensorGenerator(out, (x_m.key, x_n.key), x_m.left_idempotent, x_n.right_idempotent), (x_m_grading[0] + x_n_grading[0], x_m_grading[1] + x_n_grading[1])) for x_m in self.graph.nodes: for x_n in other.graph.nodes: if x_m.right_idempotent != x_n.left_idempotent: continue x = Module.TensorGenerator(out, (x_m.key, x_n.key), x_m.left_idempotent, x_n.right_idempotent) for _, y_m, (left_m, right_m), d_m in self.graph.out_edges(x_m, keys=True, data=True): for right_n, y_n, c_n in other.delta_n(right_m, x_n): if y_m.right_idempotent != y_n.left_idempotent: continue c_m = d_m['c'] y = Module.TensorGenerator(out, (y_m.key, y_n.key), y_m.left_idempotent, y_n.right_idempotent) out.add_structure_map( x**right_n, left_m**(in_m.apply(c_m) * in_n.apply(c_n) * y)) return out
def d_plus(module: Module, x: ETangleStrands) -> Module.TensorElement: out = module.zero() for black1, black2 in itertools.combinations(x.right_strands.keys(), 2): b1 = min(black1, black2) b2 = max(black1, black2) if x.right_y_pos(b1) > x.right_y_pos(b2): # smooth the crossing and add it to the output out += smooth_right_crossing(module, x, b1, b2) return out
def d_minus(module: Module, x: ETangleStrands) -> Module.TensorElement: out = module.zero() for black1, black2 in itertools.combinations(x.left_strands.values(), 2): b1 = min(black1, black2) b2 = max(black1, black2) # if the black strands don't cross if x.left_y_pos(b1) < x.left_y_pos(b2): # introduce a crossing and add it to the output out += introduce_left_crossing(module, x, b1, b2) return out
def d_mixed_case_1(module: Module, x: ETangleStrands, b1: int, b2: int) -> Module.TensorElement: c = x.etangle.ring.one() powers = x.to_strand_diagram().figure_8_case_1b(b1, b2) if powers is None: return module.zero() for orange, power in powers.items(): c *= x.etangle.strand_index_to_variable(orange)**power x_out = ETangleStrands(x.etangle, x.left_strands, swap_values(x.right_strands, b1, b2)) return c * x_out.to_generator(module)
def m2(module: Module, x: ETangleStrands, a: AMinus.Generator) -> Module.TensorElement: # if the sign sequences do not match, return 0 if x.etangle.right_sign_sequence() != a.algebra.ss: return module.zero() # if the strands cannot be merged, return 0 if set(x.right_strands.values()) != set(a.strands.keys()): return module.zero() orange_strands = {} orange_signs = {} for orange in range(1, len(x.etangle.signs)): if x.etangle.right_y_pos(orange): orange_strands[orange] = (x.etangle.middle_y_pos(orange), x.etangle.right_y_pos(orange), x.etangle.right_y_pos(orange)) orange_signs[orange] = x.etangle.signs[orange] black_strands = {} for black in x.right_strands.keys(): black_strands[black] = (black, x.right_strands[black], a.strands[x.right_strands[black]]) c = x.etangle.ring.one() sd = StrandDiagram(orange_strands, orange_signs, black_strands) powers = sd.figure_6_relations() if powers is None: return module.zero() for orange, power in powers.items(): for _ in range(power): c *= x.etangle.strand_index_to_variable(orange) new_right_strands = { sd.black_left_pos(black): sd.black_right_pos(black) for black in x.right_strands.keys() } x_out = ETangleStrands(x.etangle, x.left_strands, new_right_strands) return c * x_out.to_generator(module)
def delta_ell_case_2(module: Module, x: ETangleStrands, a1: int, a2: int) -> Module.TensorElement: c1 = module.left_algebra.ring.one() c2 = x.etangle.ring.one() powers = x.idempotent_and_left_strands().figure_8_case_2a(a1, a2) if powers is None: return module.zero() for orange, power in powers.items(): if x.etangle.strand_index_to_left_sign(orange) == 1: c1 *= x.etangle.left_algebra_strand_index_to_variable( orange)**power else: c2 *= x.etangle.strand_index_to_variable(orange)**power elt = x.left_idempotent() y = ETangleStrands(x.etangle, swap_values(x.left_strands, a1, a2), x.right_strands) return (c1 * elt)**(c2 * y.to_generator(module))
def d_mixed_case_4(module: Module, x: ETangleStrands, b1: int, b2: int) -> Module.TensorElement: c = x.etangle.ring.one() powers = x.to_strand_diagram().figure_8_case_4b(b1, b2) if powers is None: return module.zero() for orange, power in powers.items(): c *= x.etangle.strand_index_to_variable(orange)**power a1 = x.left_y_pos(b1) a2 = x.right_y_pos(b2) new_left_strands = dict(x.left_strands) new_left_strands[a1] = b2 new_right_strands = dict(x.right_strands) del new_right_strands[b2] new_right_strands[b1] = a2 x_out = ETangleStrands(x.etangle, new_left_strands, new_right_strands) return c * x_out.to_generator(module)
def delta_ell_case_4(module: Module, x: ETangleStrands, a1: int, a2: int) -> Module.TensorElement: c1 = module.left_algebra.ring.one() c2 = x.etangle.ring.one() powers = x.idempotent_and_left_strands().figure_8_case_4a(a1, a2) if powers is None: return module.zero() for orange, power in powers.items(): if x.etangle.strand_index_to_left_sign(orange) == 1: c1 *= x.etangle.left_algebra_strand_index_to_variable( orange)**power else: c2 *= x.etangle.strand_index_to_variable(orange)**power b1 = x.left_strands[a1] b2 = a2 elt_strands = x.left_idempotent_strands() elt_strands[b2] = a1 new_left_strands = dict(x.left_strands) del new_left_strands[a1] new_left_strands[a2] = b1 elt = x.etangle.left_algebra.generator(elt_strands) y = ETangleStrands(x.etangle, new_left_strands, x.right_strands) return (c1 * elt)**(c2 * y.to_generator(module))
def __init__(self): Module.__init__(self)
def to_generator(self, module): from Modules.Module import Module return Module.TensorGenerator(module, str(self), self.left_idempotent(), self.right_idempotent())