static Boolean singular_set_is_empty( WEPolyhedron *polyhedron) { /* * Check whether the singular set of this orbifold is empty. */ WEVertexClass *vertex_class; WEEdgeClass *edge_class; WEFaceClass *face_class; for (vertex_class = polyhedron->vertex_class_begin.next; vertex_class != &polyhedron->vertex_class_end; vertex_class = vertex_class->next) if (vertex_class->singularity_order >= 2) return FALSE; /* * Dirichlet_construction.c subdivides Dirichlet domains for * orbifolds so that the k-skeleton of the singular set lies * in the k-skeleton of the Dirichlet domain (k = 0,1,2). * Thus if there are no singular VertexClasses, there can't be * any singular EdgeClasses or FaceClasses either. */ for (edge_class = polyhedron->edge_class_begin.next; edge_class != &polyhedron->edge_class_end; edge_class = edge_class->next) if (edge_class->singularity_order >= 2) uFatalError("singular_set_is_empty", "Dirichlet_conversion"); for (face_class = polyhedron->face_class_begin.next; face_class != &polyhedron->face_class_end; face_class = face_class->next) if (face_class->num_elements != 2) uFatalError("singular_set_is_empty", "Dirichlet_conversion"); /* * No singularities are present. */ return TRUE; }
Boolean mark_fake_cusps( Triangulation *manifold) { int real_cusp_count, fake_cusp_count; Cusp *cusp; compute_cusp_Euler_characteristics(manifold); real_cusp_count = 0; fake_cusp_count = 0; for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) switch (cusp->euler_characteristic) { case 0: cusp->is_finite = FALSE; cusp->index = real_cusp_count++; break; case 2: cusp->is_finite = TRUE; cusp->index = --fake_cusp_count; break; default: uFatalError("mark_fake_cusps", "cusps"); } return (fake_cusp_count < 0); }
void count_cusps( Triangulation *manifold) { Cusp *cusp; manifold->num_cusps = 0; manifold->num_or_cusps = 0; manifold->num_nonor_cusps = 0; for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) { manifold->num_cusps++; switch (cusp->topology) { case torus_cusp: manifold->num_or_cusps++; break; case Klein_cusp: manifold->num_nonor_cusps++; break; default: uFatalError("count_cusps", "cusps"); } } }
void uAutoReleaseObject(uObject* obj) { uThreadData* thread = uGetThreadData(); if (thread->AutoReleaseStack.Length() == 0) uFatalError(XLI_FUNCTION); if (obj) { thread->AutoReleasePool.Add(obj); #ifdef U_DEBUG_MEM int releaseCount = 0; for (int i = 0; i < thread->AutoReleasePool.Length(); i++) if (thread->AutoReleasePool[i] == obj) releaseCount++; int retainCount = obj->__obj_retains - releaseCount; if (retainCount < 0) Xli::Error->WriteFormat("*** BAD RELEASE: '%s', object id: %d (%d retains) ***\n", obj->__obj_type->TypeName, obj->__obj_id, retainCount); #endif } }
static void pick_base_tet( Triangulation *manifold, Cusp *cusp, Tetrahedron **base_tet, VertexIndex *base_vertex) { Tetrahedron *tet; VertexIndex v; for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (v = 0; v < 4; v++) if (tet->cusp[v] == cusp) { *base_tet = tet; *base_vertex = v; return; } /* * If pick_base_tet() didn't find any vertex belonging * to the specified cusp, we're in big trouble. */ uFatalError("pick_base_tet", "peripheral_curves"); }
uRuntime::uRuntime() { if (uMainThreadPtr != NULL) uFatalError("There is only room for one Uno Runtime object in this process."); uWeakMutex = Xli::CreateMutex(); #ifdef U_DEBUG_MEM uHeapObjects = new Xli::HashMap<uObject*, bool>(); #endif uMainThreadPtr = Xli::GetCurrentThread(); uThreadDataTls = Xli::CreateTls(uFreeThreadData); uAutoReleasePool pool; uInitSupport(); uInitObjectModel(); }
static void make_isometry_array( IsometryList *isometry_list, Isometry *the_linked_list) { int i; Isometry *an_isometry; if (isometry_list->num_isometries == 0) isometry_list->isometry = NULL; else { isometry_list->isometry = NEW_ARRAY(isometry_list->num_isometries, Isometry *); for ( an_isometry = the_linked_list, i = 0; an_isometry != NULL && i < isometry_list->num_isometries; an_isometry = an_isometry->next, i++) isometry_list->isometry[i] = an_isometry; /* * A quick error check. */ if (an_isometry != NULL || i != isometry_list->num_isometries) uFatalError("make_isometry_array", "isometry"); } }
static Boolean attempt_two_to_three( Triangulation *manifold) { Tetrahedron *tet; FaceIndex f; for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (f = 0; f < 4; f++) if (concave_face(tet, f) == TRUE && would_create_negatively_oriented_tetrahedra(tet, f) == FALSE) { if (two_to_three(tet, f, &manifold->num_tetrahedra) == func_OK) return TRUE; else /* * We should never get to this point. */ uFatalError("attempt_two_to_three", "canonize_part_1.c"); } return FALSE; }
static FuncResult fill_first_cusp( Triangulation **manifold) { Triangulation *new_manifold; int count; Boolean fill_cusp[2] = {TRUE, FALSE}; if (get_num_cusps(*manifold) != 2) uFatalError("fill_first_cusp", "symmetry_group_closed"); new_manifold = fill_cusps(*manifold, fill_cusp, get_triangulation_name(*manifold), FALSE); if (new_manifold == NULL) return func_failed; /* this seems unlikely */ /* * Usually the complete solution will be geometric, even if * the filled solution is not. But occasionally we'll get * a new_manifold which didn't simplify sufficiently, and * we'll need to rattle it around to get a decent triangulation. */ count = MAX_RANDOMIZATIONS; while (--count >= 0 && get_complete_solution_type(new_manifold) != geometric_solution) randomize_triangulation(new_manifold); free_triangulation(*manifold); *manifold = new_manifold; new_manifold = NULL; return func_OK; }
void uWeakStateIntercept::SetCallback(uWeakObject* weak, uWeakStateIntercept::Callback cb) { if (!weak || !cb || weak->ZombieState != uWeakObject::Healthy) uFatalError(XLI_FUNCTION); weak->ZombieState = uWeakObject::Infected; weak->ZombieStateIntercept = cb; }
FuncResult compute_symmetry_group( Triangulation *manifold, SymmetryGroup **symmetry_group_of_manifold, SymmetryGroup **symmetry_group_of_link, Triangulation **symmetric_triangulation, Boolean *is_full_group) { Triangulation *simplified_manifold; FuncResult result; /* * Make sure the variables used to pass back our results * are all initially empty. */ if (*symmetry_group_of_manifold != NULL || *symmetry_group_of_link != NULL || *symmetric_triangulation != NULL) uFatalError("compute_symmetry_group", "symmetry_group"); /* * If the space isn't a manifold, return func_bad_input. */ if (all_Dehn_coefficients_are_relatively_prime_integers(manifold) == FALSE) return func_bad_input; /* * Whether the manifold is cusped or not, we want to begin * by getting rid of "unnecessary" cusps. */ simplified_manifold = fill_reasonable_cusps(manifold); if (simplified_manifold == NULL) return func_failed; /* * Split into cases according to whether the manifold is * closed or cusped (i.e. whether all cusps are filled or not). */ if (all_cusps_are_filled(simplified_manifold) == TRUE) result = compute_closed_symmetry_group( simplified_manifold, symmetry_group_of_manifold, symmetric_triangulation, is_full_group); else { result = compute_cusped_symmetry_group( simplified_manifold, symmetry_group_of_manifold, symmetry_group_of_link); *is_full_group = TRUE; } free_triangulation(simplified_manifold); return result; }
void install_current_curve_bases( Triangulation *manifold) { Cusp *cusp; MatrixInt22 *change_matrices; /* * Allocate an array to store the change of basis matrices. */ change_matrices = NEW_ARRAY(manifold->num_cusps, MatrixInt22); /* * Compute the change of basis matrices. */ for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) { if (cusp->index < 0 || cusp->index >= manifold->num_cusps) uFatalError("install_current_curve_bases", "current_curve_basis"); current_curve_basis_on_cusp(cusp, change_matrices[cusp->index]); } /* * Install the change of basis matrices. */ if (change_peripheral_curves(manifold, change_matrices) != func_OK) uFatalError("install_current_curve_bases", "current_curve_basis"); /* * Free the array used to store the change of basis matrices. */ my_free(change_matrices); }
static Boolean same_homology( Triangulation *manifold0, Triangulation *manifold1) { AbelianGroup *g0, *g1; Boolean groups_are_isomorphic; int i; /* * Compute the homology groups. */ g0 = homology(manifold0); g1 = homology(manifold1); /* * compute_isometries() has already checked that both manifolds * really are manifolds, so neither g0 nor g1 should be NULL. */ if (g0 == NULL || g1 == NULL) uFatalError("same_homology", "isometry"); /* * Put the homology groups into a canonical form. */ compress_abelian_group(g0); compress_abelian_group(g1); /* * Compare the groups. */ if (g0->num_torsion_coefficients != g1->num_torsion_coefficients) groups_are_isomorphic = FALSE; else { groups_are_isomorphic = TRUE; /* innocent until proven guilty */ for (i = 0; i < g0->num_torsion_coefficients; i++) if (g0->torsion_coefficients[i] != g1->torsion_coefficients[i]) groups_are_isomorphic = FALSE; } /* * Free the Abelian groups. */ free_abelian_group(g0); free_abelian_group(g1); return groups_are_isomorphic; }
static void verify_gen_list( MatrixPairList *gen_list, int num_matrix_pairs) { MatrixPair *matrix_pair; /* * Does the list have at least two elements beyond the identity? * Algebraically, we'll need an objective function * and at least one constraint. * Geometrically, the Dirichlet domain which provided these * generators must have at least two pairs of faces. */ if (num_matrix_pairs < 2) uFatalError("verify_gen_list", "Dirichlet_basepoint"); /* * The first MatrixPair on gen_list should be the identity. */ if (gen_list->begin.next->height > 1.0 + IDENTITY_EPSILON) uFatalError("verify_gen_list", "Dirichlet_basepoint"); /* * We want the MatrixPairs to be in order of increasing image height. * (Note that this loop starts at the second MatrixPair on the list.) */ for ( matrix_pair = gen_list->begin.next->next; matrix_pair != &gen_list->end; matrix_pair = matrix_pair->next) if (matrix_pair->height < matrix_pair->prev->height) uFatalError("verify_gen_list", "Dirichlet_basepoint"); }
void error_check_for_create_cusps( Triangulation *manifold) { Tetrahedron *tet; VertexIndex v; if (manifold->num_cusps != 0 || manifold->num_or_cusps != 0 || manifold->num_nonor_cusps != 0 || manifold->cusp_list_begin.next != &manifold->cusp_list_end) uFatalError("error_check_for_create_cusps", "cusps"); for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (v = 0; v < 4; v++) if (tet->cusp[v] != NULL) uFatalError("error_check_for_create_cusps", "cusps"); }
static void attach_extra( Triangulation *manifold) { Tetrahedron *tet; for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) { /* * Make sure no other routine is using the "extra" * field in the Tetrahedron data structure. */ if (tet->extra != NULL) uFatalError("attach_extra", "peripheral_curves"); /* * Attach the locally defined struct extra. */ tet->extra = NEW_ARRAY(4, Extra); } }
static Boolean attempt_three_to_two( Triangulation *manifold) { EdgeClass *edge, *where_to_resume; /* * Note: It's easy to prove that if the three original Tetrahedra * are positively oriented, then the two new Tetrahedra must be * positively oriented as well. So we needn't worry about negatively * oriented Tetrahedra here. */ for (edge = manifold->edge_list_begin.next; edge != &manifold->edge_list_end; edge = edge->next) if (edge->order == 3) if (concave_edge(edge) == TRUE) { if (three_to_two(edge, &where_to_resume, &manifold->num_tetrahedra) == func_OK) return TRUE; else /* * The only reason three_to_two() can fail is that the * three Tetrahedra surrounding the EdgeClass are not * distinct. But by Corolloary 3 of "Convex hulls..." * this cannot happen where the hull is concave. */ uFatalError("attempt_three_to_two", "canonize_part_1"); } return FALSE; }
FuncResult compute_isometries( Triangulation *manifold0, Triangulation *manifold1, Boolean *are_isometric, IsometryList **isometry_list, IsometryList **isometry_list_of_links) { Triangulation *simplified_manifold0, *simplified_manifold1; IsometryList *the_isometry_list, *the_isometry_list_of_links; FuncResult result; /* * Make sure the variables used to pass back our results * are initially empty. */ if ((isometry_list != NULL && *isometry_list != NULL) || (isometry_list_of_links != NULL && *isometry_list_of_links != NULL)) uFatalError("compute_isometries", "isometry"); /* * If one of the spaces isn't a manifold, return func_bad_input. */ if (all_Dehn_coefficients_are_relatively_prime_integers(manifold0) == FALSE || all_Dehn_coefficients_are_relatively_prime_integers(manifold1) == FALSE) return func_bad_input; /* * Check whether the manifolds are obviously nonhomeomorphic. * * (In the interest of a robust, beyond-a-shadow-of-a-doubt algorithm, * stick to discrete invariants like the number of cusps and the * first homology group, and avoid real-valued invariants like * the volume which require judging when two floating point numbers * are equal.) [96/12/6 Comparing canonical triangulations * relies on having at least a vaguely correct hyperbolic structure, * so it should be safe to reject manifolds whose volumes differ * by more than, say, 0.01.] */ if (count_unfilled_cusps(manifold0) != count_unfilled_cusps(manifold1) || same_homology(manifold0, manifold1) == FALSE || ( manifold0->solution_type[filled] == geometric_solution && manifold1->solution_type[filled] == geometric_solution && fabs(volume(manifold0, NULL) - volume(manifold1, NULL)) > CRUDE_VOLUME_EPSILON)) { *are_isometric = FALSE; return func_OK; } /* * Whether the actual manifolds (after taking into account Dehn * fillings) have cusps or not, we want to begin by getting rid * of "unnecessary" cusps. */ simplified_manifold0 = fill_reasonable_cusps(manifold0); if (simplified_manifold0 == NULL) return func_failed; simplified_manifold1 = fill_reasonable_cusps(manifold1); if (simplified_manifold1 == NULL) return func_failed; /* * Split into cases according to whether the manifolds are * closed or cusped (i.e. whether all cusps are filled or not). * The above tests insure that either both are closed or both * are cusped. */ if (all_cusps_are_filled(simplified_manifold0) == TRUE) result = compute_closed_isometry( simplified_manifold0, simplified_manifold1, are_isometric); else { result = compute_cusped_isometries( simplified_manifold0, simplified_manifold1, &the_isometry_list, &the_isometry_list_of_links); if (result == func_OK) { *are_isometric = the_isometry_list->num_isometries > 0; if (isometry_list != NULL) *isometry_list = the_isometry_list; else free_isometry_list(the_isometry_list); if (isometry_list_of_links != NULL) *isometry_list_of_links = the_isometry_list_of_links; else free_isometry_list(the_isometry_list_of_links); } } /* * We no longer need the simplified manifolds. */ free_triangulation(simplified_manifold0); free_triangulation(simplified_manifold1); return result; }
static void linear_programming( ObjectiveFunction objective_function, int num_constraints, Constraint *constraints, Solution solution) { int i, j, k; Constraint *active_constraints[3], *new_constraints[3]; Solution apex, new_apex, max_apex; double apex_height, new_height, max_height; int inactive_constraint_index; /* * Initialize the three active_constraints to be the first three * constraints on the list. (In the present context these are the * step size constraints, but let's write the code so as not to * rely on this knowledge.) Visually, we think of the intersection * of the halfspaces defined by the three active_constraints as * a pyramid, oriented so that the gradient of objective function * points up. */ for (i = 0; i < 3; i++) active_constraints[i] = constraints + i; /* * Initialize the apex to be the vertex defined by the intersection * of the three step size constraints. * * Important note: We assume the maximum value for the objective * function, subject to the active_constraints, occurs at the apex. * (In the present context this is true by virtue of the way the * step size constraints were written.) */ if (solve_three_equations(active_constraints, apex) == func_failed) uFatalError("linear_programming", "Dirichlet_basepoint"); /* * For future reference, set apex_height to the value of the * objective function at the apex. */ apex_height = EVALUATE_EQN(objective_function, apex); /* * Go down the full list of constraints and see whether the apex * satisfies all of them. * * If it does, we've solved the linear programming problem * and we're done. * * If it doesn't, then slice the pyramid defined by the * active_constraints with the constraint which isn't satisfied. * Let the new apex be the highest point on the truncated pyramid, * and the new active_constraints be the three faces of the truncated * pyramid incident to the new apex. Repeat this procedure until * all constraints are satisfied. Note that we have to start from * the beginning of the constraint list each time, since even if the * old apex satisfied a given constraint, the new apex might not. * * If candidate apexes are always at distinct heights, then it's easy * to prove that this algorithm will terminate in a finite number of * steps. But if different candidate apexes sometimes lie at the * same height (as would happen if a constraint function were parallel * to the level sets of the objective function, for example) then we * cannot prove that the algorithm terminates. Indeed, the example * given in the documentation at the end of this function shows how * the algorithm might get into an infinite loop. To avoid this * problem, we add an infinitessimal perturbation to the objective * function. Say we add a term epsilon*dx to the objective function, * where epsilon is a true mathematical infinitessimal, not just a very * small number. Then if two heights are precisely equal as floating * point numbers, the one with the greater dx coordinate will be * considered greater than the one with the smaller dx coordinate. * But what if their dx coordinates are equal, too? And dy and dz? * Our official theoretical definition for the objection function is * * (objective function as computed) + dx*epsilon * + dy*(epsilon^2) * + dz*(epsilon^3) * * In practice, this means that we first compare heights based on the * objective function as computed. If they come out exactly equal, * then we compare based on dx coordinates. If the dx's are equal, * then we compare dy's. If the dy's are equal we compare dz's. If * all those things are equal, then the points coincide, and it makes * sense that their heights should be equal. Since there are only * finite number of possible apexes (one for each triple of constraints), * it follows that if the height is reduced at each step, then the * algorithm must terminate after a finite number of steps. */ for (i = 0; i < num_constraints; i++) if (EVALUATE_EQN(constraints[i], apex) > CONSTRAINT_EPSILON) { /* * Uh-oh. The apex doesn't satisfy constraints[i]. * Slice the pyramid with constraints[i], and see which * new vertex is highest. The new set of active constraints * will include two of the old active constraints, plus * constraints[i]. */ /* * Initialize max_height to -1.0. */ max_height = -1.0; for (j = 0; j < 3; j++) max_apex[j] = 0.0; /* * Replace each active_constraint, in turn, with constraints[i]. * The variable j will be the index of the active_constraint * currently being replaced with constraints[i]. */ for (j = 0; j < 3; j++) { /* * Assemble the candidate set of new_constraints. */ for (k = 0; k < 3; k++) new_constraints[k] = // Cater to a DEC compiler error that chokes on &(array)[i] // (k == j ? &constraints[i] : active_constraints[k]); (k == j ? constraints + i : active_constraints[k]); /* * Find the common intersection of the new_constraints. * * The equations can't possibly be underdetermined, because * if the solution set were 1-dimensional it would have to * include the apex, which is known not to satisfy * constraints[i]. * * The equations might, however, be inconsistent. In * this case, we continue with the loop, as if new_height * were greater than apex_height (cf. below). If the * equations are in principle inconsistent but roundoff * error gives a solution, that's OK too: the solution * will yield a new_height near +infinity or -infinity, * and new_apex will be ignored or fail to be maximal, * respectively. */ if (solve_three_equations(new_constraints, new_apex) == func_failed) continue; /* * Compute the value of the objective function * at the new apex. */ new_height = EVALUATE_EQN(objective_function, new_apex); /* * If new_height is greater than apex_height, then new_apex * is above apex, and is not actually a vertex of the * truncated pyramid. We ignore it and move on. (It's * easy to prove that *some* j will yield a valid maximum * height. When we slice the pyramid with constraints[i] * the resulting solid will somewhere obtain a maximum * height. The old apex is gone, so it can't be there. * And the origin is still present, so it must be higher * than the origin. The infinitessimal correction to the * objective function insures that no planes or lines are * ever truly horizontal, so the maximum must occur at a * vertex, where constraints[i] and two of the old * constraints intersect.) * * If new_height == apex_height, apex_is_higher() applies * the infinitessimal correction to the objective function, * as explained above. */ if (apex_is_higher(new_height, apex_height, new_apex, apex) == TRUE) continue; /* * Is new_height greater than max_height? */ if (apex_is_higher(new_height, max_height, new_apex, max_apex) == TRUE) { inactive_constraint_index = j; max_height = new_height; for (k = 0; k < 3; k++) max_apex[k] = new_apex[k]; } } /* * Swap constraints[i] into the active_constraints array * at index inactive_constraint_index. */ // Cater to a DEC compiler error that chokes on &(array)[i] // active_constraints[inactive_constraint_index] = &constraints[i]; active_constraints[inactive_constraint_index] = constraints + i; /* * Set the apex to max_apex and apex_height to max_height. * * Note that we preserve the condition (cf. above) that the * maximum value of the objective function on the pyramid * occurs at the apex. */ for (j = 0; j < 3; j++) apex[j] = max_apex[j]; apex_height = max_height; /* * We've fixed up the active_constraints and the apex, * so now recheck the other constraints. Set i = -1, * so that after the i++ in the for(;;) statement it will * be back to i = 0. */ i = -1; } /* * Hooray. All the constraints are satisfied. * Set the solution equal to the apex and we're done. */ for (i = 0; i < 3; i++) solution[i] = apex[i]; return; /* * Here's an example in which an unperturbed objective function * may lead to an infinite loop. * * Make a sketch (in (dx, dy, dz) space) showing the following points: * * s0 = (2, 0, 0) * s1 = (-1, sqrt(3), 0) [twice a primitive cube root of unity] * s2 = (-1, -sqrt(3), 0) * * t0 = (1, 0, 1) * t1 = (-1, sqrt(3)/2, 1) * t2 = (-1, -sqrt(3)/2, 1) * * u = (0, 0, 2) * * The objective function is 0*dx + 0*dy + 1*dz + constant. * * The constraints are defined by the following planes. (I'll give * a spanning set for each plane. The constraint itself will be an * equation saying that (dx, dy, dz) must lie on the same side of the * plane as the origin (0, 0, 0) (or on the plane itself is OK too).) * Sketch each of these planes in your picture. * * a0 = {s1, s2, u} * a1 = {s2, s0, u} * a2 = {s0, s1, u} * * b = {t0, t1, t2} * * c0 = {s0, t1, t2} * c1 = {t0, s1, t2} * c2 = {t0, t1, s2} * * Now look what happens in the naive linear programming algorithm. * Say we start with constraints a0, a1 and a2, so the apex is at * point u. Then we consider constraint b. Constraint b will * replace one of {a0, a1, a2}; w.l.o.g. say it's a2. So we're * left with constraints {a0, a1, b} and the apex is at t2. The point * t2 satisfies all the constraints except c2, so eventually the * algorithm will swap c2 for either a0 or a1 (w.l.o.g. say its a1) * and we're left with equations {a0, c2, b}, and the apex moves to * t1. The point t1 satisfies all the constraints except c1, so * c1 gets swapped for either a0 or c2, the constraint set becomes * either {c1, c2, b} or {a0, c1, b}, and the apex moves to either * t0 or t2. This is the critical juncture for the algorithm. If * it swapped c1 for a0, then on the next iteration of the algorithm * it swaps c0 for b, and the constraint set {c1, c2, c0} gives us * the true solution. But if it swapped c1 for c2, then we run the * risk of getting into an infinite loop. But with the perturbed * objective function this will never happen, because we'll never * visit the same vertex twice. */ }
static void compute_singular_action( Triangulation *manifold, Isometry *isometry) { Boolean lower_index_is_at_top; EdgeIndex index, image_index; VertexIndex image_v1,image_v2,v1,v2; Tetrahedron *tet, *image_tet; EdgeClass *edge, *image_edge; PositionedTet ptet, ptet0; for( edge = manifold->edge_list_begin.next; edge!=&manifold->edge_list_end; edge = edge->next ) if (edge->is_singular) { if (edge->singular_index<0) uFatalError("compute_singular_action","isometry_cusped"); tet = edge->incident_tet; index = edge->incident_edge_index; v1 = MIN(one_vertex_at_edge[index], other_vertex_at_edge[index]); v2 = MAX(one_vertex_at_edge[index], other_vertex_at_edge[index]); image_tet = tet->image; image_v1 = EVALUATE(tet->map,v1); image_v2 = EVALUATE(tet->map,v2); image_index = edge_between_vertices[image_v1][image_v2]; image_edge = image_tet->edge_class[image_index]; if (image_edge->singular_index<0 || image_edge->singular_order != edge->singular_order ) uFatalError("compute_singular_action","isometry_cusped"); /* i have never kept track of a direction only the singular edges. prehaps this is something i should be doing... * for now, here is how we'll kept track of orientation of these maps from singular edge to singular edge: * each edge has an incident tet and an incident edge index, define an ordering on the ends of the singular * edge by the ordering of the vertex indices of this edge. * * there may be some clever way of doing this with the handedness of the edge classes. i am not sure. */ set_left_edge( image_edge, &ptet0 ); ptet = ptet0; lower_index_is_at_top = ( ptet.bottom_face < ptet.right_face ); isometry->singular_image[edge->singular_index] = 0; do{ if (ptet.tet == image_tet && edge_between_faces[ptet.near_face][ptet.left_face] == image_index) { if (lower_index_is_at_top) { if (image_v1 == ptet.bottom_face) isometry->singular_image[edge->singular_index] = image_edge->singular_index + 1; else isometry->singular_image[edge->singular_index] = -(image_edge->singular_index + 1); } else { if (image_v1 == ptet.bottom_face) isometry->singular_image[edge->singular_index] = -(image_edge->singular_index + 1); else isometry->singular_image[edge->singular_index] = image_edge->singular_index + 1; } break; } veer_left( &ptet ); }while(!same_positioned_tet( &ptet0, &ptet )); if (isometry->singular_image[edge->singular_index] == 0) uFatalError("compute_singular_action","isometry_cusped"); } }
static FuncResult attempt_isometry( Triangulation *manifold0, Tetrahedron *initial_tet0, Tetrahedron *initial_tet1, Permutation initial_map, int *singular_map ) { Tetrahedron *tet0, *tet1, *nbr0, *nbr1, **queue; EdgeClass *edge0, *edge1; int first, last, i, j; FaceIndex face0, face1; Permutation gluing0, gluing1, nbr0_map; /* * initial_tet1 and initial_map are arbitrary, so * the vast majority of calls to attempt_isometry() * will fail. Therefore it's worth including a quick * plausibility check at the beginning, to make the * algorithm run faster. */ if (is_isometry_plausible(initial_tet0, initial_tet1, initial_map) == FALSE) return func_failed; /* * Initialize all the image fields of manifold0 * to NULL to show they haven't been set. */ for ( tet0 = manifold0->tet_list_begin.next; tet0 != &manifold0->tet_list_end; tet0 = tet0->next) tet0->image = NULL; /* * Allocate space for a queue which is large enough * to hold pointers to all the Tetrahedra in manifold0. */ queue = NEW_ARRAY(manifold0->num_tetrahedra, Tetrahedron *); /* * At all times, the Tetrahedra on the queue will be those which * * (1) have set their image and map fields, but * * (2) have not checked their neighbors. */ /* * Set the image and map fields for initial_tet0. */ initial_tet0->image = initial_tet1; initial_tet0->map = initial_map; /* * Put initial_tet0 on the queue. */ first = 0; last = 0; queue[first] = initial_tet0; /* * While there are Tetrahedra on the queue . . . */ while (last >= first) { /* * Pull the first Tetrahedron off the queue and call it tet0. */ tet0 = queue[first++]; /* * tet0 maps to some Tetrahedron tet1 in manifold1. */ tet1 = tet0->image; /* we will keep track on how the singular edges in manifold0 map into manifold1 */ for(i=0;i<4;i++) for(j=i+1;j<4;j++) { edge0 = tet0->edge_class[edge_between_vertices[i][j]]; edge1 = tet1->edge_class[edge_between_vertices[EVALUATE(tet0->map, i)] [EVALUATE(tet0->map, j)]]; if (edge0->order != edge1->order ) { my_free(queue); return func_failed; } if (edge0->is_singular != edge1->is_singular ) { my_free(queue); return func_failed; } if (edge0->is_singular && edge0->singular_order != edge1->singular_order ) { my_free(queue); return func_failed; } if (singular_map != NULL && edge0->is_singular ) singular_map[edge0->singular_index] = edge1->singular_index; } /* * For each face of tet0 . . . */ for (face0 = 0; face0 < 4; face0++) { /* * Let nbr0 be the Tetrahedron which meets tet0 at face0. */ nbr0 = tet0->neighbor[face0]; /* * tet0->map takes face0 of tet0 to face1 of tet1. */ face1 = EVALUATE(tet0->map, face0); /* * Let nbr1 be the Tetrahedron which meets tet1 at face1. */ nbr1 = tet1->neighbor[face1]; /* * Let gluing0 be the gluing which identifies face0 of * tet0 to nbr0, and similarly for gluing1. */ gluing0 = tet0->gluing[face0]; gluing1 = tet1->gluing[face1]; /* * gluing0 * tet0 ------> nbr0 * | | * tet0->map | | nbr0->map * | | * V gluing1 V * tet1 ------> nbr1 * * We want to ensure that tet1 and nbr1 enjoy the same * relationship to each other in manifold1 that tet0 and * nbr0 do in manifold0. The conditions * * nbr0->image == nbr1 * and * nbr0->map == gluing1 o tet0->map o gluing0^-1 * * are necessary and sufficient to insure that we have a * combinatorial equivalence between the Triangulations. * (The proof relies on the fact that we've already checked * (near the beginning of compute_cusped_isometries() above) * that the Triangulations have the same number of Tetrahedra; * otherwise one Triangulation could be a (possibly branched) * covering of the other.) */ /* * Compute the required value for nbr0->map. */ nbr0_map = compose_permutations( compose_permutations( gluing1, tet0->map ), inverse_permutation[gluing0] ); /* * If nbr0->image and nbr0->map have already been set, * check that they satisfy the above conditions. */ if (nbr0->image != NULL) { if (nbr0->image != nbr1 || nbr0->map != nbr0_map) { /* * This isn't an isometry. */ my_free(queue); return func_failed; } } /* * else . . . * nbr0->image and nbr0->map haven't been set. * Set them, and put nbr0 on the queue. */ else { if (!is_isometry_plausible(nbr0,nbr1,nbr0_map)) { my_free(queue); return func_failed; } nbr0->image = nbr1; nbr0->map = nbr0_map; queue[++last] = nbr0; } } } /* * A quick error check. * Is it plausible that each Tetrahedron * has been on the queue exactly once? */ if (first != manifold0->num_tetrahedra || last != manifold0->num_tetrahedra - 1) uFatalError("attempt_isometry", "isometry"); /* * Free the queue, and report success. */ my_free(queue); return func_OK; }
static Triangulation *try_Dirichlet_to_triangulation( WEPolyhedron *polyhedron) { /* * Implement Plan A as described above. */ Triangulation *triangulation; WEEdge *edge, *nbr_edge, *mate_edge; WEEdgeEnd end; WEEdgeSide side; Tetrahedron *new_tet; FaceIndex f; /* * Don't attempt to triangulate an orbifold. */ if (singular_set_is_empty(polyhedron) == FALSE) return NULL; /* * Set up the Triangulation. */ triangulation = NEW_STRUCT(Triangulation); initialize_triangulation(triangulation); /* * Allocate and copy the name. */ triangulation->name = NEW_ARRAY(strlen(DEFAULT_NAME) + 1, char); strcpy(triangulation->name, DEFAULT_NAME); /* * Allocate the Tetrahedra. */ triangulation->num_tetrahedra = 4 * polyhedron->num_edges; for (edge = polyhedron->edge_list_begin.next; edge != &polyhedron->edge_list_end; edge = edge->next) for (end = 0; end < 2; end++) /* = tail, tip */ for (side = 0; side < 2; side++) /* = left, right */ { new_tet = NEW_STRUCT(Tetrahedron); initialize_tetrahedron(new_tet); INSERT_BEFORE(new_tet, &triangulation->tet_list_end); edge->tet[end][side] = new_tet; } /* * Initialize neighbors. */ for (edge = polyhedron->edge_list_begin.next; edge != &polyhedron->edge_list_end; edge = edge->next) for (end = 0; end < 2; end++) /* = tail, tip */ for (side = 0; side < 2; side++) /* = left, right */ { /* * Neighbor[0] is associated to this same WEEdge. * It lies on the same side (left or right), but * at the opposite end (tail or tip). */ edge->tet[end][side]->neighbor[0] = edge->tet[!end][side]; /* * Neighbor[1] lies on the same face of the Dirichlet * domain, but at the "next side" of that face. */ nbr_edge = edge->e[end][side]; if (nbr_edge->v[!end] == edge->v[end]) /* edge and nbr_edge point in the same direction */ edge->tet[end][side]->neighbor[1] = nbr_edge->tet[!end][side]; else if (nbr_edge->v[end] == edge->v[end]) /* edge and nbr_edge point in opposite directions */ edge->tet[end][side]->neighbor[1] = nbr_edge->tet[end][!side]; else uFatalError("Dirichlet_to_triangulation", "Dirichlet_conversion"); /* * Neighbor[2] is associated to this same WEEdge. * It lies at the same end (tail or tip), but * on the opposite side (left or right). */ edge->tet[end][side]->neighbor[2] = edge->tet[end][!side]; /* * Neighbor[3] lies on this face's "mate" elsewhere * on the Dirichlet domain. */ mate_edge = edge->neighbor[side]; edge->tet[end][side]->neighbor[3] = mate_edge->tet [edge->preserves_direction[side] ? end : !end ] [edge->preserves_sides[side] ? side : !side]; } /* * Initialize all gluings to the identity. */ for (edge = polyhedron->edge_list_begin.next; edge != &polyhedron->edge_list_end; edge = edge->next) for (end = 0; end < 2; end++) /* = tail, tip */ for (side = 0; side < 2; side++) /* = left, right */ for (f = 0; f < 4; f++) edge->tet[end][side]->gluing[f] = IDENTITY_PERMUTATION; /* * Set up the EdgeClasses. */ create_edge_classes(triangulation); orient_edge_classes(triangulation); /* * Attempt to orient the manifold. */ orient(triangulation); /* * Set up the Cusps, including "fake cusps" for the finite vertices. * Then locate and remove the fake cusps. If the manifold is closed, * drill out an arbitrary curve to express it as a Dehn filling. * Finally, determine the topology of each cusp (torus or Klein bottle) * and count them. */ create_cusps(triangulation); mark_fake_cusps(triangulation); peripheral_curves(triangulation); remove_finite_vertices(triangulation); count_cusps(triangulation); /* * Try to compute a hyperbolic structure, first for the unfilled * manifold, and then for the closed manifold if appropriate. */ find_complete_hyperbolic_structure(triangulation); do_Dehn_filling(triangulation); /* * If the manifold is hyperbolic, install a shortest basis on each cusp. */ if ( triangulation->solution_type[complete] == geometric_solution || triangulation->solution_type[complete] == nongeometric_solution) install_shortest_bases(triangulation); /* * All done! */ return triangulation; }
static void uDumpObjectAndStrongRefs(FILE *fp, uObject *obj) { uType *type = obj->GetType(); uDumpObject(fp, obj, type->TypeName); switch (type->TypeType) { case uTypeTypeClass: do { uDumpStrongRefs(fp, obj, obj, type); type = type->BaseType; } while (type); break; case uTypeTypeEnum: break; case uTypeTypeStruct: { uByte* valueAddr = (uByte*)obj + sizeof(uObject); uDumpStrongRefs(fp, obj, valueAddr, type); break; } case uTypeTypeDelegate: { uDelegate *delegate = (uDelegate*)obj; uDumpStrongRef(fp, obj, delegate->_obj); uDumpStrongRef(fp, obj, delegate->_prev); break; } case uTypeTypeArray: { uArray *array = (uArray *)obj; uArrayType *arrayType = (uArrayType *)type; uType *elmType = arrayType->ElementType; switch (elmType->TypeType) { case uTypeTypeClass: case uTypeTypeInterface: case uTypeTypeDelegate: case uTypeTypeArray: { for (int i = 0; i < array->_len; ++i) { uObject *target = ((uObject **)array->_ptr)[i]; uDumpStrongRef(fp, obj, target); } } break; case uTypeTypeEnum: break; case uTypeTypeStruct: { for (int i = 0; i < array->_len; ++i) { uByte *valueAddr = (uByte *)array->_ptr + i * elmType->ValueSize; uDumpStrongRefs(fp, obj, valueAddr, elmType); } } break; default: uFatalError(XLI_FUNCTION); } } break; default: uFatalError(XLI_FUNCTION); } }
static PositionedTet find_start( Triangulation *manifold, Cusp *cusp) { Tetrahedron *tet; VertexIndex vertex; Orientation orientation; FaceIndex side; PositionedTet ptet; for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (vertex = 0; vertex < 4; vertex++) { if (tet->cusp[vertex] != cusp) continue; for (orientation = right_handed; orientation <= left_handed; orientation++) for (side = 0; side < 4; side++) if (side != vertex && tet->curve[M][orientation][vertex][side] != 0 && tet->curve[L][orientation][vertex][side] != 0) { /* * Record the current position of the Tetrahedron in * a PositionedTet structure . . . */ ptet.tet = tet; ptet.bottom_face = vertex; ptet.near_face = side; if (orientation == right_handed) { ptet.left_face = remaining_face[ptet.bottom_face][ptet.near_face]; ptet.right_face = remaining_face[ptet.near_face][ptet.bottom_face]; } else { ptet.left_face = remaining_face[ptet.near_face][ptet.bottom_face]; ptet.right_face = remaining_face[ptet.bottom_face][ptet.near_face]; } ptet.orientation = orientation; /* * . . . and return it. */ return ptet; } } /* * The program should never get to this point. */ uFatalError("find_start", "cusp_shapes"); /* * The compiler would like a return value, even though * we never return from the uFatalError() call. * The Metrowerks compiler would, in addition, like * the data to be initialized before use. */ ptet.tet = NULL; ptet.near_face = 0; ptet.left_face = 0; ptet.right_face = 0; ptet.bottom_face = 0; ptet.orientation = unknown_orientation; return ptet; }
void uReleaseObject(uObject* obj) { if (obj) { if (Xli::AtomicDecrement(&obj->__obj_retains) == 0) { if (!uTryClearWeakObject(obj)) return; #ifdef U_DEBUG_MEM uThreadData* thread = uGetThreadData(); if (thread->AutoReleaseStack.Length() > 0 && thread->AutoReleaseStack.Last().AllocCount > 0) { thread->AutoReleaseStack.Last().FreeCount++; thread->AutoReleaseStack.Last().FreeSize += obj->__obj_alloc_size; } #endif uType* type = obj->__obj_type; switch (type->TypeType) { case uTypeTypeClass: do { if (type->__fp_Finalize) { try { (*type->__fp_Finalize)(obj); } catch (...) { Xli::Error->WriteFormat("Runtime Error: Unhandled exception in finalizer for '%s'\n", type->TypeName); } } uReleaseValue(type, obj); type = type->BaseType; } while (type); break; case uTypeTypeEnum: break; case uTypeTypeStruct: // Note: This must be a boxed value, so append size of object header uReleaseValue(type, (uByte*)obj + sizeof(uObject)); break; case uTypeTypeDelegate: uReleaseObject(((uDelegate*)obj)->_obj); uReleaseObject(((uDelegate*)obj)->_prev); break; case uTypeTypeArray: { uArray* array = (uArray*)obj; uArrayType* arrayType = (uArrayType*)type; uType* elmType = arrayType->ElementType; switch (elmType->TypeType) { case uTypeTypeClass: case uTypeTypeInterface: case uTypeTypeDelegate: case uTypeTypeArray: for (uObject** objAddr = (uObject**)array->_ptr; array->_len--; objAddr++) uReleaseObject(*objAddr); break; case uTypeTypeEnum: break; case uTypeTypeStruct: for (uByte* valueAddr = (uByte*)array->_ptr; array->_len--; valueAddr += elmType->ValueSize) uReleaseValue(elmType, valueAddr); break; default: uFatalError(XLI_FUNCTION); } } break; default: uFatalError(XLI_FUNCTION); } #if U_DEBUG_MEM >= 2 Xli::Error->WriteFormat("Freeing '%s' (%d bytes)\n", obj->__obj_type->TypeName, obj->__obj_alloc_size); #endif #ifdef U_DEBUG_MEM uEnterCritical(); uHeapObjects->Remove(obj); uExitCritical(); #endif U_FREE_OBJECT(obj); } else if ((*(uUInt*)&obj->__obj_retains) & 0xF0000000) { // Object must be corrupt if one of the four first bits are set uFatalError(XLI_FUNCTION); } else { #if U_DEBUG_MEM >= 3 Xli::Error->WriteFormat("Released '%s' (%d bytes) (%d retains)\n", obj->__obj_type->TypeName, obj->__obj_alloc_size, obj->__obj_retains); #endif } } }
void fix_peripheral_orientations( Triangulation *manifold) { Tetrahedron *tet; VertexIndex v; FaceIndex f; Cusp *cusp; /* * This function should get called only for orientable manifolds. */ if (manifold->orientability != oriented_manifold && manifold->orientability != oriented_orbifold) uFatalError("fix_peripheral_orientations", "orient"); /* * Compute the intersection number of the meridian and longitude. */ copy_curves_to_scratch(manifold, 0, FALSE); copy_curves_to_scratch(manifold, 1, FALSE); compute_intersection_numbers(manifold); /* * Reverse the meridian on cusps with intersection_number[L][M] == -1. */ /* which Tetrahedron */ for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) /* which ideal vertex */ for (v = 0; v < 4; v++) if (tet->cusp[v]->intersection_number[L][M] == -1) /* which side of the vertex */ for (f = 0; f < 4; f++) if (v != f) { tet->curve[M][right_handed][v][f] = - tet->curve[M][right_handed][v][f]; if (tet->curve[M][left_handed][v][f] != 0.0 || tet->curve[L][left_handed][v][f] != 0.0) uFatalError("fix_peripheral_orientations", "orient"); } /* * When we reverse the meridian we must also negate the meridional * Dehn filling coefficient in order to maintain the same (oriented) * Dehn filling curve as before. However, this Dehn filling curve * will wind clockwise around the core geodesics, relative to * the global orientation on the manifold (because the global * orientation disagrees with the local orientation we had been using * on the nonorientable manifold's torus cusp). This forces a whole * new solution to be found to the gluing equations. To avoid this, * we reverse the direction of the Dehn filling curve (i.e. we * negate both the m and l coefficients). The net effect is that * we negate the l coefficient. * * This reversal of the Dehn filling curve is not really * necessary, and could be eliminated if it's ever causes problems. */ for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) if (cusp->intersection_number[L][M] == -1) cusp->l = - cusp->l; }
void extend_orientation( Triangulation *manifold, Tetrahedron *initial_tet) { Tetrahedron **queue, *tet; int queue_first, queue_last; FaceIndex f; /* * Set all the tet->flag fields to FALSE, * to show that no Tetrahedra have been visited. */ for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) tet->flag = FALSE; /* * Tentatively assume the manifold is orientable. */ manifold->orientability = oriented_manifold; /* * Allocate space for a queue of pointers to the Tetrahedra. * Each Tetrahedron will appear on the queue exactly once, * so an array of length manifold->num_tetrahedra will be just right. */ queue = NEW_ARRAY(manifold->num_tetrahedra, Tetrahedron *); /* * Put the initial Tetrahedron on the queue, * and mark it as visited. */ queue_first = 0; queue_last = 0; queue[0] = initial_tet; queue[0]->flag = TRUE; /* * Start processing the queue. */ do { /* * Pull a Tetrahedron off the front of the queue. */ tet = queue[queue_first++]; /* * Look at the four neighboring Tetrahedra. */ for (f = 0; f < 4; f++) { /* * If the neighbor hasn't been visited... */ if (tet->neighbor[f]->flag == FALSE) { /* * ...reverse its orientation if necessary... */ if (parity[tet->gluing[f]] == orientation_reversing) reverse_orientation(tet->neighbor[f]); /* * ...mark it as visited... */ tet->neighbor[f]->flag = TRUE; /* * ...and put it on the back of the queue. */ queue[++queue_last] = tet->neighbor[f]; } /* * If the neighbor has been visited . . . */ else { /* * ...check whether its orientation is consistent. */ if (parity[tet->gluing[f]] == orientation_reversing) manifold->orientability = nonorientable_manifold; } } } /* * Keep going until either we discover the manifold is nonorientable, * or the queue is exhausted. */ while (manifold->orientability == oriented_manifold && queue_first <= queue_last); /* * Free the memory used for the queue. */ my_free(queue); /* * An "unnecessary" (but quick) error check. */ if (manifold->orientability == oriented_manifold && ( queue_first != manifold->num_tetrahedra || queue_last != manifold->num_tetrahedra - 1)) uFatalError("orient", "orient"); /* * Another error check. * We should have oriented a manifold before attempting to * compute the Chern-Simons invariant. */ /* if (manifold->CS_value_is_known || manifold->CS_fudge_is_known) uFatalError("orient", "orient"); */ /* * Respect the conventions for peripheral curves and * edge orientations in oriented manifolds. */ if (manifold->orientability == oriented_manifold) { transfer_peripheral_curves(manifold); make_all_edge_orientations_right_handed(manifold); } }
int main(int argc, char *argv[]) { Widget toplevel; XtAppContext app_con; Widget panel; Widget base[XkbNumModifiers]; Widget latched[XkbNumModifiers]; Widget locked[XkbNumModifiers]; Widget effective[XkbNumModifiers]; Widget compat[XkbNumModifiers]; Widget baseBox, latchBox, lockBox, effBox, compatBox; register int i; unsigned bit; XkbEvent ev; XkbStateRec state; static Arg hArgs[] = { {XtNorientation, (XtArgVal) XtorientHorizontal} }; static Arg vArgs[] = { {XtNorientation, (XtArgVal) XtorientVertical} }; static Arg onArgs[] = { {XtNon, (XtArgVal) True} }; static Arg offArgs[] = { {XtNon, (XtArgVal) False} }; static char *fallback_resources[] = { "*Box*background: grey50", "*Box*borderWidth: 0", "*Box*vSpace: 1", NULL }; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-version") == 0) { printf("xkbwatch (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); exit(0); } } uSetErrorFile(NullString); toplevel = XtOpenApplication(&app_con, "XkbWatch", options, XtNumber(options), &argc, argv, fallback_resources, sessionShellWidgetClass, NULL, ZERO); if (toplevel == NULL) { uFatalError("Couldn't create application top level\n"); exit(1); } inDpy = outDpy = XtDisplay(toplevel); if (inDpy) { int i1, mn, mj; mj = XkbMajorVersion; mn = XkbMinorVersion; if (!XkbQueryExtension(inDpy, &i1, &evBase, &errBase, &mj, &mn)) { uFatalError("Server doesn't support a compatible XKB\n"); exit(1); } } panel = XtCreateManagedWidget("xkbwatch", boxWidgetClass, toplevel, vArgs, 1); if (panel == NULL) { uFatalError("Couldn't create top level box\n"); exit(1); } baseBox = XtCreateManagedWidget("base", boxWidgetClass, panel, hArgs, 1); if (baseBox == NULL) uFatalError("Couldn't create base modifiers box\n"); latchBox = XtCreateManagedWidget("latched", boxWidgetClass, panel, hArgs, 1); if (latchBox == NULL) uFatalError("Couldn't create latched modifiers box\n"); lockBox = XtCreateManagedWidget("locked", boxWidgetClass, panel, hArgs, 1); if (lockBox == NULL) uFatalError("Couldn't create locked modifiers box\n"); effBox = XtCreateManagedWidget("effective", boxWidgetClass, panel, hArgs, 1); if (effBox == NULL) uFatalError("Couldn't create effective modifiers box\n"); compatBox = XtCreateManagedWidget("compat", boxWidgetClass, panel, hArgs, 1); if (compatBox == NULL) uFatalError("Couldn't create compatibility state box\n"); XkbSelectEvents(inDpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask); XkbGetState(inDpy, XkbUseCoreKbd, &state); for (i = XkbNumModifiers - 1, bit = 0x80; i >= 0; i--, bit >>= 1) { ArgList list; char buf[30]; sprintf(buf, "base%d", i); if (state.base_mods & bit) list = onArgs; else list = offArgs; base[i] = XtCreateManagedWidget(buf, ledWidgetClass, baseBox, list, 1); sprintf(buf, "latched%d", i); if (state.latched_mods & bit) list = onArgs; else list = offArgs; latched[i] = XtCreateManagedWidget(buf, ledWidgetClass, latchBox, list, 1); sprintf(buf, "locked%d", i); if (state.locked_mods & bit) list = onArgs; else list = offArgs; locked[i] = XtCreateManagedWidget(buf, ledWidgetClass, lockBox, list, 1); sprintf(buf, "effective%d", i); if (state.mods & bit) list = onArgs; else list = offArgs; effective[i] = XtCreateManagedWidget(buf, ledWidgetClass, effBox, list, 1); sprintf(buf, "compat%d", i); if (state.compat_state & bit) list = onArgs; else list = offArgs; compat[i] = XtCreateManagedWidget(buf, ledWidgetClass, compatBox, list, 1); } XtRealizeWidget(toplevel); while (1) { XtAppNextEvent(app_con, &ev.core); if (ev.core.type == evBase + XkbEventCode) { if (ev.any.xkb_type == XkbStateNotify) { unsigned changed; if (ev.state.changed & XkbModifierBaseMask) { changed = ev.state.base_mods ^ state.base_mods; state.base_mods = ev.state.base_mods; for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) { if (changed & bit) { ArgList list; if (state.base_mods & bit) list = onArgs; else list = offArgs; XtSetValues(base[i], list, 1); } } } if (ev.state.changed & XkbModifierLatchMask) { changed = ev.state.latched_mods ^ state.latched_mods; state.latched_mods = ev.state.latched_mods; for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) { if (changed & bit) { ArgList list; if (state.latched_mods & bit) list = onArgs; else list = offArgs; XtSetValues(latched[i], list, 1); } } } if (ev.state.changed & XkbModifierLockMask) { changed = ev.state.locked_mods ^ state.locked_mods; state.locked_mods = ev.state.locked_mods; for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) { if (changed & bit) { ArgList list; if (state.locked_mods & bit) list = onArgs; else list = offArgs; XtSetValues(locked[i], list, 1); } } } if (ev.state.changed & XkbModifierStateMask) { changed = ev.state.mods ^ state.mods; state.mods = ev.state.mods; for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) { if (changed & bit) { ArgList list; if (state.mods & bit) list = onArgs; else list = offArgs; XtSetValues(effective[i], list, 1); } } } if (ev.state.changed & XkbCompatStateMask) { changed = ev.state.compat_state ^ state.compat_state; state.compat_state = ev.state.compat_state; for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) { if (changed & bit) { ArgList list; if (state.compat_state & bit) list = onArgs; else list = offArgs; XtSetValues(compat[i], list, 1); } } } } } else XtDispatchEvent(&ev.core); } /* BAIL: */ if (inDpy) XCloseDisplay(inDpy); if (outDpy != inDpy) XCloseDisplay(outDpy); inDpy = outDpy = NULL; return 0; }
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 compute_cusp_Euler_characteristics( Triangulation *manifold) { Cusp *cusp; EdgeClass *edge; Tetrahedron *tet; VertexIndex v, v0, v1; /* * Initialize all Euler characteristics to zero. */ for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) cusp->euler_characteristic = 0; /* * It'll be easier to count the edges twice (once from each side) * so compute twice the Euler characteristic and divide by two * at the end. */ /* * Count the vertices in the triangulation of the boundary, * which come from edges in the manifold itself. */ for (edge = manifold->edge_list_begin.next; edge != &manifold->edge_list_end; edge = edge->next) { tet = edge->incident_tet; v0 = one_vertex_at_edge[edge->incident_edge_index]; v1 = other_vertex_at_edge[edge->incident_edge_index]; tet->cusp[v0]->euler_characteristic += 2; tet->cusp[v1]->euler_characteristic += 2; } /* * Count the edges in the triangulation of the boundary, * which come from faces in the manifold itself. */ for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (v = 0; v < 4; v++) tet->cusp[v]->euler_characteristic -= 3; /* * Count the faces in the triangulation of the boundary, * which come from tetrahedra in the manifold itself. */ for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (v = 0; v < 4; v++) tet->cusp[v]->euler_characteristic += 2; /* * Divide by two (cf. above). */ for (cusp = manifold->cusp_list_begin.next; cusp != &manifold->cusp_list_end; cusp = cusp->next) { if (cusp->euler_characteristic % 2 != 0) uFatalError("compute_cusp_Euler_characteristics", "cusps"); cusp->euler_characteristic /= 2; } }