File: holonomy.c

package info (click to toggle)
snappea 3.0d3-20.1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 5,896 kB
  • ctags: 3,582
  • sloc: ansic: 33,469; sh: 8,293; python: 7,623; makefile: 240
file content (260 lines) | stat: -rw-r--r-- 7,269 bytes parent folder | download | duplicates (12)
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;
		}
}