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);
    }
}