# Revision history [back]

### Conflict between generators in different groups with the same name

I wrote a relatively simple implementation of the Seifert van Kampen theorem, and I have a commutative 'cube', so to speak, meaning I want to apply it twice successively. The implementation is

# This function computes the fundamental group of a topological space X using
# the Seifert-van Kampen theorem. We decompose X into the union of two open
# connected subsets, U and V, whose fundamental groups are the free group on
# some generators along with relations alpha and beta, respectively.
# Additionally, we have the fundamental group of U \cap V, which is the free
# group on the generators gamma_i. We then have the inclusion maps
# I: \pi(U\cap V) -> \pi(U) and J: \pi(U\cap V) -> \pi(V) which gives
# us the categorical coproduct of \pi(U) * \pi(V).
def seifert_van_kampen(U, alpha, V, beta, I, J, intersection):
X = FreeGroup(U.gens() + V.gens())
relations = []
for generator in intersection.gens():
relations.append(X(I(generator))*X(J(generator))^-1)
relations = relations + alpha + beta
return X / relations


And it seems to work properly in simple cases. My problem arises when trying to apply it twice successively. My diagram looks like this:

     A --- AB
/     X    \
S -- B     AG -- X
\     X    /
G --- BG


Where S is the pairwise intersection between any of A, B, and G, and the X in the middle of the diagram represents crossing arrows. Through one application of SVK, I can get the fundamental group for AB, AG, or BG, and the problem occurs with the second step to compute the fundamental group for X.

If I have the fundamental groups for A, B, and G generated by alpha_i, beta_i, and gamma_i respectively, then the fundamental group for AB is generated by the alpha_i and beta_i, and similar for AG and BG. But if I try to use the same logic, say using AB and BG to get X, the generators would be alpha_i, beta_i from AB, and beta_i and gamma_i from BG. But my understanding is that those generators should be considered distinct, and I don't quite see how to make that happen in Sage.

In particular, the additional relations when we compute the coproduct (in the AB/BG case) come from the inclusion map of the generators for B into each of AB and BG respectively, which is exactly those duplicate generators. That part is fine, but if I want to consider those words as elements of the free group on (alpha_i, beta_i, beta_i, gamma_i), I don't know how to make those words use the 'correct' generators.

Would appreciate any help on possibly remapping the generators, or any other solutions!

### Conflict between generators in different groups with the same name

I wrote a relatively simple implementation of the Seifert van Kampen theorem, and I have a commutative 'cube', so to speak, meaning I want to apply it twice successively. The implementation is

# This function computes the fundamental group of a topological space X using
# the Seifert-van Kampen theorem. We decompose X into the union of two open
# connected subsets, U and V, whose fundamental groups are the free group on
# some generators along with relations alpha and beta, respectively.
# Additionally, we have the fundamental group of U \cap V, which is the free
# group on the generators gamma_i. We then have the inclusion maps
# I: \pi(U\cap V) -> \pi(U) and J: \pi(U\cap V) -> \pi(V) which gives
# us the categorical coproduct of \pi(U) * \pi(V).
def seifert_van_kampen(U, alpha, V, beta, I, J, intersection):
X = FreeGroup(U.gens() + V.gens())
relations = []
for generator in intersection.gens():
relations.append(X(I(generator))*X(J(generator))^-1)
relations = relations + alpha + beta
return X / relations


And it seems to work properly in simple cases. My problem arises when trying to apply it twice successively. My diagram looks like this:

     A --- AB
/     X    \
S -- B     AG -- X
\     X    /
G --- BG


Where S is the pairwise intersection between any of A, B, and G, and the X in the middle of the diagram represents crossing arrows. Through one application of SVK, I can get the fundamental group for AB, AG, or BG, and the problem occurs with the second step to compute the fundamental group for X.

If I have the fundamental groups for A, B, and G generated by alpha_i, beta_i, and gamma_i respectively, then the fundamental group for AB is generated by the alpha_i and beta_i, and similar for AG and BG. But if I try to use the same logic, say using AB and BG to get X, the generators would be alpha_i, beta_i from AB, and beta_i and gamma_i from BG. But my understanding is that those generators should be considered distinct, and I don't quite see how to make that happen in Sage.

