static ex atan_conjugate(const ex & x) { // conjugate(atan(x))==atan(conjugate(x)) unless on the branch cuts which // run along the imaginary axis outside the interval [-I, +I]. if (x.info(info_flags::real)) return atan(x); if (is_exactly_a<numeric>(x)) { const numeric x_re = ex_to<numeric>(x.real_part()); const numeric x_im = ex_to<numeric>(x.imag_part()); if (!x_re.is_zero() || (x_im > *_num_1_p && x_im < *_num1_p)) return atan(x.conjugate()); } return conjugate_function(atan(x)).hold(); }
static ex binomial_sym(const ex & x, const numeric & y) { if (y.is_integer()) { if (y.is_nonneg_integer()) { const unsigned N = y.to_int(); if (N == 0) return _ex1; if (N == 1) return x; ex t = x.expand(); for (unsigned i = 2; i <= N; ++i) t = (t * (x + i - y - 1)).expand() / i; return t; } else return _ex0; } return binomial(x, y).hold(); }
// These tests work with Python 2.2, but you must have Numeric installed. object check_numeric_array_rich_slice( char const* module_name, char const* array_type_name, object all) { using numeric::array; array::set_module_and_type(module_name, array_type_name); array original = array( make_tuple( make_tuple( 11, 12, 13, 14), make_tuple( 21, 22, 23, 24), make_tuple( 31, 32, 33, 34), make_tuple( 41, 42, 43, 44))); array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12), make_tuple( 21, 22))); array odd_cells = array( make_tuple( make_tuple( 11, 13), make_tuple( 31, 33))); array even_cells = array( make_tuple( make_tuple( 22, 24), make_tuple( 42, 44))); array lower_right_quadrant_reversed = array( make_tuple( make_tuple(44, 43), make_tuple(34, 33))); // The following comments represent equivalent Python expressions used // to validate the array behavior. // original[::] == original ASSERT_EQUAL(original[slice()],original); // original[:2,:2] == array( [[11, 12], [21, 22]]) ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant); // original[::2,::2] == array( [[11, 13], [31, 33]]) ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells); // original[1::2, 1::2] == array( [[22, 24], [42, 44]]) ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells); // original[:-3:-1, :-3,-1] == array( [[44, 43], [34, 33]]) ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed); return object(1); }
// These tests work with Python 2.2, but you must have Numeric installed. bool check_numeric_array_rich_slice() { using numeric::array; array original = array( make_tuple( make_tuple( 11, 12, 13, 14), make_tuple( 21, 22, 23, 24), make_tuple( 31, 32, 33, 34), make_tuple( 41, 42, 43, 44))); array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12), make_tuple( 21, 22))); array odd_cells = array( make_tuple( make_tuple( 11, 13), make_tuple( 31, 33))); array even_cells = array( make_tuple( make_tuple( 22, 24), make_tuple( 42, 44))); array lower_right_quadrant_reversed = array( make_tuple( make_tuple(44, 43), make_tuple(34, 33))); // The following comments represent equivalent Python expressions used // to validate the array behavior. // original[::] == original if (original[slice()] != original) return false; // original[:2,:2] == array( [[11, 12], [21, 22]]) if (original[make_tuple(slice(_,2), slice(_,2))] != upper_left_quadrant) return false; // original[::2,::2] == array( [[11, 13], [31, 33]]) if (original[make_tuple( slice(_,_,2), slice(_,_,2))] != odd_cells) return false; // original[1::2, 1::2] == array( [[22, 24], [42, 44]]) if (original[make_tuple( slice(1,_,2), slice(1,_,2))] != even_cells) return false; // original[:-3:-1, :-3,-1] == array( [[44, 43], [34, 33]]) if (original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))] != lower_right_quadrant_reversed) return false; return true; }
inline Target numeric_cast(Source arg) { // typedefs abbreviating respective trait classes typedef detail::fixed_numeric_limits<Source> arg_traits; typedef detail::fixed_numeric_limits<Target> result_traits; #if defined(BOOST_STRICT_CONFIG) \ || (!defined(__HP_aCC) || __HP_aCC > 33900) \ && (!defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) \ || defined(BOOST_SGI_CPP_LIMITS)) // typedefs that act as compile time assertions // (to be replaced by boost compile time assertions // as and when they become available and are stable) typedef bool argument_must_be_numeric[arg_traits::is_specialized]; typedef bool result_must_be_numeric[result_traits::is_specialized]; const bool arg_is_signed = arg_traits::is_signed; const bool result_is_signed = result_traits::is_signed; const bool same_sign = arg_is_signed == result_is_signed; if (less_than_type_min<arg_is_signed, result_is_signed>::check(arg, (result_traits::min)()) || greater_than_type_max<same_sign, arg_is_signed>::check(arg, (result_traits::max)()) ) #else // We need to use #pragma hacks if available # if BOOST_MSVC # pragma warning(push) # pragma warning(disable : 4018) #elif defined(__BORLANDC__) #pragma option push -w-8012 # endif if ((arg < 0 && !result_traits::is_signed) // loss of negative range || (arg_traits::is_signed && arg < (result_traits::min)()) // underflow || arg > (result_traits::max)()) // overflow # if BOOST_MSVC # pragma warning(pop) #elif defined(__BORLANDC__) #pragma option pop # endif #endif { throw bad_numeric_cast(); } return static_cast<Target>(arg); } // numeric_cast
static ex eta_eval(const ex &x, const ex &y) { // trivial: eta(x,c) -> 0 if c is real and positive if (x.info(info_flags::positive) || y.info(info_flags::positive)) return _ex0; if (x.info(info_flags::numeric) && y.info(info_flags::numeric)) { // don't call eta_evalf here because it would call Pi.evalf()! const numeric nx = ex_to<numeric>(x); const numeric ny = ex_to<numeric>(y); const numeric nxy = ex_to<numeric>(x*y); int cut = 0; if (nx.is_real() && nx.is_negative()) cut -= 4; if (ny.is_real() && ny.is_negative()) cut -= 4; if (nxy.is_real() && nxy.is_negative()) cut += 4; return (I/4)*Pi*((csgn(-imag(nx))+1)*(csgn(-imag(ny))+1)*(csgn(imag(nxy))+1)- (csgn(imag(nx))+1)*(csgn(imag(ny))+1)*(csgn(-imag(nxy))+1)+cut); } return eta(x,y).hold(); }
static ex eta_evalf(const ex &x, const ex &y) { // It seems like we basically have to replicate the eval function here, // since the expression might not be fully evaluated yet. if (x.info(info_flags::positive) || y.info(info_flags::positive)) return _ex0; if (x.info(info_flags::numeric) && y.info(info_flags::numeric)) { const numeric nx = ex_to<numeric>(x); const numeric ny = ex_to<numeric>(y); const numeric nxy = ex_to<numeric>(x*y); int cut = 0; if (nx.is_real() && nx.is_negative()) cut -= 4; if (ny.is_real() && ny.is_negative()) cut -= 4; if (nxy.is_real() && nxy.is_negative()) cut += 4; return evalf(I/4*Pi)*((csgn(-imag(nx))+1)*(csgn(-imag(ny))+1)*(csgn(imag(nxy))+1)- (csgn(imag(nx))+1)*(csgn(imag(ny))+1)*(csgn(-imag(nxy))+1)+cut); } return eta(x,y).hold(); }
/** Numeric postfix decrement. Returns the number and leaves the original * decremented by 1. */ const numeric operator--(numeric & lh, int) { numeric tmp(lh); lh = lh.add(*_num_1_p); return tmp; }
/** * Exact polynomial division of a, b \in Z_p[x_0, \ldots, x_n] * It doesn't check whether the inputs are proper polynomials, so be careful * of what you pass in. * * @param a first multivariate polynomial (dividend) * @param b second multivariate polynomial (divisor) * @param q quotient (returned) * @param var variables X iterator to first element of vector of symbols * * @return "true" when exact division succeeds (the quotient is returned in * q), "false" otherwise. * @note @a p = 0 means the base ring is Z */ bool divide_in_z_p(const ex &a, const ex &b, ex &q, const exvector& vars, const long p) { static const ex _ex1(1); if (b.is_zero()) throw(std::overflow_error("divide_in_z: division by zero")); if (b.is_equal(_ex1)) { q = a; return true; } if (is_exactly_a<numeric>(a)) { if (is_exactly_a<numeric>(b)) { // p == 0 means division in Z if (p == 0) { const numeric tmp = ex_to<numeric>(a/b); if (tmp.is_integer()) { q = tmp; return true; } else return false; } else { q = (a*recip(ex_to<numeric>(b), p)).smod(numeric(p)); return true; } } else return false; } if (a.is_equal(b)) { q = _ex1; return true; } // Main symbol const ex &x = vars.back(); // Compare degrees int adeg = a.degree(x), bdeg = b.degree(x); if (bdeg > adeg) return false; // Polynomial long division (recursive) ex r = a.expand(); if (r.is_zero()) return true; int rdeg = adeg; ex eb = b.expand(); ex blcoeff = eb.coeff(x, bdeg); exvector v; v.reserve(std::max(rdeg - bdeg + 1, 0)); exvector rest_vars(vars); rest_vars.pop_back(); while (rdeg >= bdeg) { ex term, rcoeff = r.coeff(x, rdeg); if (!divide_in_z_p(rcoeff, blcoeff, term, rest_vars, p)) break; term = (term*power(x, rdeg - bdeg)).expand(); v.push_back(term); r = (r - term*eb).expand(); if (p != 0) r = r.smod(numeric(p)); if (r.is_zero()) { q = (new add(v))->setflag(status_flags::dynallocated); return true; } rdeg = r.degree(x); } return false; }
const numeric fsolve(const ex& f_in, const symbol& x, const numeric& x1, const numeric& x2) { if (!x1.is_real() || !x2.is_real()) { throw std::runtime_error("fsolve(): interval not bounded by real numbers"); } if (x1==x2) { throw std::runtime_error("fsolve(): vanishing interval"); } // xx[0] == left interval limit, xx[1] == right interval limit. // fx[0] == f(xx[0]), fx[1] == f(xx[1]). // We keep the root bracketed: xx[0]<xx[1] and fx[0]*fx[1]<0. numeric xx[2] = { x1<x2 ? x1 : x2, x1<x2 ? x2 : x1 }; ex f; if (is_a<relational>(f_in)) { f = f_in.lhs()-f_in.rhs(); } else { f = f_in; } const ex fx_[2] = { f.subs(x==xx[0]).evalf(), f.subs(x==xx[1]).evalf() }; if (!is_a<numeric>(fx_[0]) || !is_a<numeric>(fx_[1])) { throw std::runtime_error("fsolve(): function does not evaluate numerically"); } numeric fx[2] = { ex_to<numeric>(fx_[0]), ex_to<numeric>(fx_[1]) }; if (!fx[0].is_real() || !fx[1].is_real()) { throw std::runtime_error("fsolve(): function evaluates to complex values at interval boundaries"); } if (fx[0]*fx[1]>=0) { throw std::runtime_error("fsolve(): function does not change sign at interval boundaries"); } // The Newton-Raphson method has quadratic convergence! Simply put, it // replaces x with x-f(x)/f'(x) at each step. -f/f' is the delta: const ex ff = normal(-f/f.diff(x)); int side = 0; // Start at left interval limit. numeric xxprev; numeric fxprev; do { xxprev = xx[side]; fxprev = fx[side]; ex dx_ = ff.subs(x == xx[side]).evalf(); if (!is_a<numeric>(dx_)) throw std::runtime_error("fsolve(): function derivative does not evaluate numerically"); xx[side] += ex_to<numeric>(dx_); // Now check if Newton-Raphson method shot out of the interval bool bad_shot = (side == 0 && xx[0] < xxprev) || (side == 1 && xx[1] > xxprev) || xx[0] > xx[1]; if (!bad_shot) { // Compute f(x) only if new x is inside the interval. // The function might be difficult to compute numerically // or even ill defined outside the interval. Also it's // a small optimization. ex f_x = f.subs(x == xx[side]).evalf(); if (!is_a<numeric>(f_x)) throw std::runtime_error("fsolve(): function does not evaluate numerically"); fx[side] = ex_to<numeric>(f_x); } if (bad_shot) { // Oops, Newton-Raphson method shot out of the interval. // Restore, and try again with the other side instead! xx[side] = xxprev; fx[side] = fxprev; side = !side; xxprev = xx[side]; fxprev = fx[side]; ex dx_ = ff.subs(x == xx[side]).evalf(); if (!is_a<numeric>(dx_)) throw std::runtime_error("fsolve(): function derivative does not evaluate numerically [2]"); xx[side] += ex_to<numeric>(dx_); ex f_x = f.subs(x==xx[side]).evalf(); if (!is_a<numeric>(f_x)) throw std::runtime_error("fsolve(): function does not evaluate numerically [2]"); fx[side] = ex_to<numeric>(f_x); } if ((fx[side]<0 && fx[!side]<0) || (fx[side]>0 && fx[!side]>0)) { // Oops, the root isn't bracketed any more. // Restore, and perform a bisection! xx[side] = xxprev; fx[side] = fxprev; // Ah, the bisection! Bisections converge linearly. Unfortunately, // they occur pretty often when Newton-Raphson arrives at an x too // close to the result on one side of the interval and // f(x-f(x)/f'(x)) turns out to have the same sign as f(x) due to // precision errors! Recall that this function does not have a // precision goal as one of its arguments but instead relies on // x converging to a fixed point. We speed up the (safe but slow) // bisection method by mixing in a dash of the (unsafer but faster) // secant method: Instead of splitting the interval at the // arithmetic mean (bisection), we split it nearer to the root as // determined by the secant between the values xx[0] and xx[1]. // Don't set the secant_weight to one because that could disturb // the convergence in some corner cases! constexpr double secant_weight = 0.984375; // == 63/64 < 1 numeric xxmid = (1-secant_weight)*0.5*(xx[0]+xx[1]) + secant_weight*(xx[0]+fx[0]*(xx[0]-xx[1])/(fx[1]-fx[0])); ex fxmid_ = f.subs(x == xxmid).evalf(); if (!is_a<numeric>(fxmid_)) throw std::runtime_error("fsolve(): function does not evaluate numerically [3]"); numeric fxmid = ex_to<numeric>(fxmid_); if (fxmid.is_zero()) { // Luck strikes... return xxmid; } if ((fxmid<0 && fx[side]>0) || (fxmid>0 && fx[side]<0)) { side = !side; } xxprev = xx[side]; fxprev = fx[side]; xx[side] = xxmid; fx[side] = fxmid; } } while (xxprev!=xx[side]); return xxprev; }