FuncResult change_peripheral_curves( Triangulation *manifold, CONST MatrixInt22 change_matrices[]) { int i, v, f, old_m, old_l; double old_m_coef, /* changed from int to double, JRW 2000/01/18 */ old_l_coef; Tetrahedron *tet; Cusp *cusp; Complex old_Hm, old_Hl; /* * First make sure all the change_matrices have determinant +1. */ for (i = 0; i < manifold->num_cusps; i++) if (DET2(change_matrices[i]) != +1) return func_bad_input; /* * The change_matrices for Klein bottle cusps must have zeros in the * off-diagonal entries. (Nothing else makes sense topologically.) */ for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) if (cusp->topology == Klein_cusp) for (i = 0; i < 2; i++) if (change_matrices[cusp->index][i][!i] != 0) uFatalError("change_peripheral_curves", "change_peripheral_curves"); /* * Change the peripheral curves according to the change_matrices. * As stated at the top of this file, the transformation rule is * * | new m | | | | old m | * | | = | change_matrices[i] | | | * | new l | | | | old l | */ for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (i = 0; i < 2; i++) /* which orientation */ for (v = 0; v < 4; v++) /* which vertex */ for (f = 0; f < 4; f++) /* which side */ { old_m = tet->curve[M][i][v][f]; old_l = tet->curve[L][i][v][f]; tet->curve[M][i][v][f] = change_matrices[tet->cusp[v]->index][0][0] * old_m + change_matrices[tet->cusp[v]->index][0][1] * old_l; tet->curve[L][i][v][f] = change_matrices[tet->cusp[v]->index][1][0] * old_m + change_matrices[tet->cusp[v]->index][1][1] * old_l; } /* * Change the Dehn filling coefficients to reflect the new * peripheral curves. That is, we want the Dehn filling curves * to be topologically the same as before, even though the * coefficients will be different because we changed the basis. * * To keep our thinking straight, let's imagine all peripheral * curves -- old and new -- in terms of some arbitrary but * fixed basis for pi_1(T^2) = Z + Z. We never actually compute * such a basis, but it helps keep our thinking straight. * Relative to this fixed basis, we have * * old m = (old m [0], old m [1]) * old l = (old l [0], old l [1]) * new m = (new m [0], new m [1]) * new l = (new l [0], new l [1]) * * Note that these m's and l's are curves, not coefficients! * They are elements of pi_1(T^2) = Z + Z. * * We can then rewrite the above transformation rule, with * each peripheral curve (old m, old l, new m and new l) * appearing as a row in a 2 x 2 matrix: * * | <--new m--> | | | | <--old m--> | * | | = | change_matrices[i] | | | * | <--new l--> | | | | <--old l--> | * * We can invert the change_matrix to solve for the old curves * in terms of the new ones: * -1 * | <--old m--> | | | | <--new m--> | * | | = | change_matrices[i] | | | * | <--old l--> | | | | <--new l--> | * * The Dehn filling curve is * * old_m_coef * old_m + old_l_coef * old_l * * = old_m_coef * [ change_matrices[i][1][1] * new_m * - change_matrices[i][0][1] * new_l] * + old_l_coef * [- change_matrices[i][1][0] * new_m * + change_matrices[i][0][0] * new_l] * * = new_m * [ old_m_coef * change_matrices[i][1][1] * - old_l_coef * change_matrices[i][1][0] ] * + new_l * [- old_m_coef * change_matrices[i][0][1] * + old_l_coef * change_matrices[i][0][0] ] * * Therefore * * new_m_coef = old_m_coef * change_matrices[i][1][1] * - old_l_coef * change_matrices[i][1][0] * new_l_coef = - old_m_coef * change_matrices[i][0][1] * + old_l_coef * change_matrices[i][0][0] */ for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) if (cusp->is_complete == FALSE) { old_m_coef = cusp->m; old_l_coef = cusp->l; cusp->m = old_m_coef * change_matrices[cusp->index][1][1] - old_l_coef * change_matrices[cusp->index][1][0]; cusp->l = - old_m_coef * change_matrices[cusp->index][0][1] + old_l_coef * change_matrices[cusp->index][0][0]; } /* * Update the holonomies according to the rule * * | new H(m) | | | | old H(m) | * | | = | change_matrices[i] | | | * | new H(l) | | | | old H(l) | * * (These are actually logs of holonomies, so it's correct to * add -- not multiply -- them.) * * For complete Cusps the holonomies should be zero, but that's OK. */ for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) if ( cusp->topology == torus_cusp || cusp->topology == Klein_cusp ) /* DJH */ for (i = 0; i < 2; i++) /* i = ultimate, penultimate */ { old_Hm = cusp->holonomy[i][M]; old_Hl = cusp->holonomy[i][L]; cusp->holonomy[i][M] = complex_plus( complex_real_mult( change_matrices[cusp->index][0][0], old_Hm ), complex_real_mult( change_matrices[cusp->index][0][1], old_Hl ) ); cusp->holonomy[i][L] = complex_plus( complex_real_mult( change_matrices[cusp->index][1][0], old_Hm ), complex_real_mult( change_matrices[cusp->index][1][1], old_Hl ) ); } /* * Update the cusp_shapes. */ for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) if ( cusp->topology == torus_cusp || cusp->topology == Klein_cusp ) /* DJH */ { cusp->cusp_shape[initial] = transformed_cusp_shape( cusp->cusp_shape[initial], change_matrices[cusp->index]); if (cusp->is_complete == TRUE) cusp->cusp_shape[current] = transformed_cusp_shape( cusp->cusp_shape[current], change_matrices[cusp->index]); /* * else cusp->cusp_shape[current] == Zero, and needn't be changed. */ } return func_OK; }
static void current_curve_basis_on_cusp( Cusp *cusp, MatrixInt22 basis_change) { int m_int, l_int, the_gcd; long a, b; Complex new_shape; int multiple; int i, j; m_int = (int) cusp->m; l_int = (int) cusp->l; if (cusp->is_complete == FALSE /* cusp is filled and */ && m_int == cusp->m /* coefficients are integers */ && l_int == cusp->l) { /* * Find a and b such that am + bl = gcd(m, l). */ the_gcd = euclidean_algorithm(m_int, l_int, &a, &b); /* * Divide through by the g.c.d. */ m_int /= the_gcd; l_int /= the_gcd; /* * Set basis_change to * * m l * -b a */ basis_change[0][0] = m_int; basis_change[0][1] = l_int; basis_change[1][0] = -b; basis_change[1][1] = a; /* * Make sure the new longitude is as short as possible. * The ratio (new longitude)/(new meridian) should have a * real part in the interval (-1/2, +1/2]. */ /* * Compute the new_shape, using the tentative longitude. */ new_shape = transformed_cusp_shape( cusp->cusp_shape[initial], basis_change); /* * 96/10/1 There is a danger that for nonhyperbolic solutions * the cusp shape will be ill-defined (either very large or NaN). * However for some nonhyperbolic solutions (flat solutions * for example) it may make good sense. So we attempt to * make the longitude short iff the new_shape is defined and * not outrageously large; otherwise we're content with an * arbitrary longitude. */ if (complex_modulus(new_shape) < BIG_MODULUS) { /* * Figure out how many meridians we need to subtract * from the longitude. */ multiple = (int) floor(new_shape.real - (-0.5 + EPSILON)); /* * longitude -= multiple * meridian */ for (j = 0; j < 2; j++) basis_change[1][j] -= multiple * basis_change[0][j]; } } else { /* * Set basis_change to the identity. */ for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) basis_change[i][j] = (i == j); } }