In particular, the additional relations when we compute the coproduct (in the AB/BG case) come from the inclusion map of the generators for B into each of AB and BG respectively, which is exactly those duplicate generators. That part is fine, but if I want to consider those words as elements of the free group on (alpha_i, beta_i, beta_i, gamma_i), I don't know how to make those words use the 'correct' generators.

Would appreciate any help EDIT: To give the specific way I'm trying to use this, I'm studying 2-knots, and have a particular decomposition into 3 1-knots. The fundamental group of each of the knot complements are A, B, and G above, and I'm trying to recover the fundamental group for the original 2-knot complement. There's a lot of boilerplate stuff to get the knot in a particular representation I can work with, but right now I use the above function like this:

def SVK_cube(braids, b):
prefixes = ['x', 'y', 'z']
intersect_maps = []
groups = []

intersect_group = FreeGroup(2 * b, 'a')

# Boilerplate stuff
graph, _ = make_graph(braids, b)
graph = is_orientable(graph)
signs = orientation_signs(graph, b)

for i in range(3):
# hom[i] is the element that the ith generator of fundamental group for
# intersection gets sent to
hom, group = wirtinger_relations(braids[i], signs, b, prefixes[i])
print(group)
print(hom)
groups.append(group)
intersect_maps.append(intersect_group.hom(hom))

a_group, b_group, g_group = groups
a_rels = [a_group.gen(2*i)*a_group.gen(2*i+1)^-1 for i in range(b)]
b_rels = [b_group.gen(2*i)*b_group.gen(2*i+1)^-1 for i in range(b)]
g_rels = [g_group.gen(2*i)*g_group.gen(2*i+1)^-1 for i in range(b)]

ab = seifert_van_kampen(a_group, a_rels, b_group, b_rels, intersect_maps[0], intersect_maps[1], intersect_group)
ag = seifert_van_kampen(a_group, a_rels, g_group, g_rels, intersect_maps[0], intersect_maps[2], intersect_group)
bg = seifert_van_kampen(b_group, b_rels, g_group, g_rels, intersect_maps[1], intersect_maps[2], intersect_group)
print(ab.simplified())
print(ag.simplified())
print(bg.simplified())

braids = [[4,5,6,7,2,3,4,5,6,7],[2,3,4,5,6,7], [2, 3, 4, 5, 6, 7, -7, -7, -7, 1, 1, 1, 3, -5, -4]]
SVK_cube(braids, 4)


And this gives the output:

Free Group on possibly remapping the generators, or any other solutions!generators {x0, x1, x2, x3, x4, x5, x6, x7}
[x0, x1^-1*x2*x1, x1^-1*x3^-1*x4^-1*x3*x1, x1^-1*x3^-1*x5*x3*x1, x1^-1*x3^-1*x6^-1*x3*x1, x1^-1*x3^-1*x7*x3*x1, x1^-1*x3^-1*x1, x1^-1]
Free Group on generators {y0, y1, y2, y3, y4, y5, y6, y7}
[y0, y1^-1*y2*y1, y1^-1*y3^-1*y1, y1^-1*y4*y1, y1^-1*y5^-1*y1, y1^-1*y6*y1, y1^-1*y7^-1*y1, y1^-1]
Free Group on generators {z0, z1, z2, z3, z4, z5, z6, z7}
[(z0*z1^-1*z2*z1)^2*z0^-1*z1^-1*z2^-1*z1*z0^-1, z0*z1^-1*z2*z1*z0*z1^-1*z2^-1*z1*z0^-1, z1^-1*z3^-1*z4^-1*z3*z1, z1^-1*z6*z1, z1^-1*z6^-1*z3^-1*z6*z1, z1^-1*z6^-1*z5*z6*z1, z7*z1^-1*z7^-1, z7*z1*z7^-1*z1^-1*z7^-1]
Finitely presented group < x0, x2 |  >
Finitely presented group < x4, z0 |  >
Finitely presented group < y0, y2 |  >


I have the simplified group printed out for the sake of space, but the next step would be to take a pair of these groups and compute the coproduct again. I don't think I can use the simplified form because I need to know where the generators for b (for example) are sent to into ab and bg, which is lost in the simplified form.