1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
|
/*
* holonomy.c
*
* This file provides the functions
*
* void compute_holonomies(Triangulation *manifold);
* void compute_edge_angle_sums(Triangulation *manifold);
*
* which the functions compute_complex_equations() and
* compute_real_equations() in gluing_equations.c call. They store
* their results directly into Triangulation *manifold, so whenever
* a hyperbolic structure has been found, you may also assume the
* holonomies are present. (The edge angle sums will be present too,
* but since they'll all be 2 pi i they won't be very interesting.)
*
* The most accurate holonomies are stored in holonomy[ultimate][M]
* and holonomy[ultimate][L]. The fields holonomy[penultimate][M]
* and holonomy[penultimate][L] store the holonomies from the
* penultimate iteration of Newton's method, for use in estimating
* the numerical error.
*
*
* The holonomy of a Klein bottle cusp deserves special discussion.
*
* (1) The holonomy of the meridian may have a rotational part, but
* never has a contraction part. I.e. it's log is pure imaginary.
* Proof: the meridian is freely homotopic to it's own inverse.
*
* (2) The holonomy of the longitude doesn't even make sense. As
* you tilt the angle of the curve at the basepoint, the angle
* of the next lift down the line rotates in the opposite
* direction. The rotational part of the holonomy is not an
* isotopy invariant for an orientation-reversing curve. The
* contraction is an isotopy invariant, but it's cleaner and
* simpler to work with the preimage of the longitude in the
* Klein bottle's orientation double cover, which is a torus.
* The curve on the double cover must have zero rotational part,
* because the orientation-reversing covering transformation
* takes the curve to itself.
*
* These observations imply that a Dehn filling on a Klein bottle cusp
* must be of the form (m,0).
*
*
* 96/9/27 I split compute_holonomies() into separate functions
* copy_holonomies_ultimate_to_penultimate() and compute_the_holonomies(),
* so that other functions (e.g. cover.c) can call compute_the_holonomies()
* to compute the penultimate holonomies directly.
*/
#include "kernel.h"
static void copy_holonomies_ultimate_to_penultimate(Triangulation *manifold);
void compute_holonomies(
Triangulation *manifold)
{
copy_holonomies_ultimate_to_penultimate(manifold);
compute_the_holonomies(manifold, ultimate);
}
static void copy_holonomies_ultimate_to_penultimate(
Triangulation *manifold)
{
/*
* Copy holonomy[ultimate][] into holonomy[penultimate][].
*/
Cusp *cusp;
int i;
for (cusp = manifold->cusp_list_begin.next;
cusp != &manifold->cusp_list_end;
cusp = cusp->next)
for (i = 0; i < 2; i++) /* i = M, L */
cusp->holonomy[penultimate][i] = cusp->holonomy[ultimate][i];
}
void compute_the_holonomies(
Triangulation *manifold,
Ultimateness which_iteration)
{
Cusp *cusp;
Tetrahedron *tet;
Complex log_z[2];
VertexIndex v;
FaceIndex initial_side,
terminal_side;
int init[2][2],
term[2][2];
int i,
j;
/*
* Initialize holonomy[which_iteration][] to zero.
*/
for (cusp = manifold->cusp_list_begin.next;
cusp != &manifold->cusp_list_end;
cusp = cusp->next)
for (i = 0; i < 2; i++) /* i = M, L */
cusp->holonomy[which_iteration][i] = Zero;
/*
* Now add the contribution of each tetrahedron.
*
* The cross section of the ideal vertex v is the union
* of two triangles, one with the right_handed orientation
* and one with the left_handed orientation (please see the
* documentationvat the top of peripheral_curves.c for details).
*
* This loop is similar to the loop in compute_complex_derivative()
* in gluing_equations.c.
*/
for (tet = manifold->tet_list_begin.next;
tet != &manifold->tet_list_end;
tet = tet->next)
for (v = 0; v < 4; v++)
for (initial_side = 0; initial_side < 4; initial_side++)
{
if (initial_side == v)
continue;
terminal_side = remaining_face[v][initial_side];
/*
* Note the log of the complex edge parameter,
* for use with the right_handed triangle.
*/
log_z[right_handed] = tet->shape[filled]->cwl[which_iteration][ edge3_between_faces[initial_side][terminal_side] ].log;
/*
* The conjugate of log_z[right_handed] will apply to
* the left_handed triangle.
*/
log_z[left_handed] = complex_conjugate(log_z[right_handed]);
/*
* Note the intersection numbers of the meridian and
* longitude with the initial and terminal sides.
*/
for (i = 0; i < 2; i++) { /* which curve */
for (j = 0; j < 2; j++) { /* which sheet */
init[i][j] = tet->curve[i][j][v][initial_side];
term[i][j] = tet->curve[i][j][v][terminal_side];
}
}
/*
* holonomy[which_iteration][i] +=
* FLOW(init[i][right_handed], term[i][right_handed]) * log_z[right_handed]
* + FLOW(init[i][left_handed ], term[i][left_handed ]) * log_z[left_handed ];
*/
for (i = 0; i < 2; i++) /* which curve */
#if 0
The stupid Symantec C compiler is choking on the following expression.
So I am breaking it into two parts to make its work easier.
original version:
tet->cusp[v]->holonomy[which_iteration][i] = complex_plus(
tet->cusp[v]->holonomy[which_iteration][i],
complex_plus(
complex_real_mult(
FLOW(init[i][right_handed], term[i][right_handed]),
log_z[right_handed]
),
complex_real_mult(
FLOW(init[i][left_handed], term[i][left_handed]),
log_z[left_handed]
)
)
);
modified version:
#else
{
Complex temp;
temp = complex_plus(
tet->cusp[v]->holonomy[which_iteration][i],
complex_plus(
complex_real_mult(
FLOW(init[i][right_handed], term[i][right_handed]),
log_z[right_handed]
),
complex_real_mult(
FLOW(init[i][left_handed], term[i][left_handed]),
log_z[left_handed]
)
)
);
tet->cusp[v]->holonomy[which_iteration][i] = temp;
}
#endif
}
}
void compute_edge_angle_sums(
Triangulation *manifold)
{
EdgeClass *edge;
Tetrahedron *tet;
EdgeIndex e;
/*
* Initialize all edge_angle_sums to zero.
*/
for ( edge = manifold->edge_list_begin.next;
edge != &manifold->edge_list_end;
edge = edge->next)
edge->edge_angle_sum = Zero;
/*
* Add in the contribution of each edge of each tetrahedron.
*
* If the EdgeClass sees the Tetrahedron as right_handed,
* add in the log of the edge parameter directly. If it sees
* it as left_handed, add in the log of the conjugate-inverse
* (i.e. add the imaginary part of the log as usual, but subtract
* the real part).
*/
for (tet = manifold->tet_list_begin.next;
tet != &manifold->tet_list_end;
tet = tet->next)
for (e = 0; e < 6; e++)
{
tet->edge_class[e]->edge_angle_sum.imag
+= tet->shape[filled]->cwl[ultimate][edge3[e]].log.imag;
if (tet->edge_orientation[e] == right_handed)
tet->edge_class[e]->edge_angle_sum.real
+= tet->shape[filled]->cwl[ultimate][edge3[e]].log.real;
else
tet->edge_class[e]->edge_angle_sum.real
-= tet->shape[filled]->cwl[ultimate][edge3[e]].log.real;
}
}
|