void complex_gamma (complex_t *dst, complex_t const *src) { if (complex_real_p (src)) { complex_init (dst, gnm_gamma (src->re), 0); } else if (src->re < 0) { /* Gamma(z) = pi / (sin(pi*z) * Gamma(-z+1)) */ complex_t a, b, mz; complex_init (&mz, -src->re, -src->im); complex_fact (&a, &mz); complex_init (&b, M_PIgnum * gnm_fmod (src->re, 2), M_PIgnum * src->im); /* Hmm... sin overflows when b.im is large. */ complex_sin (&b, &b); complex_mul (&a, &a, &b); complex_init (&b, M_PIgnum, 0); complex_div (dst, &b, &a); } else { complex_t zmh, zmhd2, zmhpg, f, f2, p, q, pq; int i; i = G_N_ELEMENTS(lanczos_num) - 1; complex_init (&p, lanczos_num[i], 0); complex_init (&q, lanczos_denom[i], 0); while (--i >= 0) { complex_mul (&p, &p, src); p.re += lanczos_num[i]; complex_mul (&q, &q, src); q.re += lanczos_denom[i]; } complex_div (&pq, &p, &q); complex_init (&zmh, src->re - 0.5, src->im); complex_init (&zmhpg, zmh.re + lanczos_g, zmh.im); complex_init (&zmhd2, zmh.re * 0.5, zmh.im * 0.5); complex_pow (&f, &zmhpg, &zmhd2); zmh.re = -zmh.re; zmh.im = -zmh.im; complex_exp (&f2, &zmh); complex_mul (&f2, &f, &f2); complex_mul (&f2, &f2, &f); complex_mul (dst, &f2, &pq); } }
complex_float complex_cot(complex_float c1){ // this is 1/tan = 1/(sin/cos) = cos/sin complex_float cpx_sin = complex_sin(c1); complex_float cpx_cos = complex_cos(c1); complex_float r = complex_div(cpx_cos,cpx_sin); return r; }
complex_float complex_log(complex_float c1, complex_float c2){ complex_float a, b, r; a = complex_ln(c1); b = complex_ln(c2); r = complex_div(b,a); return r; }
complex_float complex_cos(complex_float c1){ complex_float exp1 = complex_pow( complex_make(exp(1)), complex_i(c1) ); complex_float exp2 = complex_pow( complex_make(exp(1)), complex_mul(complex_make(-1.0f),complex_i(c1)) ); complex_float sum = complex_add(exp1,exp2); complex_float r = complex_div( sum, complex_make(2.0f) ); return r; }
complex_float complex_hyptan(complex_float c1){ // I'm assuming sinh/cosh complex_float cpx_sinh = complex_hypsin(c1); complex_float cpx_cosh = complex_hypcos(c1); complex_float r = complex_div(cpx_sinh,cpx_cosh); return r; }
complex_float complex_sin(complex_float c1){ // So... Euler said: exp(i*t) = cos(t) + i*sin(t) // and then: sin(t) = (exp(i*t) - exp(-i*t)) / 2i // and also: cos(t) = (exp(i*t) + exp(-i*t)) / 2 // Hm... I already have functions that raise complex numbers // to complex numbers so I'll use those for sin/code. complex_float exp1 = complex_pow( complex_make(exp(1)), complex_i(c1) ); complex_float exp2 = complex_pow( complex_make(exp(1)), complex_mul(complex_make(-1.0f),complex_i(c1)) ); complex_float diff = complex_sub(exp1,exp2); complex_float r = complex_div( diff, complex_i(complex_make(2.0f)) ); return r; }
static void compute_cwl( ComplexWithLog cwl[3], EdgeIndex e) { /* * Compute cwl[(e+1)%3] and cwl[(e+2)%3] in terms of cwl[e]. */ int i; for (i = 1; i < 3; i++) { cwl[(e+i)%3].rect = complex_div(One, complex_minus(One, cwl[(e+i-1)%3].rect)); cwl[(e+i)%3].log = complex_log(cwl[(e+i)%3].rect, PI_OVER_2); } }
/* Based on http://en.wikipedia.org/wiki/Quartic_function#Quick_and_memorable_solution_from_first_principles */ static int solve_depressed_quartic(const complex_t* poly, complex_t* results) { complex_t helper_cubic[4]; complex_t helper_results[3]; complex_t quadratic_factor[3]; complex_t p, c_plus_p_sqr, d_div_p; const complex_t e = poly[0]; const complex_t d = poly[1]; const complex_t c = poly[2]; int num_results; if (complex_eq(d, complex_from_real(0.0))) { int i, num_quad_results; complex_t quadratic[3]; complex_t quadratic_results[2]; quadratic[0] = e; quadratic[1] = c; quadratic[2] = complex_from_real(1.0); num_quad_results = solve_poly(2, quadratic, quadratic_results); for (i = 0; i < num_quad_results; ++i) { const complex_t s = complex_sqrt(quadratic_results[i]); results[2*i] = complex_negate(s); results[2*i + 1] = s; } return 2 * num_quad_results; } helper_cubic[0] = complex_negate(complex_mult(d, d)); helper_cubic[1] = complex_add(complex_mult(c, c), complex_mult_real(-4.0, e)); helper_cubic[2] = complex_mult_real(2.0, c); helper_cubic[3] = complex_from_real(1.0); if (solve_poly(3, helper_cubic, helper_results) < 1) return 0; p = complex_sqrt(helper_results[0]); c_plus_p_sqr = complex_add(c, complex_mult(p, p)); d_div_p = complex_div(d, p); quadratic_factor[0] = complex_add(c_plus_p_sqr, complex_negate(d_div_p)); quadratic_factor[1] = complex_mult_real(2.0, p); quadratic_factor[2] = complex_from_real(2.0); num_results = solve_poly(2, quadratic_factor, results); quadratic_factor[0] = complex_add(c_plus_p_sqr, d_div_p); quadratic_factor[1] = complex_negate(quadratic_factor[1]); return num_results + solve_poly(2, quadratic_factor, results + num_results); }
/* poly: pointer to coefficients array of size degree + 1. * results: pointer to results output array of size degree. */ int solve_poly(int degree, const complex_t* poly, complex_t* results) { complex_t normalized_poly[MAX_DEGREE + 1]; int i; const complex_t a = poly[degree]; if (complex_eq(a, complex_from_real(0.0))) return solve_poly(degree - 1, poly, results); if (degree > MAX_DEGREE) return -1; if (degree > 2 && stableness_score(poly[degree], poly[degree - 1]) > stableness_score(poly[0], poly[1])) { complex_t rev_poly[MAX_DEGREE + 1]; int num_results; for (i = 0; i <= degree; ++i) rev_poly[i] = poly[degree - i]; num_results = solve_poly(degree, rev_poly, results); for (i = 0; i < num_results; ++i) results[i] = complex_inverse(results[i]); return num_results; } for (i = 0; i < degree; ++i) normalized_poly[i] = complex_div(poly[i], a); normalized_poly[degree] = complex_from_real(1.0); return solve_normalized_poly(degree, normalized_poly, results); }
/* Based on http://en.wikipedia.org/wiki/Cubic_equation#Cardano.27s_method */ static int solve_depressed_cubic(const complex_t* poly, complex_t* results) { const complex_t q = poly[0]; const complex_t p = poly[1]; complex_t t, u, cubic_root_of_unity; int i; if (complex_eq(p, complex_from_real(0.0))) { results[0] = complex_pow_real(complex_negate(q), 1.0/3.0); return 1; } t = complex_add( complex_mult_real(0.25, complex_mult(q, q)), complex_mult_real(1.0/27.0, complex_mult(p, complex_mult(p, p)))); cubic_root_of_unity.real = -0.5; cubic_root_of_unity.imag = 0.5 * sqrt(3.0); for (i = 0; i < 3; ++i) { if (i == 0) u = complex_pow_real(complex_add(complex_mult_real(-0.5, q), complex_sqrt(t)), 1.0/3.0); else u = complex_mult(u, cubic_root_of_unity); results[i] = complex_add(u, complex_div(p, complex_mult_real(-3.0, u))); } return 3; }
// expect wavelength in m int SetReflectivity(struct ElementType *ep, double wavelength) { double f1, f2, a, rho, energy, nt, delta, beta, ac, sinag, cosag, Rs, Rp; int z, myreturn; COMPLEX cn, cn2, cwu, crs, cts, crp, ctp, c1, c2, c3, csinag; char *material; struct ReflecType *rp; material= ep->MDat.material; rp= (struct ReflecType *)&ep->reflec; #ifdef DEBUG printf("debug: SetReflectivity called, material= >%s<, file= %s\n", material, __FILE__); #endif if (!(wavelength > 0.0)) { fprintf(stderr, "error SetReflectivity: wavelength not defined (%f)- return"); return 0; } energy= 1240e-9/ wavelength; myreturn= ReadMaterial(material, &z, &a, &rho); myreturn &= ReadHenke(material, energy, &f1, &f2); nt= 1e6* rho * NA / a; // Teilchendichte (1/m^3), rho is in (g/cm^3) delta= RE * pow(wavelength, 2) * nt * f1 / (2.0 * PI); beta = RE * pow(wavelength, 2) * nt * f2 / (2.0 * PI); ac = acos(1.0 - delta); // critical (grazing) angle in rad complex_in(&cn, (1.0- delta), beta); // complex index of refraction sinag= ep->geo.cosa; // sin(grazing angle) grazing angle in rad cosag= ep->geo.sina; // sin <-> cos change for grazing angle // we calculate the compex reflectivity and transmission coefficients // transmission coefficients not used so far complex_x (&cn, &cn, &cn2); // n^2 complex_in (&c1, pow(cosag, 2.0), 0.0); // cos(theta))^2 saved in c1 complex_minus(&cn2, &c1, &c2); // c2= n2- c1 complex_pow (&c2, 0.5, &cwu); // wu= sqrt(c2) complex_in (&csinag, sinag, 0.0); // sin(theta) saved in csinag complex_minus(&csinag, &cwu, &c1); // zehler in c1 complex_plus (&csinag, &cwu, &c2); // nenner in c2 complex_div (&c1, &c2, &crs); // calc crs complex_in (&c1, (2* sinag), 0.0); // zehler in c1 complex_div(&c1, &c2, &cts); // calc cts complex_x (&cn2, &csinag, &c3); // c3 complex_minus(&c3, &cwu, &c1); // zehler in c1 complex_plus (&c3, &cwu, &c2); // nenner in c2 complex_div (&c1, &c2, &crp); // calc crp complex_in (&c1, 2.0, 0.0); // 2.0 in c1 complex_x (&c1, &cn, &c3); // 2n in c3 complex_x (&c3, &csinag, &c1); // zaehler in c1 complex_div(&c1, &c2, &ctp); // calc ctp Rs= pow(crs.re, 2)+ pow(crs.im, 2); // abs()^2 Rp= pow(crp.re, 2)+ pow(crp.im, 2); // abs()^2; rp->runpol= 0.5 * (Rs + Rp); // fill double ryamp, rypha, rzamp, rzpha, runpol; switch (ep->GDat.azimut) /* vertikal 0; nach links 1; nach unten 2 ; nach rechts 3 */ { case 0: case 2: rp->ryamp= sqrt(pow(crp.re, 2)+ pow(crp.im, 2)); rp->rypha= atan2(crp.im, crp.re); rp->rzamp= sqrt(pow(crs.re, 2)+ pow(crs.im, 2)); rp->rzpha= atan2(crs.im, crs.re); break; case 1: case 3: rp->rzamp= sqrt(pow(crp.re, 2)+ pow(crp.im, 2)); rp->rzpha= atan2(crp.im, crp.re); rp->ryamp= sqrt(pow(crs.re, 2)+ pow(crs.im, 2)); rp->rypha= atan2(crs.im, crs.re); break; default: fprintf(stderr, "error in file %s- azimut >>%d<<out of range\n", __FILE__, ep->GDat.azimut); exit(-1); } return myreturn; } // SetReflectivity
void compute_fourth_corner( Complex corner[4], VertexIndex missing_corner, Orientation orientation, ComplexWithLog cwl[3]) { int i; VertexIndex v[4]; Complex z[4], cross_ratio, diff20, diff21, numerator, denominator; /* * Given the locations on the sphere at infinity in * the upper half space model of three of a Tetrahedron's * four ideal vertices, compute_fourth_corner() computes * the location of the remaining corner. * * corner[4] is the array which contains the three known * corners, and into which the fourth will be * written. * * missing_corner is the index of the unknown corner. * * orientation is the Orientation with which the Tetrahedron * is currently being viewed. * * cwl[3] describes the shape of the Tetrahedron. */ /* * Set up an indexing scheme v[] for the vertices. * * If some vertex (!= missing_corner) is positioned at infinity, let its * index be v0. Otherwise choose v0 arbitrarily. Then choose * v2 and v3 so that the Tetrahedron looks right_handed relative * to the v[]. */ v[3] = missing_corner; v[0] = ! missing_corner; for (i = 0; i < 4; i++) if (i != missing_corner && complex_infinite(corner[i])) v[0] = i; if (orientation == right_handed) { v[1] = remaining_face[v[3]][v[0]]; v[2] = remaining_face[v[0]][v[3]]; } else { v[1] = remaining_face[v[0]][v[3]]; v[2] = remaining_face[v[3]][v[0]]; } /* * Let z[i] be the location of v[i]. * The z[i] are known for i < 3, unknown for i == 3. */ for (i = 0; i < 3; i++) z[i] = corner[v[i]]; /* * Note the cross_ratio at the edge connecting v0 to v1. */ cross_ratio = cwl[edge3_between_faces[v[0]][v[1]]].rect; if (orientation == left_handed) cross_ratio = complex_conjugate(complex_div(One, cross_ratio)); /* * The cross ratio is defined as * * (z3 - z1) (z2 - z0) * cross_ratio = ----------------------- * (z2 - z1) (z3 - z0) * * Solve for z3. * * z1*(z2 - z0) - cross_ratio*z0*(z2 - z1) * z3 = ----------------------------------------- * (z2 - z0) - cross_ratio*(z2 - z1) * * If z0 is infinite, this reduces to * * z3 = z1 + cross_ratio * (z2 - z1) * * which makes sense geometrically. */ if (complex_infinite(z[0]) == TRUE) z[3] = complex_plus( z[1], complex_mult( cross_ratio, complex_minus(z[2], z[1]) ) ); else { diff20 = complex_minus(z[2], z[0]); diff21 = complex_minus(z[2], z[1]); numerator = complex_minus( complex_mult(z[1], diff20), complex_mult( cross_ratio, complex_mult(z[0], diff21) ) ); denominator = complex_minus( diff20, complex_mult(cross_ratio, diff21) ); z[3] = complex_div(numerator, denominator); /* will handle division by Zero correctly */ } corner[missing_corner] = z[3]; }
static void compute_derivative( Triangulation *manifold) { Tetrahedron *tet; Complex z[3], d[3], *eqn_coef = NULL, dz[2]; EdgeIndex e; VertexIndex v; FaceIndex initial_side, terminal_side; int init[2][2], term[2][2]; double m, l, a, b, *eqn_coef_00 = NULL, *eqn_coef_01 = NULL, *eqn_coef_10 = NULL, *eqn_coef_11 = NULL; int i, j; for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) { /* * Note the three edge parameters. */ for (i = 0; i < 3; i++) z[i] = tet->shape[filled]->cwl[ultimate][i].rect; /* * Set the derivatives of log(z0), log(z1) and log(z2) * with respect to the given coordinate system, as * indicated by the above table. */ switch (tet->coordinate_system) { case 0: d[0] = One; d[1] = complex_div(MinusOne, z[2]); d[2] = complex_minus(Zero, z[1]); break; case 1: d[0] = complex_minus(Zero, z[2]); d[1] = One; d[2] = complex_div(MinusOne, z[0]); break; case 2: d[0] = complex_div(MinusOne, z[1]); d[1] = complex_minus(Zero, z[0]); d[2] = One; break; } /* * Record this tetrahedron's contribution to the edge equations. */ for (e = 0; e < 6; e++) /* Look at each of the six edges. */ { /* * Find the matrix entry(ies) corresponding to the * derivative of the edge equation with respect to this * tetrahedron. If the manifold is oriented it will be * a single entry in the complex matrix. If the manifold * is unoriented it will be a 2 x 2 block in the real matrix. */ if (manifold->orientability == oriented_manifold || manifold->orientability == oriented_orbifold ) /* DJH */ eqn_coef = &tet->edge_class[e]->complex_edge_equation[tet->index]; else { eqn_coef_00 = &tet->edge_class[e]->real_edge_equation_re[2 * tet->index]; eqn_coef_01 = &tet->edge_class[e]->real_edge_equation_re[2 * tet->index + 1]; eqn_coef_10 = &tet->edge_class[e]->real_edge_equation_im[2 * tet->index]; eqn_coef_11 = &tet->edge_class[e]->real_edge_equation_im[2 * tet->index + 1]; } /* * Add in the derivative of the log of the edge parameter * with respect to the chosen coordinate system. Please * see the comment preceding this function for details. */ if (manifold->orientability == oriented_manifold || manifold->orientability == oriented_orbifold ) /* DJH */ *eqn_coef = complex_plus(*eqn_coef, d[edge3[e]]); else { /* * These are the same a and b as in the comment * preceding this function. */ a = d[edge3[e]].real; b = d[edge3[e]].imag; if (tet->edge_orientation[e] == right_handed) { *eqn_coef_00 += a; *eqn_coef_01 -= b; *eqn_coef_10 += b; *eqn_coef_11 += a; } else { *eqn_coef_00 -= a; *eqn_coef_01 += b; *eqn_coef_10 += b; *eqn_coef_11 += a; } } } /* * Record this tetrahedron's contribution to the cusp equations. */ for (v = 0; v < 4; v++) /* Look at each ideal vertex. */ { /* * Note the Dehn filling coefficients on this cusp. * If the cusp is complete, use m = 1.0 and l = 0.0. */ if (tet->cusp[v]->is_complete) /* DJH : not sure ? */ { m = 1.0; l = 0.0; } else { m = tet->cusp[v]->m; l = tet->cusp[v]->l; } /* * Find the matrix entry(ies) corresponding to the * derivative of the cusp equation with respect to this * tetrahedron. If the manifold is oriented it will be * a single entry in the complex matrix. If the manifold * is unoriented it will be a 2 x 2 block in the real matrix. */ /* DJH */ if ( (manifold->orientability == oriented_manifold || manifold->orientability == oriented_orbifold ) && ( tet->cusp[v]->topology == torus_cusp || tet->cusp[v]->topology == Klein_cusp ) ) eqn_coef = &tet->cusp[v]->complex_cusp_equation[tet->index]; else { eqn_coef_00 = &tet->cusp[v]->real_cusp_equation_re[2 * tet->index]; eqn_coef_01 = &tet->cusp[v]->real_cusp_equation_re[2 * tet->index + 1]; eqn_coef_10 = &tet->cusp[v]->real_cusp_equation_im[2 * tet->index]; eqn_coef_11 = &tet->cusp[v]->real_cusp_equation_im[2 * tet->index + 1]; } /* * Each ideal vertex contains two triangular cross sections, * one right_handed and the other left_handed. We want to * compute the contribution of each angle of each triangle * to the holonomy. We begin by considering the right_handed * triangle, looking at each of its three angles. A directed * angle is specified by its initial and terminal sides. * We find the number of strands of the Dehn filling curve * passing from the initial side to the terminal side; * it is m * (number of strands of meridian) * + l * (number of strands of longitude), where (m,l) are * the Dehn filling coefficients (in practice, m and l need * not be integers, but it's simpler to imagine them to be * integers as you try to understand the following code). * The number of strands of the Dehn filling curves passing * from the initial to the terminal side is multiplied by * the derivative of the log of the complex angle, to yield * the contribution to the derivative matrix. If the manifold * is oriented, that complex number is added directly to * the relevant matrix entry. If the manifold is unoriented, * we convert the complex number to a 2 x 2 real matrix * (cf. the comments preceding this function) and add it to * the appropriate 2 x 2 block of the real derivative matrix. * The 2 x 2 matrix for the left_handed triangle is modified * to account for the fact that although the real part of the * derivative of the log (i.e. the compression/expansion * factor) is the same, the imaginary part (i.e. the rotation) * is negated. [Note that in computing the edge equations * the real part was negated, while for the cusp equations * the imaginary part is negated. I will leave an explanation * of the difference as an exercise for the reader.] * * Note that we cannot possibly handle curves on the * left_handed sheet of the orientation double cover of * a cusp of an oriented manifold. The reason is that the * log of the holonomy of the Dehn filling curve is not * a complex analytic function of the shape of the tetrahedron * (it's the complex conjugate of such a function). I.e. * it doesn't have a derivative in the complex sense. This * is why we make the convention that all peripheral curves * in oriented manifolds lie on the right_handed sheet of * the double cover. */ for (initial_side = 0; initial_side < 4; initial_side++) { if (initial_side == v) continue; terminal_side = remaining_face[v][initial_side]; /* * 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]; } } /* * For each triangle (right_handed and left_handed), * multiply the number of strands of the Dehn filling * curve running from initial_side to terminal_side * by the derivative of the log of the edge parameter. */ for (i = 0; i < 2; i++) /* which sheet */ dz[i] = complex_real_mult( m * FLOW(init[M][i],term[M][i]) + l * FLOW(init[L][i],term[L][i]), d[ edge3_between_faces[initial_side][terminal_side] ] ); /* * If the manifold is oriented, the Dehn filling curve * must lie of the right_handed sheet of the orientation * double cover (cf. above). Add its contributation to * the cusp equation. */ /* DJH */ if (manifold->orientability == oriented_manifold || manifold->orientability == oriented_orbifold ) *eqn_coef = complex_plus(*eqn_coef, dz[right_handed]); /* "else" follows below */ /* * If the manifold is unoriented, treat the right_ and * left_handed sheets separately. Add in the contribution * of the right_handed sheet normally. For the left_handed * sheet, we must account for the fact that even though * the modulus of the derivative (i.e. the expansion/ * contraction factor) is correct, its argument (i.e. the * angle of rotation) is the negative of what it should be. */ else { a = dz[right_handed].real; b = dz[right_handed].imag; *eqn_coef_00 += a; *eqn_coef_01 -= b; *eqn_coef_10 += b; *eqn_coef_11 += a; a = dz[left_handed].real; b = dz[left_handed].imag; *eqn_coef_00 += a; *eqn_coef_01 -= b; *eqn_coef_10 -= b; *eqn_coef_11 -= a; } } } } }
complex_float complex_tan(complex_float c1){ complex_float cpx_sin = complex_sin(c1); complex_float cpx_cos = complex_cos(c1); complex_float r = complex_div( cpx_sin, cpx_cos ); return r; }
static void compute_one_cusp_shape( Triangulation *manifold, Cusp *cusp, FillingStatus which_structure) { PositionedTet initial_ptet; TraceDirection direction[2]; /* direction[M/L] */ Complex translation[2][2], /* translation[M/L][ultimate/penultimate] */ shape[2]; /* shape[ultimate/penultimate] */ int i; /* * Compute the longitudinal and meridional translations, and * divide them to get the cusp shape. * * Do parallel computations for the ultimate and penultimate shapes, * to estimate the accuracy of the final answer. */ /* * Find and position a tetrahedron so that the near edge of the top * vertex intersects both the meridian and the longitude. */ initial_ptet = find_start(manifold, cusp); for (i = 0; i < 2; i++) /* which curve */ { /* * Decide whether the meridian and longitude cross the near edge of the * top vertex in a forwards or backwards direction. */ direction[i] = (initial_ptet.tet->curve[i][initial_ptet.orientation] [initial_ptet.bottom_face] [initial_ptet.near_face] > 0) ? trace_forwards: trace_backwards; /* * Compute the translation. */ compute_translation(&initial_ptet, i, direction[i], translation[i], which_structure); } /* * Compute the cusp shape. */ for (i = 0; i < 2; i++) /* i = ultimate, penultimate */ shape[i] = complex_div(translation[L][i], translation[M][i]); /* will handle division by Zero correctly */ /* * Record the cusp shape and its accuracy. */ cusp->cusp_shape[which_structure] = shape[ultimate]; cusp->shape_precision[which_structure] = complex_decimal_places_of_accuracy(shape[ultimate], shape[penultimate]); /* * Adjust for the fact that the meridian and/or the longitude may have * been traced backwards. */ if (direction[M] != direction[L]) { cusp->cusp_shape[which_structure].real = - cusp->cusp_shape[which_structure].real; cusp->cusp_shape[which_structure].imag = - cusp->cusp_shape[which_structure].imag; } /* * As explained at the top of this file, the usual convention for the * cusp shape requires viewing the cusp from the fat part of * the manifold looking out, rather than from the cusp looking in, as * in done in the rest of SnapPea. For this reason, we must take the * complex conjugate of the final cusp shape. */ cusp->cusp_shape[which_structure].imag = - cusp->cusp_shape[which_structure].imag; }
int main(){ int ix,iy,radius,i,tries,nit; double zx,zy,zxn,zyn,cx,cy,theta, x,y,eps, poly[MAX_ROOTS+1]; _roots roots; _complex z,w,fz,dfz; root_init(&roots); // Number of iteration for each pointer. // The bigger, the less prone to error the program will be. nit=100; // The radius where the points will be looked for. radius=6; // Precision for the roots eps=1E-10; scanf("%d",&roots.grad); for(i=roots.grad;i>=0;i--){ scanf("%lf",&poly[i]); } printf("Coefficients:\n"); for(i=roots.grad;i>=0;i--){ printf(" a%d=%+.2f\n",i,poly[i]); } printf("\n f(0+0i)="); complex_print(f(complex_init(0,0),roots.grad, poly)); printf("df(0+0i)="); complex_print(df(complex_init(0,0),roots.grad, poly)); tries=0; do{ tries++; theta=drand48()*2*M_PI; x=radius*cos(theta); y=radius*sin(theta); z=complex_init(x,y); for(i=0;i<=nit;i++){ fz = f(z,roots.grad,poly); dfz=df(z,roots.grad,poly); if(complex_abs(dfz)<ee){ break; } w=z; z=complex_sub(z,complex_div(fz,dfz)); if(complex_abs(complex_sub(z,w))<=eps){ process_root(z,&roots,eps); break; } } }while(roots.nor<roots.grad); printf("\nTook %d tries to get all %d roots\n",tries,roots.grad); printf("\nZeroes and their images:\n\n"); for(i=0;i<roots.grad;i++){ printf("Root Z%d=%+lf %+lfi \tf(z%d)=",i+1,roots.root[i].x,roots.root[i].y,i+1); complex_print(f(roots.root[i],roots.grad, poly)); } return EXIT_SUCCESS; }
static void compute_translation( PositionedTet *initial_ptet, PeripheralCurve which_curve, TraceDirection which_direction, Complex translation[2], /* returns translations based on ultimate */ /* and penultimate shapes */ FillingStatus which_structure) { PositionedTet ptet; int i, initial_strand, strand, *this_vertex, near_strands, left_strands; Complex left_endpoint[2], /* left_endpoint[ultimate/penultimate] */ right_endpoint[2], /* right_endpoint[ultimate/penultimate] */ old_diff, new_diff, rotation; /* * Place the near edge of the top vertex of the initial_ptet in the * complex plane with its left endpoint at zero and its right endpoint at one. * Trace the curve which_curve in the direction which_direction, using the * shapes of the ideal tetrahedra to compute the position of endpoints of * each edge we cross. When we return to our starting point in the manifold, * the position of the left endpoint (or the position of the right endpoint * minus one) will tell us the translation. * * Note that we are working in the orientation double cover of the cusp. * * Here's how we keep track of where we are. At each step, we are always * at the near edge of the top vertex (i.e. the truncated vertex opposite * the bottom face) of the PositionedTet ptet. The curve (i.e. the * meridian or longitude) may cross that edge several times. The variable * "strand" keeps track of which intersection we are at; 0 means we're at * the strand on the far left, 1 means we're at the next strand, etc. */ ptet = *initial_ptet; initial_strand = 0; strand = initial_strand; for (i = 0; i < 2; i++) /* i = ultimate, penultimate */ { left_endpoint[i] = Zero; right_endpoint[i] = One; } do { /* * Note the curve's intersection numbers with the near side and left side. */ this_vertex = ptet.tet->curve[which_curve][ptet.orientation][ptet.bottom_face]; near_strands = this_vertex[ptet.near_face]; left_strands = this_vertex[ptet.left_face]; /* * If we are tracing the curve backwards, negate the intersection numbers * so the rest of compute_translation() can enjoy the illusion that we * are tracing the curve forwards. */ if (which_direction == trace_backwards) { near_strands = - near_strands; left_strands = - left_strands; } /* * Does the current strand bend to the left or to the right? */ if (strand < FLOW(near_strands, left_strands)) { /* * The current strand bends to the left. */ /* * The left_endpoint remains fixed. * Update the right_endpoint. * * The plan is to compute the vector old_diff which runs * from left_endpoint to right_endpoint, multiply it by the * complex edge parameter to get the vector new_diff which * runs from left_endpoint to the new value of right_endpoint, * and then add new_diff to left_endpoint to get the new * value of right_endpoint itself. * * Note that the complex edge parameters are always expressed * relative to the right_handed Orientation, so if we are * viewing this Tetrahedron relative to the left_handed * Orientation, we must take the conjugate-inverse of the * edge parameter. */ for (i = 0; i < 2; i++) /* i = ultimate, penultimate */ { old_diff = complex_minus(right_endpoint[i], left_endpoint[i]); rotation = ptet.tet->shape[which_structure]->cwl[i][edge3_between_faces[ptet.near_face][ptet.left_face]].rect; if (ptet.orientation == left_handed) { rotation = complex_div(One, rotation); /* invert . . . */ rotation.imag = - rotation.imag; /* . . . and conjugate */ } new_diff = complex_mult(old_diff, rotation); right_endpoint[i] = complex_plus(left_endpoint[i], new_diff); } /* * strand remains unchanged. */ /* * Move the PositionedTet onward, following the curve. */ veer_left(&ptet); } else { /* * The current strand bends to the right. * * Proceed as above, but note that * * (1) We now divide by the complex edge parameter * instead of multiplying by it. * * (2) We must adjust the variable "strand". Some of the strands * from the near edge may be peeling off to the left (in which * case left_strands is negative), or some strands from the left * edge may be joining those from the near edge in passing to * the right edge (in which case left_strands is positive). * Either way, the code "strand += left_strands" is correct. */ for (i = 0; i < 2; i++) /* i = ultimate, penultimate */ { old_diff = complex_minus(left_endpoint[i], right_endpoint[i]); rotation = ptet.tet->shape[which_structure]->cwl[i][edge3_between_faces[ptet.near_face][ptet.right_face]].rect; if (ptet.orientation == left_handed) { rotation = complex_div(One, rotation); rotation.imag = - rotation.imag; } new_diff = complex_div(old_diff, rotation); left_endpoint[i] = complex_plus(right_endpoint[i], new_diff); } strand += left_strands; veer_right(&ptet); } } while ( ! same_positioned_tet(&ptet, initial_ptet) || strand != initial_strand); /* * Write the computed translations, and return. */ for (i = 0; i < 2; i++) /* i = ultimate, penultimate */ translation[i] = left_endpoint[i]; }
complex_float complex_sec(complex_float c1){ // this is 1/cos complex_float cpx_cos = complex_cos(c1); complex_float r = complex_div(complex_make(1.0f),cpx_cos); return r; }
complex_float complex_csc(complex_float c1){ // this is 1/sin complex_float cpx_sin = complex_sin(c1); complex_float r = complex_div(complex_make(1.0f),cpx_sin); return r; }
static void initial_tetrahedron( Triangulation *manifold, Tetrahedron **initial_tet, Boolean compute_corners, Boolean centroid_at_origin) { VertexIndex v[4]; Complex z, sqrt_z, w[4]; Tetrahedron *tet; EdgeIndex best_edge, edge; /* * Set a default choice of tetrahedron and edge. */ *initial_tet = manifold->tet_list_begin.next; best_edge = 0; /* * 2000/02/11 JRW Can we choose the initial tetrahedron in such * a way that if we happen to have the canonical triangulation * of a 2-bridge knot or link complement, the basepoint falls * at a center of D2 symmetry? That is, can we find a Tetrahedron * that looks like the "top of the tower" in the canonical * triangulation of a 2-bridge knot or link complement? */ for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (edge = 0; edge < 6; edge++) if (tet->neighbor[one_face_at_edge [edge]] == tet->neighbor[other_face_at_edge[edge]]) { *initial_tet = tet; best_edge = edge; } if (compute_corners) { if (centroid_at_origin == TRUE) { /* * Proposition. For any value of w, positioning the corners at * * corner[0] = w * corner[1] = w^-1 * corner[2] = -w^-1 * corner[3] = -w * * defines a tetrahedron with its centroid at the "origin" and * the common perpendiculars between pairs of opposite edges * coincident with the "coordinate axes". [In the Klein model, * the tetrahedron is inscribed in a rectangular box whose faces * are parallel to the coordinate axes.] * * Proof: Use the observation that the line from a0 to a1 will * intersect the line from b0 to b1 iff the cross ratio * * (b0 - a0) (b1 - a1) * ------------------- * (b1 - a0) (b0 - a1) * * of the tetrahedron they span is real, and they will be * orthogonal iff the cross ratio is -1. * * [-w, w] is orthogonal to [0, infinity] because * * (0 - -w) (infinity - w) * ----------------------- = -1 * (infinity - -w) (0 - w) * * and similarly for [-w^-1, w^-1] and [0, infinity]. * * [w^-1, w] is orthogonal to [-1, 1] because * * (-1 - w^-1) (1 - w) * ------------------- = -1 * (1 - w^-1) (-1 - w) * * and similarly for [-w^-1, -w] and [-1, 1]. * * [-w^-1, w] is orthogonal to [-i, i] because * * (-i - -w^-1) (i - w) * -------------------- = -1 * (i - -w^-1) (-i - w) * * and similarly for [w^-1, -w] and [-i, i]. * * Q.E.D. * * * The tetrahedron will have the correct cross ratio z iff * * (w - -w^-1) (w^-1 - -w ) (w + w^-1)^2 * z = -------------------------- = -------------- * (w - -w ) (w^-1 - -w^-1) 4 * * Solving for w in terms of z gives the four possibilities * * w = +- (sqrt(z) +- sqrt(z - 1)) * * Note that sqrt(z) + sqrt(z - 1) and sqrt(z) - sqrt(z - 1) are * inverses of one another. We can choose any of the four solutions * to be "w", and the other three will automatically become w^-1, * -w, and -w^-1. * * Comment: This position for the initial corners brings out * nice numerical properties in the O(3,1) matrices for manifolds * composed of regular ideal tetrahedra (cf. the proofs in the * directory "Tilings of H^3", which aren't part of SnapPea, but * I could give you a copy). */ z = (*initial_tet)->shape[filled]->cwl[ultimate][0].rect; w[0] = complex_plus( complex_sqrt(z), complex_sqrt(complex_minus(z, One)) ); w[1] = complex_div(One, w[0]); w[2] = complex_negate(w[1]); w[3] = complex_negate(w[0]); (*initial_tet)->corner[0] = w[0]; (*initial_tet)->corner[1] = w[1]; (*initial_tet)->corner[2] = w[2]; (*initial_tet)->corner[3] = w[3]; } else { /* * Originally this code positioned the Tetrahedron's vertices * at {0, 1, z, infinity}. As of 2000/02/04 I modified it * to put the vertices at {0, 1/sqrt(z), sqrt(z), infinity} instead, * so that the basepoint (0,0,1) falls at the midpoint * of the edge extending from 0 to infinity, and the * tetrahedron's symmetry axis lies parallel to the x-axis. * To convince yourself that the tetrahedron's axis of * symmetry does indeed pass through that point, note * that a half turn around the axis of symmetry factors * as a reflection in the plane |z| = 1 followed by * a reflection in the vertical plane sitting over x-axis. */ /* * Order the vertices so that the tetrahedron is positively * oriented, and the selected edge is between vertices * v[0] and v[1]. */ v[0] = one_vertex_at_edge[best_edge]; v[1] = other_vertex_at_edge[best_edge]; v[2] = remaining_face[v[1]][v[0]]; v[3] = remaining_face[v[0]][v[1]]; /* * Set the coordinates of the corners. */ z = (*initial_tet)->shape[filled]->cwl[ultimate][edge3[best_edge]].rect; sqrt_z = complex_sqrt(z); (*initial_tet)->corner[v[0]] = Infinity; (*initial_tet)->corner[v[1]] = Zero; (*initial_tet)->corner[v[2]] = complex_div(One, sqrt_z); (*initial_tet)->corner[v[3]] = sqrt_z; } } }
complex_float complex_arctan(complex_float c1){ complex_float cpx_asin = complex_arcsin(c1); complex_float cpx_acos = complex_arccos(c1); complex_float r = complex_div(cpx_asin,cpx_acos); return r; }