def get_fxi(a,mu1,mu2,cart_state): c4,c3,c2,c1,c0 = get_fxi_cf(a,mu1,mu2,cart_state) def retval(xi): return polyval([c4,c3,c2,c1,c0],xi) def retval_p(xi): return polyval([4*c4,3*c3,2*c2,c1],xi) def retval_pp(xi): return polyval([4*3*c4,3*2*c3,2*c2],xi) return retval,retval_p,retval_pp,polyroots([c4,c3,c2,c1,c0]),polyroots([4*c4,3*c3,2*c2,c1])
def get_feta(a,mu1,mu2,cart_state): c4,c3,c2,c1,c0 = get_feta_cf(a,mu1,mu2,cart_state) def retval(eta): return polyval([c4,c3,c2,c1,c0],eta) def retval_p(eta): return polyval([4*c4,3*c3,2*c2,c1],eta) def retval_pp(eta): return polyval([4*3*c4,3*2*c3,2*c2],eta) return retval,retval_p,retval_pp,polyroots([c4,c3,c2,c1,c0]),polyroots([4*c4,3*c3,2*c2,c1])
def process(seed, K): """ K is model order / number of zeros """ # create the dirac locations with many, many points rng = np.random.RandomState(seed) tk = np.sort(rng.rand(K)*period) # true zeros uk = np.exp(-1j*2*np.pi*tk/period) coef_poly = poly.polyfromroots(uk) # more accurate than np.poly # estimate zeros uk_hat = np.roots(np.flipud(coef_poly)) uk_hat_poly = poly.polyroots(coef_poly) uk_hat_mpmath = mpmath.polyroots(np.flipud(coef_poly), maxsteps=100, cleanup=True, error=False, extraprec=50) # compute error min_dev_norm = distance(uk, uk_hat)[0] _err_roots = 20*np.log10(np.linalg.norm(uk)/min_dev_norm) min_dev_norm = distance(uk, uk_hat_poly)[0] _err_poly = 20*np.log10(np.linalg.norm(uk)/min_dev_norm) # for mpmath, need to compute error with its precision uk = np.sort(uk) uk_mpmath = [mpmath.mpc(z) for z in uk] uk_hat_mpmath = sorted(uk_hat_mpmath, key=cmp_to_key(compare_mpc)) dev = [uk_mpmath[k] - uk_hat_mpmath[k] for k in range(len(uk_mpmath))] _err_mpmath = 20*mpmath.log(mpmath.norm(uk_mpmath) / mpmath.norm(dev), b=10) return _err_roots, _err_poly, _err_mpmath
def getNthKFibonacciNumber( n, k ): if real( n ) < 0: raise ValueError( 'non-negative argument expected' ) if real( k ) < 2: raise ValueError( 'argument <= 2 expected' ) if n < k - 1: return 0 nth = int( n ) + 4 precision = int( fdiv( fmul( n, k ), 8 ) ) if ( mp.dps < precision ): mp.dps = precision poly = [ 1 ] poly.extend( [ -1 ] * int( k ) ) roots = polyroots( poly ) nthPoly = getNthFibonacciPolynomial( k ) result = 0 exponent = fsum( [ nth, fneg( k ), -2 ] ) for i in range( 0, int( k ) ): result += fdiv( power( roots[ i ], exponent ), polyval( nthPoly, roots[ i ] ) ) return floor( fadd( re( result ), fdiv( 1, 2 ) ) )
def polynomial_to_roots(polynomial): try: return [ np.conjugate(complex(root)) for root in mpmath.polyroots(polynomial) ] except: return [complex(0, 0) for i in range(len(polynomial) - 1)]
def polynomial_C(polynomial): try: roots = [ np.conjugate(complex(root)) for root in mpmath.polyroots(polynomial) ] except: return [float('Inf') for i in range(len(polynomial) - 1)] return roots
def mp_log_integral_exp(log_func, theta): x_lbound, x_ubound = config.logpoly.x_lbound, config.logpoly.x_ubound k = theta.size - 1 derivative_poly_coeffs = np.flip(theta[1:] * np.arange(1, k + 1)) if config.logpoly.verbose: print(' poly_roots start') sys.stdout.flush() # r = np.roots(derivative_poly_coeffs) # r = r.real[np.abs(r.imag) < 1e-10] # r = np.unique(r[(r >= x_lbound) & (r <= x_ubound)]) # r = np.array([mpf(r_i) for r_i in r]) _tmp_ind = derivative_poly_coeffs != 0 if not np.any(_tmp_ind): r = np.array([]) else: derivative_poly_coeffs = derivative_poly_coeffs[np.argmax(_tmp_ind):] r = mpmath.polyroots(derivative_poly_coeffs, maxsteps=500, extraprec=mpmath.mp.dps) r = np.array([r_i for r_i in r if isinstance(r_i, mpf)]) r = np.unique(r[(r >= x_lbound) & (r <= x_ubound)]) if config.logpoly.verbose: print(' poly_roots finish') sys.stdout.flush() if r.size > 0: br_points = np.unique( np.concatenate([ np.array([mpf(x_lbound)]), r.reshape([-1]), np.array([mpf(x_ubound)]) ])) else: br_points = np.array([mpf(x_lbound), mpf(x_ubound)]) buff = np.array([mpf(0) for _ in range(br_points.size - 1)]) for i in range(br_points.size - 1): p1 = br_points[i] p2 = br_points[i + 1] l = p2 - p1 parts = config.logpoly.mp_log_integral_exp_parts delta = l / parts points = np.arange(p1, p2, delta) if len(points) < parts + 1: points = np.concatenate([points, [p2]]) f = log_func(points, theta) f = np.concatenate([f, f[1:-1]]) buff[i] = mp_log_sum_exp(f) + mpmath.log(l / parts) - mpmath.log(2) return mp_log_sum_exp(buff), r
def solvePolynomial( args ): '''Uses the mpmath solve function to numerically solve an arbitrary polynomial.''' if isinstance( args, RPNGenerator ): args = list( args ) elif not isinstance( args, list ): args = [ args ] while args[ 0 ] == 0: args = args[ 1 : ] length = len( args ) if length == 0: raise ValueError( 'invalid expression, no variable coefficients' ) if length < 2: raise ValueError( "'solve' requires at least an order-1 polynomial (i.e., 2 terms)" ) nonZeroes = 0 nonZeroIndex = 0 for i in range( 0, length ): if args[ i ] != 0: nonZeroes += 1 nonZeroIndex = i if nonZeroes == 1 and nonZeroIndex == length - 1: raise ValueError( 'invalid expression, no variable coefficients' ) if nonZeroes == 1: return [ 0 ] * ( length - nonZeroIndex - 1 ) try: result = polyroots( args ) except libmp.libhyper.NoConvergence: try: # Let's try again, really hard! result = polyroots( args, maxsteps = 2000, extraprec = 5000 ) except libmp.libhyper.NoConvergence: raise ValueError( 'polynomial failed to converge' ) return result
def solvePolynomialOperator( args ): '''Uses the mpmath solve function to numerically solve an arbitrary polynomial.''' if isinstance( args, RPNGenerator ): args = list( args ) elif not isinstance( args, list ): args = [ args ] while args[ 0 ] == 0: args = args[ 1 : ] length = len( args ) if length == 0: raise ValueError( 'invalid expression, no variable coefficients' ) if length < 2: raise ValueError( "'solve' requires at least an order-1 polynomial (i.e., 2 terms)" ) nonZeroes = 0 nonZeroIndex = 0 for i in range( 0, length ): if args[ i ] != 0: nonZeroes += 1 nonZeroIndex = i if nonZeroes == 1 and nonZeroIndex == length - 1: raise ValueError( 'invalid expression, no variable coefficients' ) if nonZeroes == 1: return [ 0 ] * ( length - nonZeroIndex - 1 ) try: result = polyroots( args ) except libmp.libhyper.NoConvergence: try: # Let's try again, really hard! result = polyroots( args, maxsteps = 2000, extraprec = 5000 ) except libmp.libhyper.NoConvergence: raise ValueError( 'polynomial failed to converge' ) return result
def get_roots(real=None, imag=None): if real is None: real = random_coeffs(N) if imag is None: imag = random_coeffs(N) coeffs = real + imag * 1j # p = mp.polyroots(coeffs, maxsteps=100, extraprec=110) p = mp.polyroots(coeffs, maxsteps=50, extraprec=20) p = [[float(z.real), float(z.imag)] for z in p] return np.array(p)
def eigen(M,dic,order): M1 = M.xreplace(dic) with mp.workdps(int(mp.mp.dps*2)): M1 = M1.evalf(mp.mp.dps) det =(M1).det(method = 'berkowitz') detp = Poly(det,kz) co = detp.all_coeffs() co = [mp.mpc(str(re(k)),str(im(k))) for k in co] maxsteps = 3000 extraprec = 500 ok =0 while ok == 0: try: sol,err = mp.polyroots(co,maxsteps =maxsteps,extraprec = extraprec,error =True) sol = np.array(sol) print("Error on polyroots =", err) ok=1 except: maxsteps = int(maxsteps*2) extraprec = int(extraprec*1.5) print("Poly roots fail precision increased: ",maxsteps,extraprec) te = np.array([mp.fabs(m) < mp.mpf(10**mp.mp.dps) for m in sol]) solr = sol[te] if Bound_nb == 1: solr = solr[[mp.im(m) < 0 for m in solr]] eigen1 = np.empty((len(solr),np.shape(M1)[0]),dtype = object) with mp.workdps(int(mp.mp.dps*2)): for i in range(len(solr)): M2 = mpmathM(M1.xreplace({kz:solr[i]})) eigen1[i] = null_space(M2) solr1 = solr div = [mp.fabs(x) for x in (order*kxl.xreplace(dic)*eigen1[:,4]+order*kyl.xreplace(dic)*eigen1[:,5]+solr1*eigen1[:,6])] testdivB = [mp.almosteq(x,0,10**(-(mp.mp.dps/2))) for x in div] eigen1 =eigen1[testdivB] solr1 = solr1[testdivB] if len(solr1) == 3: print("Inviscid semi infinite domain") elif len(solr1) == 6: print("Inviscid 2 boundaries") elif len(solr1) == 5: print("Viscous semi infinite domain") elif len(solr1) == 10: print("Viscous 2 boundaries") else: print("number of solution inconsistent,",len(solr1)) return(solr1,eigen1,M1)
def check(self, f): # reciprocal version of Dimitrov's first comment in https://mathoverflow.net/questions/214962/criteria-for-irreducibility-using-the-location-of-complex-roots import mpmath import sympy const_coeff = f.TC() if const_coeff == 0: return REDUCIBLE, None # constant coeff needs to be in form +-p^d primes = sympy.ntheory.factorint(abs(const_coeff)) if len(primes) != 1: return UNKNOWN, None # extract p p = next(iter(primes.keys())) # linear coefficients must not be divisible by p a1 = get_coeff(f, 1) if a1 % p == 0: return UNKNOWN, None if self.max_p and abs(const_coeff) >= self.max_p: return UNKNOWN, None # check if there are roots inside as well as outside of unit circle try: all = mpmath.polyroots(f.all_coeffs(), maxsteps=100) inside_unit_circle = 0 outside_unit_circle = 0 on_unit_circle = 0 for root in all: root_size = abs(root) if root_size == 1: on_unit_circle += 1 elif root_size < 1: inside_unit_circle += 1 else: outside_unit_circle += 1 if (inside_unit_circle + on_unit_circle == 0): return IRREDUCIBLE, { "inside/on": inside_unit_circle + on_unit_circle, "outside": outside_unit_circle, "p": p } except Exception as e: # could not get complex roots, too bad pass return UNKNOWN, None
def pade_propagator_coefs(*, pade_order, diff2, k0, dx, spe=False, alpha=0): """ :param pade_order: order of Pade approximation, tuple, for ex (7, 8) :param diff2: :param k0: :param dx: :param spe: :param alpha: rotation angle, see F. A. Milinazzo et. al. Rational square-root approximations for parabolic equation algorithms. 1997. Acoustical Society of America. :return: """ mpmath.mp.dps = 63 if spe: def sqrt_1plus(x): return 1 + x / 2 elif alpha == 0: def sqrt_1plus(x): return mpmath.mp.sqrt(1 + x) else: a_n, b_n = pade_sqrt_coefs(pade_order[1]) def sqrt_1plus(x): return pade_sqrt(x, a_n, b_n, alpha) def propagator_func(s): return mpmath.mp.exp(1j * k0 * dx * (sqrt_1plus(diff2(s)) - 1)) t = mpmath.taylor(propagator_func, 0, pade_order[0] + pade_order[1] + 2) p, q = mpmath.pade(t, pade_order[0], pade_order[1]) pade_coefs = list( zip_longest([ -1 / complex(v) for v in mpmath.polyroots(p[::-1], maxsteps=2000) ], [-1 / complex(v) for v in mpmath.polyroots(q[::-1], maxsteps=2000)], fillvalue=0.0j)) return pade_coefs
def solvePolynomial( args ): if isinstance( args, RPNGenerator ): args = list( args ) elif not isinstance( args, list ): args = [ args ] while args[ 0 ] == 0: args = args[ 1 : ] length = len( args ) if length == 0: raise ValueError( 'invalid expression, no variable coefficients' ) if length < 2: raise ValueError( "'solve' requires at least an order-1 polynomial (i.e., 2 terms)" ) nonZeroes = 0 nonZeroIndex = 0 for i in range( 0, length ): if args[ i ] != 0: nonZeroes += 1 nonZeroIndex = i if nonZeroes == 1 and nonZeroIndex == length - 1: raise ValueError( 'invalid expression, no variable coefficients' ) if nonZeroes == 1: return [ 0 ] * ( length - nonZeroIndex - 1 ) try: result = polyroots( args ) except libmp.libhyper.NoConvergence: result = polyroots( args, maxsteps = 100, extraprec = 20 ) return result
def check(self, f): import mpmath import sympy const_coeff = f.TC() if const_coeff == 0: return REDUCIBLE, None # const coefficient needs to be prime if not sympy.isprime(abs(const_coeff)): return UNKNOWN, None if self.max_p and abs(const_coeff) >= self.max_p: return UNKNOWN, None # need to be monic lead_coeff = f.LC() if lead_coeff != 1: return UNKNOWN, None # check if there are roots inside as well as outside of unit circle try: all = mpmath.polyroots(f.all_coeffs(), maxsteps=100) inside_unit_circle = 0 outside_unit_circle = 0 on_unit_circle = 0 for root in all: root_size = abs(root) if root_size == 1: on_unit_circle += 1 elif root_size < 1: inside_unit_circle += 1 else: outside_unit_circle += 1 if (inside_unit_circle + on_unit_circle == 0) or (outside_unit_circle == 0): return IRREDUCIBLE, { "inside/on": inside_unit_circle + on_unit_circle, "outside": outside_unit_circle, "p": const_coeff } except mpmath.libmp.libhyper.NoConvergence as e: # could not get complex roots, too bad pass return UNKNOWN, None
def check(self, f): # Polynomials - Prasolov - Theorem 2.2.7 ([Os1]) part b) lead_coeff = f.LC() if lead_coeff != 1: return UNKNOWN, None const_coeff = abs(f.TC()) if not sympy.isprime(const_coeff): return UNKNOWN, None if self.max_p and const_coeff >= self.max_p: return UNKNOWN, None s = 0 for exp, coeff in poly_non_zero_exps(f): if exp != f.degree() and exp != 0: s += abs(coeff) if const_coeff < 1 + s: return UNKNOWN, None import mpmath # check if there are roots inside as well as outside of unit circle try: all = mpmath.polyroots(f.all_coeffs(), maxsteps=100) inside_unit_circle = 0 outside_unit_circle = 0 on_unit_circle = 0 for root in all: root_size = abs(root) if root_size == 1: on_unit_circle += 1 elif root_size < 1: inside_unit_circle += 1 else: outside_unit_circle += 1 if on_unit_circle == 0: return IRREDUCIBLE, {'s': const_coeff, "on": on_unit_circle} except mpmath.libmp.libhyper.NoConvergence: # could not get complex roots, too bad pass return UNKNOWN, None
def polynomial_C(polynomial): zeros = 0 for i in range(len(polynomial)): if polynomial[i] == 0: zeros += 1 else: break poles = [float('Inf') for i in range(zeros)] try: roots = [complex(root) for root in mpmath.polyroots(polynomial)] except: try: roots = [complex(root) for root in np.roots(polynomial)] except: print(polynomial) roots = [float('Inf') for i in range(len(polynomial) - zeros)] return poles + roots
def generate_roots(self, polly): """ Given a polynomial, cleans it up (removes leading zeros), and generates roots. Returns roots as list of tuples """ polly = np.trim_zeros(polly) # print(polly) if len(polly) < 2: # no roots! return [] try: roots = mpmath.polyroots(polly, extraprec=1000, maxsteps=self.maxsteps) except: self.didnotconverge += 1 return [] return roots
def __cubic_roots(self,a,c,d): from mpmath import mpf, polyroots assert(all([isinstance(_,mpf) for _ in [a,c,d]])) Delta = -4 * a * c*c*c - 27 * a*a * d*d self.__Delta = Delta # NOTE: replace with exact calculation of cubic roots. proots, err = polyroots([a,0,c,d],error=True,maxsteps=100) if Delta < 0: # NOTE: here and below we ignore any residual imaginary part that we know must come from numerical artefacts. # Sort the roots following the convention. proots[1] is the first complex root, proots[0] is the real one. # The complex root with negative imaginary part is e3. if proots[2].imag <= 0: e1,e2,e3 = proots[1],proots[0].real,proots[2] else: e1,e2,e3 = proots[2],proots[0].real,proots[1] else: # The convention in this case is to sort in descending order. e1,e2,e3 = sorted([_.real for _ in proots],reverse = True) return e1,e2,e3
def __cubic_roots(self, a, c, d): from mpmath import mpf, polyroots assert (all([isinstance(_, mpf) for _ in [a, c, d]])) Delta = -4 * a * c * c * c - 27 * a * a * d * d self.__Delta = Delta # NOTE: replace with exact calculation of cubic roots. proots, err = polyroots([a, 0, c, d], error=True, maxsteps=100) if Delta < 0: # NOTE: here and below we ignore any residual imaginary part that we know must come from numerical artefacts. # Sort the roots following the convention. proots[1] is the first complex root, proots[0] is the real one. # The complex root with negative imaginary part is e3. if proots[2].imag <= 0: e1, e2, e3 = proots[1], proots[0].real, proots[2] else: e1, e2, e3 = proots[2], proots[0].real, proots[1] else: # The convention in this case is to sort in descending order. e1, e2, e3 = sorted([_.real for _ in proots], reverse=True) return e1, e2, e3
def test_poly(): output("""\ poly_:{ r:{$[prec>=abs(x:reim x)1;x 0;x]} each .qml.poly x; r iasc {x:reim x;(abs x 1;neg x 1;x 0)} each r};""") for A in poly_subjects: A = sp.Poly(A, sp.Symbol("x")) if A.degree() <= 3 and all(a.is_real for a in A.all_coeffs()): R = [] for r in sp.roots(A, multiple=True): r = sp.simplify(sp.expand_complex(r)) R.append(r) R.sort(key=lambda x: (abs(sp.im(x)), -sp.im(x), sp.re(x))) else: R = mp.polyroots([mp.mpc(*(a.evalf(mp.mp.dps)).as_real_imag()) for a in A.all_coeffs()]) R.sort(key=lambda x: (abs(x.imag), -x.imag, x.real)) assert len(R) == A.degree() test("poly_", A.all_coeffs(), R, complex_pair=True)
def plot_phase_line(a,b,c,d,e): from mpmath import polyroots, sqrt, polyval from numpy import linspace from pylab import plot, xlim, xticks, yticks, grid, xlabel, ylabel assert(a < 0) p4roots, err = polyroots([a,b,c,d,e],error = True, maxsteps = 1000) real_roots = filter(lambda x: x.imag == 0,p4roots) assert(len(real_roots) == 2 or len(real_roots) == 4) print(real_roots) # Left and right padding for the plot. lr_pad = (real_roots[-1] - real_roots[0]) / 10 # This is the plotting function. def func(x): retval = sqrt(polyval([a,b,c,d,e],x)) if retval.imag == 0: return retval else: return float('nan') func_m = lambda x: -func(x) def plot_lobe(start,end,f): delta = (end - start) / 100 rng = linspace(start + delta,end - delta,1000) plot(rng,[f(x) for x in rng],'k-',linewidth=2) rng = linspace(start,start + delta,1000) plot(rng,[f(x) for x in rng],'k-',linewidth=2) rng = linspace(end - delta,end,1000) plot(rng,[f(x) for x in rng],'k-',linewidth=2) if len(real_roots) == 2: plot_lobe(real_roots[0],real_roots[1],func) plot_lobe(real_roots[0],real_roots[1],func_m) else: plot_lobe(real_roots[0],real_roots[1],func) plot_lobe(real_roots[0],real_roots[1],func_m) plot_lobe(real_roots[2],real_roots[3],func) plot_lobe(real_roots[2],real_roots[3],func_m) xlim(float(real_roots[0] - lr_pad),float(real_roots[-1] + lr_pad)) xticks([0],['']) yticks([0],['']) grid() xlabel(r'$H$') ylabel(r'$dH/dt$')
def gauss_lobatto_points(start, stop, num_points): """Get the node points for Gauss-Lobatto quadrature. Rather than using the optimizations in :func:`.dg1.gauss_lobatto_points`, this uses :mod:`mpmath` utilities directly to find the roots of :math:`P_n'(x)` (where :math:`n` is equal to ``num_points - 1``). :type start: :class:`mpmath.mpf` (or ``float``) :param start: The beginning of the interval. :type stop: :class:`mpmath.mpf` (or ``float``) :param stop: The end of the interval. :type num_points: int :param num_points: The number of points to use. :rtype: :class:`numpy.ndarray` :returns: 1D array, the interior quadrature nodes. """ def leg_poly(value): """Legendre polynomial :math:`P_n(x)`.""" return mpmath.legendre(num_points - 1, value) def leg_poly_diff(value): """Legendre polynomial derivative :math:`P_n'(x)`.""" return mpmath.diff(leg_poly, value) poly_coeffs = mpmath.taylor(leg_poly_diff, 0, num_points - 2)[::-1] inner_roots = mpmath.polyroots(poly_coeffs) # Create result. start = mpmath.mpf(start) stop = mpmath.mpf(stop) result = [start] # Convert the inner nodes to the interval at hand. half_width = (stop - start) / 2 for index in six.moves.xrange(num_points - 2): result.append(start + (inner_roots[index] + 1) * half_width) result.append(stop) return np.array(result)
def __init__(self, n): self.n = n mpmath.mp.dps = 100 def func(x): return mpmath.exp(-x) * mpmath.besseli(0, x) t = mpmath.taylor(func, 0, 2 * n + 1) self.p, self.q = mpmath.pade(t, n, n) # self.pade_coefs = list(zip_longest([-1 / complex(v) for v in mpmath.polyroots(p[::-1], maxsteps=2000)], # [-1 / complex(v) for v in mpmath.polyroots(q[::-1], maxsteps=2000)], # fillvalue=0.0j)) #self.pade_roots_num = [complex(v) for v in mpmath.polyroots(self.p[::-1], maxsteps=5000)] #self.pade_roots_den = [complex(v) for v in mpmath.polyroots(self.q[::-1], maxsteps=5000)] self.pade_coefs_num = [complex(v) for v in self.p] self.pade_coefs_den = [complex(v) for v in self.q] self.taylor_coefs = [complex(v) for v in t] a = [self.q[-1]] + [b + c for b, c in zip(self.q[:-1:], self.p)] self.a_roots = [ complex(v) for v in mpmath.polyroots(a[::-1], maxsteps=5000) ]
def test_poly(): output("""\ poly_:{ r:{$[prec>=abs(x:reim x)1;x 0;x]} each .qml.poly x; r iasc {x:reim x;(abs x 1;neg x 1;x 0)} each r};""") for A in poly_subjects: A = sp.Poly(A, sp.Symbol("x")) if A.degree() <= 3 and all(a.is_real for a in A.all_coeffs()): R = [] for r in sp.roots(A, multiple=True): r = sp.simplify(sp.expand_complex(r)) R.append(r) R.sort(key=lambda x: (abs(sp.im(x)), -sp.im(x), sp.re(x))) else: R = mp.polyroots([ mp.mpc(*(a.evalf(mp.mp.dps)).as_real_imag()) for a in A.all_coeffs() ]) R.sort(key=lambda x: (abs(x.imag), -x.imag, x.real)) assert len(R) == A.degree() test("poly_", A.all_coeffs(), R, complex_pair=True)
def check(self, f): # see question body in https://mathoverflow.net/questions/214962/criteria-for-irreducibility-using-the-location-of-complex-roots import mpmath const_coeff = f.TC() if const_coeff == 0: return REDUCIBLE, None # need to be monic lead_coeff = f.LC() if lead_coeff != 1: return UNKNOWN, None # check if there are roots inside as well as outside of unit circle try: all = mpmath.polyroots(f.all_coeffs(), maxsteps=100) inside_unit_circle = 0 outside_unit_circle = 0 on_unit_circle = 0 for root in all: root_size = abs(root) if root_size == 1: on_unit_circle += 1 elif root_size < 1: inside_unit_circle += 1 else: outside_unit_circle += 1 if (outside_unit_circle + on_unit_circle == 1): return IRREDUCIBLE, { "inside": inside_unit_circle, "outside/on": outside_unit_circle + on_unit_circle } except mpmath.libmp.libhyper.NoConvergence as e: # could not get complex roots, too bad pass return UNKNOWN, None
def __set_params(self,d): from copy import deepcopy from mpmath import mpf, sqrt, polyroots, cos, acos, pi, mp from weierstrass_elliptic import weierstrass_elliptic as we names = ['m2','r2','rot2','r1','rot1','i_a','ht','a','e','i','h'] if not all([s in d for s in names]): raise ValueError('invalid set of parameters') # Convert all the values to mpf and introduce convenience shortcuts. m2, r2, rot2, r1, rot1, i_a, ht_in, a, e, i, h_in = [mpf(d[s]) for s in names] L_in = sqrt(self.__GG_val * m2 * a) G_in = L_in * sqrt(1. - e**2) H_in = G_in * cos(i) Gt_in = (2 * r1**2 * rot1) / 5 Ht_in = Gt_in * cos(i_a) Hts_in = H_in + Ht_in hs_in = h_in - ht_in Gxy_in = sqrt(G_in**2 - H_in**2) Gtxys_in = sqrt(Gt_in**2 - Ht_in**2) J2 = (2 * m2 * r2**2 * rot2) / 5 II_1 = mpf(5) / (2 * r1**2) # Evaluation dictionary. eval_names = ['L','G','H','\\tilde{G}','\\tilde{H}_\\ast','h_\\ast','\\tilde{G}_{xy\\ast}','m_2','\\mathcal{G}','J_2','G_{xy}',\ '\\varepsilon','\\mathcal{I}_1'] eval_values = [L_in,G_in,H_in,Gt_in,Hts_in,hs_in,Gtxys_in,m2,self.__GG_val,J2,Gxy_in,self.__eps_val,II_1] d_eval = dict(zip(eval_names,eval_values)) # Evaluate Hamiltonian with initial conditions. HHp_val = self.__HHp.trim().evaluate(d_eval) # Add the value of the Hamiltonian to the eval dictionary. d_eval['\\mathcal{H}^\\prime'] = HHp_val # Evaluate g2 and g3. g2_val, g3_val = self.__g2.trim().evaluate(d_eval), self.__g3.trim().evaluate(d_eval) # Create the Weierstrass object. wp = we(g2_val,g3_val) # Store the period. self.__wp_period = wp.periods[0] # Now let's find the roots of the quartic polynomial. # NOTE: in theory here we could use the exact solution for the quartic. p4coeffs = [t[0] * t[1].trim().evaluate(d_eval) for t in zip([1,4,6,4,1],self.__f4_cf)] p4roots, err = polyroots(p4coeffs,error = True, maxsteps = 1000) # Find a reachable root. Hr, H_max, n_lobes, lobe_idx = self.__reachable_root(p4roots,H_in) # Determine t_r t_r = self.__compute_t_r(n_lobes,lobe_idx,H_in,Hr,d_eval,p4roots,p4coeffs[0]) # Now evaluate the derivatives of the polynomial. We will need to replace H_in with Hr in the eval dict. d_eval['H'] = Hr _, f4Hp, f4Hpp, _, _ = self.__f4 f4p_eval = f4Hp.trim().evaluate(d_eval) f4pp_eval = f4Hpp.trim().evaluate(d_eval) # Build and store the expression for H(t). self.__H_time = lambda t: Hr + f4p_eval / (4 * (wp.P(t - t_r) - f4pp_eval / 24)) # H will not be needed any more, replace with H_r del d_eval['H'] d_eval['H_r'] = Hr # Inject the invariants and the other two constants into the evaluation dictionary. d_eval['g_2'] = g2_val d_eval['g_3'] = g3_val d_eval['A'] = f4p_eval / 4 d_eval['B'] = f4pp_eval / 24 # Verify the formulae in solutions.py self.__verify_solutions(d_eval) # Assuming g = 0 as initial angle. self.__g_time = spin_gr_theory.__get_g_time(d_eval,t_r,0.) self.__hs_time = spin_gr_theory.__get_hs_time(d_eval,t_r,hs_in) self.__ht_time = spin_gr_theory.__get_ht_time(d_eval,t_r,ht_in) def obliquity(t): from mpmath import acos, cos, sqrt H = self.__H_time(t) hs = self.__hs_time(t) G = d_eval['G'] Gt = d_eval['\\tilde{G}'] Hts = d_eval['\\tilde{H}_\\ast'] Gxy = sqrt(G**2-H**2) Gtxys = sqrt(Gt**2-(Hts-H)**2) retval = (Gxy*Gtxys*cos(hs)+H*(Hts-H))/(G*Gt) return acos(retval) self.__obliquity_time = obliquity def spin_vector(t): import numpy ht = self.__ht_time(t) H = self.__H_time(t) G = d_eval['G'] Gt = d_eval['\\tilde{G}'] Hts = d_eval['\\tilde{H}_\\ast'] Gtxys = sqrt(Gt**2-(Hts-H)**2) return numpy.array([x.real for x in [Gtxys*sin(ht),-Gtxys*cos(ht),Hts-H]]) self.__spin_vector_time = spin_vector def orbit_vector(t): import numpy ht = self.__ht_time(t) hs = self.__hs_time(t) h = hs + ht H = self.__H_time(t) G = d_eval['G'] Gxy = sqrt(G**2-H**2) return numpy.array([x.real for x in [Gxy*sin(h),-Gxy*cos(h),H]]) self.__orbit_vector_time = orbit_vector # Store the params of the system. self.__params = dict(zip(names,[mpf(d[s]) for s in names])) # Final report. rad_conv = 360 / (2 * pi()) print("\x1b[31mAccuracy in the identification of the poly roots:\x1b[0m") print(err) print("\n\x1b[31mPeriod (years):\x1b[0m") print(wp.periods[0] / (3600*24*365)) print("\n\x1b[31mMin and max orbital inclination (deg):\x1b[0m") print(acos(Hr/G_in) * rad_conv,acos(H_max/G_in) * rad_conv) print("\n\x1b[31mMin and max axial inclination (deg):\x1b[0m") print(acos((Hts_in - Hr)/Gt_in) * rad_conv,acos((Hts_in-H_max)/Gt_in) * rad_conv) print("\n\x1b[31mNumber of lobes:\x1b[0m " + str(n_lobes)) print("\n\x1b[31mLobe idx:\x1b[0m " + str(lobe_idx)) # Report the known results for simplified system for comparison. H = H_in HHp,G,L,GG,eps,m2,Hts,Gt,J2 = [d_eval[s] for s in ['\\mathcal{H}^\\prime','G','L','\\mathcal{G}',\ '\\varepsilon','m_2','\\tilde{H}_\\ast','\\tilde{G}','J_2']] print("\n\x1b[31mEinstein (g):\x1b[0m " + str((3 * eps * GG**4 * m2**4/(G**2*L**3)))) print("\n\x1b[31mLense-Thirring (g):\x1b[0m " + str(((eps * ((-6*H*J2*GG**4*m2**3)/(G**4*L**3)+3*GG**4*m2**4/(G**2*L**3)))))) print("\n\x1b[31mLense-Thirring (h):\x1b[0m " + str((2*eps*J2*GG**4*m2**3/(G**3*L**3)))) # These are the Delta_ constants of quasi-periodicity. f_period = self.wp_period print("\n\x1b[31mDelta_g:\x1b[0m " + str(self.g_time(f_period) - self.g_time(0))) print("\n\x1b[31mg_rate:\x1b[0m " + str((self.g_time(f_period) - self.g_time(0))/f_period)) Delta_hs = self.hs_time(f_period) - self.hs_time(0) print("\n\x1b[31mDelta_hs:\x1b[0m " + str(Delta_hs)) print("\n\x1b[31mhs_rate:\x1b[0m " + str(Delta_hs/f_period)) Delta_ht = self.ht_time(f_period) - self.ht_time(0) print("\n\x1b[31mDelta_ht:\x1b[0m " + str(Delta_ht)) print("\n\x1b[31mht_rate:\x1b[0m " + str(Delta_ht/f_period)) print("\n\x1b[31mDelta_h:\x1b[0m " + str(Delta_ht+Delta_hs)) print("\n\x1b[31mh_rate:\x1b[0m " + str((Delta_ht+Delta_hs)/f_period)) print("\n\n")
def solve_scattering_equations(n, dict_ss): """Solves the scattering equations given multiplicity and mandelstams.""" if n == 3: return [{}] Mn = M(n) zs = punctures(n) num_coeffs = numerical_coeffs(Mn, n, dict_ss) roots = mpmath.polyroots(num_coeffs, maxsteps=10000, extraprec=300) sols = [{str(zs[-2]): root * zs[-3]} for root in roots] if n == 4: sols = [{ str(zs[-2]): mpmath.mpc(sympy.simplify(sols[0][str(zs[-2])].subs({zs[1]: 1}))) }] else: Mnew = copy.deepcopy(Mn) Mnew[:, 0] += Mnew[:, 1] * zs[1] Mnew.col_del(1) Mnew.row_del(-1) # subs sol = sols[0] Mnew = Mnew.tolist() Mnew = [[ _zs_sub(_ss_sub(str(entry))).replace( "dict_zs['z{}']".format(n - 1), "dict_zs['z{}'] * mpmath.mpc(sol[str(zs[-2])] / zs[-3])". format(n - 2)) for entry in line ] for line in Mnew] # get scaling if n == 5: scaling = 0 elif n == 6: scaling = 2 elif n == 7: scaling = 17 else: # computing from scratch, should work for any multiplicity in principle dict_zs = {str(zs[-3]): 10**-100, str(zs[1]): 1} nMn = mpmath.matrix([[eval(entry, None) for entry in line] for line in Mnew]) a = mpmath.det(nMn) dict_zs = {str(zs[-3]): 10**-101, str(zs[1]): 1} nMn = mpmath.matrix([[eval(entry, None) for entry in line] for line in Mnew]) b = mpmath.det(nMn) scaling = -round(mpmath.log(abs(b) / abs(a)) / mpmath.log(10)) assert (abs( round(mpmath.log(abs(b) / abs(a)) / mpmath.log(10)) - mpmath.log(abs(b) / abs(a)) / mpmath.log(10)) < 10**-30) # solve the linear equations for i in range(1, n - 3): Mnew = copy.deepcopy(Mn) index = V(n).index(zs[i]) Mnew[:, 0] += Mnew[:, index] * zs[i] Mnew.col_del(index) Mnew.row_del(-1) Mnew = Mnew.tolist() if i == 1: Mnew = [[ _zs_sub(_ss_sub(str(entry))).replace( "dict_zs['z{}']".format(n - 1), "dict_zs['z{}'] * mpmath.mpc(sol[str(zs[-2])] / zs[-3])" .format(n - 2)) for entry in line ] for line in Mnew] for sol in sols: A = [[value**exponent for exponent in [1, 0]] for value in [-1, 1]] b = [] for value in [-1, 1]: dict_zs = {str(zs[-3]): value, str(zs[1]): 1} nMn = mpmath.matrix( [[eval(entry, None) for entry in line] for line in Mnew]) b += [mpmath.det(nMn) / (value**scaling)] coeffs = mpmath.lu_solve(A, b).T.tolist()[0] sol[str(zs[-3])] = -coeffs[1] / coeffs[0] sol[str(zs[-2])] = mpmath.mpc((sympy.simplify(sol[str( zs[-2])].subs({zs[-3]: sol[str(zs[-3])]})))) else: Mnew = [[_zs_sub(_ss_sub(str(entry))) for entry in line] for line in Mnew] for sol in sols: A = [[value**exponent for exponent in [1, 0]] for value in [-1, 1]] b = [] for value in [-1, 1]: dict_zs = { str(zs[i]): value, str(zs[-3]): sol[str(zs[-3])], str(zs[-2]): sol[str(zs[-2])] } # noqa --- used in eval function nMn = mpmath.matrix( [[eval(entry, None) for entry in line] for line in Mnew]) b += [mpmath.det(nMn)] coeffs = mpmath.lu_solve(A, b).T.tolist()[0] sol[str(zs[i])] = -coeffs[1] / coeffs[0] return sols
def __init__(self, eps, x0, v0): from numpy import dot from mpmath import polyroots, mpf, mpc, sqrt, atan2, polyval from weierstrass_elliptic import weierstrass_elliptic as we if eps <= 0: raise ValueError('thrust must be strictly positive') eps = mpf(eps) # Unitary grav. parameter. mu = mpf(1.) x, y, z = [mpf(x) for x in x0] vx, vy, vz = [mpf(v) for v in v0] r = sqrt(x**2 + y**2 + z**2) xi = sqrt(r + z) eta = sqrt(r - z) phi = atan2(y, x) vr = dot(v0, x0) / r vxi = (vr + vz) / (2 * sqrt(r + z)) veta = (vr - vz) / (2 * sqrt(r - z)) vphi = (vy * x - vx * y) / (x**2 + y**2) pxi = (xi**2 + eta**2) * vxi peta = (xi**2 + eta**2) * veta pphi = xi**2 * eta**2 * vphi if pphi == 0: raise ValueError('bidimensional case') # Energy constant. h = (pxi**2 + peta**2) / (2 * (xi**2 + eta**2)) + pphi**2 / ( 2 * xi**2 * eta**2) - (2 * mu) / (xi**2 + eta**2) - eps * (xi**2 - eta**2) / 2 # Alpha constants. alpha1 = -eps * xi**4 / 2 - h * xi**2 + pxi**2 / 2 + pphi**2 / (2 * xi**2) alpha2 = eps * eta**4 / 2 - h * eta**2 + peta**2 / 2 + pphi**2 / ( 2 * eta**2) # Analysis of the cubic polynomials in the equations for pxi and peta. roots_xi, _ = polyroots([8 * eps, 8 * h, 4 * alpha1, -pphi**2], error=True, maxsteps=100) roots_eta, _ = polyroots([-8 * eps, 8 * h, 4 * alpha2, -pphi**2], error=True, maxsteps=100) # NOTE: these are all paranoia checks that could go away if we used the exact cubic formula. if not (all([isinstance(x, mpf) for x in roots_xi]) or (isinstance(roots_xi[0], mpf) and isinstance(roots_xi[1], mpc) and isinstance(roots_xi[2], mpc))): raise ValueError('invalid xi roots detected: ' + str(roots_xi)) if not (all([isinstance(x, mpf) for x in roots_eta]) or (isinstance(roots_eta[0], mpf) and isinstance( roots_eta[1], mpc) and isinstance(roots_eta[2], mpc))): raise ValueError('invalid eta roots detected: ' + str(roots_eta)) # For xi we need to understand which of the real positive roots will be or was reached # given the initial condition. rp_roots_extract = lambda x: isinstance(x, mpf) and x > 0 rp_roots_xi = [sqrt(2 * _) for _ in filter(rp_roots_extract, roots_xi)] rp_roots_eta = [ sqrt(2. * _) for _ in filter(rp_roots_extract, roots_eta) ] # Paranoia. if not len(rp_roots_xi) in [1, 3]: raise ValueError('invalid xi roots detected: ' + str(roots_xi)) if len(rp_roots_eta) != 2: raise ValueError('invalid eta roots detected: ' + str(roots_eta)) # We choose as reachable/reached roots always those corresponding to the "pericentre" # for the two coordinates. if len(rp_roots_xi) == 1: # Here there's really no choice, only 1 root available. rr_xi = rp_roots_xi[0] else: # If motion is unbound, take the only root, otherwise take the smallest of the # two roots of the bound motion. rr_xi = rp_roots_xi[-1] if xi >= rp_roots_xi[-1] else rp_roots_xi[0] # No choice to be made here. rr_eta = rp_roots_eta[0] # Store parameters and constants. self.__init_coordinates = [xi, eta, phi] self.__init_momenta = [pxi, peta, pphi] self.__eps = eps self.__h = h self.__alpha1 = alpha1 self.__alpha2 = alpha2 self.__rp_roots_xi = rp_roots_xi self.__rp_roots_eta = rp_roots_eta self.__rr_xi = rr_xi self.__rr_eta = rr_eta self.__roots_xi = roots_xi self.__roots_eta = roots_eta # Create the Weierstrass objects for xi and eta. a1, a2, a3, a4 = 2 * eps, (4 * h) / 3, alpha1, -pphi**2 g2 = -4 * a1 * a3 + 3 * a2**2 g3 = 2 * a1 * a2 * a3 - a2**3 - a1**2 * a4 self.__f_xi = [4 * a1, 6 * a2, 4 * a3, a4] self.__fp_xi = [12 * a1, 12 * a2, 4 * a3] self.__fpp_xi = [24 * a1, 12 * a2] self.__w_xi = we(g2, g3) # Eta. a1, a3 = -a1, alpha2 g2 = -4 * a1 * a3 + 3 * a2**2 g3 = 2 * a1 * a2 * a3 - a2**3 - a1**2 * a4 self.__f_eta = [4 * a1, 6 * a2, 4 * a3, a4] self.__fp_eta = [12 * a1, 12 * a2, 4 * a3] self.__fpp_eta = [24 * a1, 12 * a2] self.__w_eta = we(g2, g3) # Compute the taus. tau_xi = self.__compute_tau_xi() tau_eta = self.__compute_tau_eta() self.__tau_xi = tau_xi self.__tau_eta = tau_eta # Store the real periods. self.__T_xi = self.__w_xi.periods[0] self.__T_eta = self.__w_eta.periods[0] # Delta bound (for debugging). xi_roots = self.__w_xi.roots # Determine the root corresponding to the real half-period. e_R = min(xi_roots, key=lambda x: abs(self.__w_xi.P(self.__T_xi / 2) - x)) self.__Dbound = e_R - polyval(self.__fpp_xi, xi**2 / 2) / 24
def compute_extremum_on_arc(self, col, row, endpoints, interpolation_region): (lb_col, ub_col), (lb_row, ub_row) = interpolation_region alpha = interpolate( self.images.double(), torch.tensor([lb_col, lb_row]).double().to(self.device)) beta = interpolate( self.images.double(), torch.tensor([ub_col, lb_row]).double().to(self.device)) gamma = interpolate( self.images.double(), torch.tensor([lb_col, ub_row]).double().to(self.device)) delta = interpolate( self.images.double(), torch.tensor([ub_col, ub_row]).double().to(self.device)) # a = torch.add( # alpha * ub_col * ub_row - beta * lb_col * ub_row, # delta * lb_col * lb_row - gamma * ub_col * lb_row # ) b = (beta - alpha) * ub_row + (gamma - delta) * lb_row c = (gamma - alpha) * ub_col + (beta - delta) * lb_col d = alpha - beta - gamma + delta e = -b / (2 * d) f = b * b / (4 * d * d) g = c / d h = e * e + f j = (self.delta**2 - h)**2 - 4 * f * e * e k = -2 * g * ((self.delta**2 - h) + 2 * e * e) l = g * g - 4 * ((self.delta**2 - h) + e * e) m = 4 * g n = torch.full_like(m, 4).double().to(self.device) flows = [[ torch.zeros(self.batch_size, self.height, self.width, 2).float().to(self.device) for _ in range(16) ] for channel in range(self.channels)] for batch in range(self.batch_size): for channel in range(self.channels): for height in range(self.height): for width in range(self.width): b_val = b[batch, channel, height, width].item() c_val = c[batch, channel, height, width].item() d_val = d[batch, channel, height, width].item() if math.isclose(d_val, 0, abs_tol=1e-6): if (c_val == 0) or (b_val == 0): continue denominator = math.sqrt(b_val**2 + c_val**2) x = b_val * self.delta / denominator y = c_val * self.delta / denominator flows[channel][0][batch, height, width, 0] = x flows[channel][0][batch, height, width, 1] = y flows[channel][1][batch, height, width, 0] = x flows[channel][1][batch, height, width, 1] = -y flows[channel][2][batch, height, width, 0] = -x flows[channel][2][batch, height, width, 1] = y flows[channel][3][batch, height, width, 0] = -x flows[channel][3][batch, height, width, 1] = -y continue coeffs = [ n[batch, channel, height, width].item(), m[batch, channel, height, width].item(), l[batch, channel, height, width].item(), k[batch, channel, height, width].item(), j[batch, channel, height, width].item() ] roots = polyroots(coeffs, maxsteps=500, extraprec=100) for idx, root in enumerate(roots): root = complex(root) if not math.isclose(root.imag, 0, abs_tol=1e-7): continue x = float(root.real) if self.delta**2 < x**2: continue y = math.sqrt(self.delta**2 - x**2) i = 4 * idx flows[channel][i + 0][batch, height, width, 0] = x flows[channel][i + 0][batch, height, width, 1] = y flows[channel][i + 1][batch, height, width, 0] = x flows[channel][i + 1][batch, height, width, 1] = -y flows[channel][i + 2][batch, height, width, 0] = -x flows[channel][i + 2][batch, height, width, 1] = y flows[channel][i + 3][batch, height, width, 0] = -x flows[channel][i + 3][batch, height, width, 1] = -y for channel in range(self.channels): for idx in range(16): vx = flows[channel][idx][:, :, :, 0] vy = flows[channel][idx][:, :, :, 1] box_col_constraint = (lb_col <= vx) & (vx <= ub_col) box_row_constraint = (lb_row <= vy) & (vy <= ub_row) box_constraint = box_col_constraint & box_row_constraint flows[channel][idx][:, :, :, 0] = torch.where(box_constraint, vx, torch.zeros_like(vx)) flows[channel][idx][:, :, :, 1] = torch.where(box_constraint, vy, torch.zeros_like(vy)) return flows
polysol = np.poly1d(np.array(lsq[::-1])) # deviation from model dev = y - polysol(x) # mad = np.median(np.abs(dev)) / 0.6745 chisq = sum((dev**2) / lc['dmag'][indx]) rchisq = chisq / (len(dev) - deg - 2) # reduced chi sq lsq = all[0] # /[0.1, 10.0, 1000., 10000] covar = all[1] success = all[4] solution = {'sol': polysol, 'deg': deg, 'pars': pars, 'covar': covar} try: root = polyroots(solution['pars'])[0].real except: # what is this exception... continue mjdindex = np.where(solution['sol'](xp) == min(solution['sol'](xp)))[0] # index of max maxjd = np.mean(xp[mjdindex]) # if there are more than one identical maxima - this should make you suspicious anyways maxflux = solution['sol'](maxjd) # mag at max print ("maxjd", maxjd+50000, "maxflux", maxflux) ax.plot(x + 0.5, y, 'o', alpha=0.1, color='k') ax.plot(xp + 0.5, solution['sol'](xp + 0.5), '-', color="k", alpha=0.1) # why + 0.5? I forgot pl.show()
def croots(co): return [mp.mpc(x) for x in mp.polyroots(co)]
def solve_r(pv=False, q=False, t=False, fv=False, annuity_due=False, get=False, q_per_t=False): # docstring ''' Function Description: Solves for interest rates [i,d,v,delta] based on payments described by either pv, q, t, and fv Use get to return a specific interest rate, otherwise function returns a dict of all four based on the output of the function rates(). Calculation assumptions: pv and fv are assumed to be the opposite of q, i.e. if pv = 3, q = 1, and t = 4, then the annuity payment stream is assumed to be either [-3,1,1,1,1] or [3,-1,-1,-1,-1] - both of which return the same interest rate (in this case ~12.6%). t multiplies q, so if t = 2 and q = 1, then the annuity stream is assumed to be [1,1]. However if q = [1,2] and t = 2, then the annuity stream is assumed to be [1,2,1,2]. t has no affect on pv or fv. annuity payments q are evenly spaced for the duration of the annuity. There is no bottom limit to negative interest rates. Variable/argument Description: pv: present value of future funds/first annuity payment made to opposite to q q: annuity payments equally spaced out over time t: the number of times the annuity payments are made. If q is a list and t is passed, then the pattern q is assumed to be repeated t times, all the payments of which are made at evenly spaced intervals. fv: accumulated value of funds/final annuity payment made opposite to q annuity_due: annuity payments are assumed to be immediate, i.e. begin one period t from inception. If that is not the case, i.e. annuity payments begin immediately upon inception, then the annuity due on inception, and thus an annuity-due. Annuities-due are atypical. get: return a rate either i, d, v, or delta. See rates() function for descriptions of each. This function returns i by default q_per_t: return rate r adjusted for different compounding period than calculated. So if the annuity payments passed are actually monthly but you're looking for an annual effective rate, then pass q_per_t as 12. Conversely if the annuity payments as described are biannual, then pass q_per_t as 0.5 to return the effective annual interest rate. See the description in the rates() function for further explanation, but be advised that it this functions inversely here as opposed to there. i.e. passing 12 in this function will mean that the returned rate r is r ** 12 as opposed to r ** (1/12) Acceptable argument inputs: q: int, float, or a list of either or both get: interest rate i, pass: nothing OR 1 OR a string that starts with 'i' discount rate d, pass: 2 OR a string that starts with 'd' discount rate v, pass: 3 OR a string that starts with 'v' continuously compounded force of interest, pass: 4 OR a string that starts with 'de', 'c', or 'f' t: int only annuity_due: True or False all others: int or float ''' # Function Body # If q is False, the answer is easier if q == False: # account for the possibility that we are only given fv if pv == False: pv = 1 if fv == False: fv = 1 # simple rate calculation r = (fv / pv)**(1 / t) - 1 else: # need to create a list of payments (q). if isinstance(q, list) == False: q = [q] if t != False: q *= t if pv != False and annuity_due == True: q[0] = q[0] - pv elif pv != False: q = [-pv] + q if fv != False and annuity_due == False: q[-1] = q[-1] - fv elif fv != False and annuity_due == True: q.append(-fv) # find the roots of the polynomial as created above real = [] for i in polyroots(q): # we only want real numbers if isinstance(i, ctx_mp_python.mpf): real.append(i) # we want the positive zero, if it exists, and we can't take the max of a null list if real == []: real = [1] r = max(real) # make r a percentage r = float(r - 1) # payments q must have ins and outs. If it is all outs or all ins then q is free money and no investment was # made to make a return. Therefore test for lack of investment and return an error value (0) if no # investment was ever made. if max(q) < 0 or min(q) > 0: r = 0 # q_per_t functions inversely in this function to all other functions. if q_per_t != False: q_per_t = 1 / q_per_t r = rates(r=r, get=get, q_per_t=q_per_t) return r
def polyroots(l): from mpmath import polyroots, mpc, mpf retval = polyroots(l,maxsteps=200,extraprec=40) if not any([isinstance(_,(mpf,mpc)) for _ in l]): retval = [float(_) if isinstance(_,mpf) else complex(_) for _ in retval] return retval
def roots(self, r): a = [r * p + q for p, q in zip(self.p, self.q)] rootss = [v for v in mpmath.polyroots(a[::-1], maxsteps=5000)] #b = mpmath.polyval(self.p[::-1], rootss[0]) + mpmath.polyval(self.q[::-1], rootss[0]) return [complex(v) for v in rootss]
def volume_solutions_mpmath(T, P, b, delta, epsilon, a_alpha, dps=30): r'''Solution of this form of the cubic EOS in terms of volumes, using the `mpmath` arbitrary precision library. The number of decimal places returned is controlled by the `dps` parameter. This function is the reference implementation which provides exactly correct solutions; other algorithms are compared against this one. Parameters ---------- T : float Temperature, [K] P : float Pressure, [Pa] b : float Coefficient calculated by EOS-specific method, [m^3/mol] delta : float Coefficient calculated by EOS-specific method, [m^3/mol] epsilon : float Coefficient calculated by EOS-specific method, [m^6/mol^2] a_alpha : float Coefficient calculated by EOS-specific method, [J^2/mol^2/Pa] dps : int Number of decimal places in the result by `mpmath`, [-] Returns ------- Vs : tuple[complex] Three possible molar volumes, [m^3/mol] Notes ----- Although `mpmath` has a cubic solver, it has been found to fail to solve in some cases. Accordingly, the algorithm is as follows: Working precision is `dps` plus 40 digits; and if P < 1e-10 Pa, it is `dps` plus 400 digits. The input parameters are converted exactly to `mpf` objects on input. `polyroots` from mpmath is used with `maxsteps=2000`, and extra precision of 15 digits. If the solution does not converge, 20 extra digits are added up to 8 times. If no solution is found, mpmath's `findroot` is called on the pressure error function using three initial guesses from another solver. Needless to say, this function is quite slow. Examples -------- Test case which presented issues for PR EOS (three roots were not being returned): >>> volume_solutions_mpmath(0.01, 1e-05, 2.5405184201558786e-05, 5.081036840311757e-05, -6.454233843151321e-10, 0.3872747173781095) (mpf('0.0000254054613415548712260258773060137'), mpf('4.66038025602155259976574392093252'), mpf('8309.80218708657190094424659859346')) References ---------- .. [1] Johansson, Fredrik. Mpmath: A Python Library for Arbitrary-Precision Floating-Point Arithmetic, 2010. ''' # Tried to remove some green on physical TV with more than 30, could not # 30 is fine, but do not dercease further! # No matter the precision, still cannot get better # Need to switch from `rindroot` to an actual cubic solution in mpmath # Three roots not found in some cases # PRMIX(T=1e-2, P=1e-5, Tcs=[126.1, 190.6], Pcs=[33.94E5, 46.04E5], omegas=[0.04, 0.011], zs=[0.5, 0.5], kijs=[[0,0],[0,0]]).volume_error() # Once found it possible to compute VLE down to 0.03 Tc with ~400 steps and ~500 dps. # need to start with a really high dps to get convergence or it is discontinuous if P == 0.0 or T == 0.0: raise ValueError("Bad P or T; issue is not the algorithm") import mpmath as mp mp.mp.dps = dps + 40#400#400 if P < 1e-10: mp.mp.dps = dps + 400 b, T, P, epsilon, delta, a_alpha = [mp.mpf(i) for i in [b, T, P, epsilon, delta, a_alpha]] roots = None if 1: RT_inv = 1/(mp.mpf(R)*T) P_RT_inv = P*RT_inv B = etas = b*P_RT_inv deltas = delta*P_RT_inv thetas = a_alpha*P_RT_inv*RT_inv epsilons = epsilon*P_RT_inv*P_RT_inv b = (deltas - B - 1) c = (thetas + epsilons - deltas*(B + 1)) d = -(epsilons*(B + 1) + thetas*etas) extraprec = 15 # extraprec alone is not enough to converge everything try: # found case 20 extrapec not enough, increased to 30 # Found another case needing 40 for i in range(8): try: # Found 1 case 100 steps not enough needed 200; then found place 400 was not enough roots = mp.polyroots([mp.mpf(1.0), b, c, d], extraprec=extraprec, maxsteps=2000) break except Exception as e: extraprec += 20 # print(e, extraprec) if i == 7: # print(e, 'failed') raise e if all(i == 0 or i == 1 for i in roots): return volume_solutions_mpmath(T, P, b, delta, epsilon, a_alpha, dps=dps*2) except: try: guesses = volume_solutions_fast(T, P, b, delta, epsilon, a_alpha) roots = mp.polyroots([mp.mpf(1.0), b, c, d], extraprec=40, maxsteps=100, roots_init=guesses) except: pass # roots = np.roots([1.0, b, c, d]).tolist() if roots is not None: RT_P = mp.mpf(R)*T/P hits = [V*RT_P for V in roots] if roots is None: # print('trying numerical mpmath') guesses = volume_solutions_fast(T, P, b, delta, epsilon, a_alpha) RT = T*R def err(V): return(RT/(V-b) - a_alpha/(V*(V + delta) + epsilon)) - P hits = [] for Vi in guesses: try: V_calc = mp.findroot(err, Vi, solver='newton') hits.append(V_calc) except Exception as e: pass if not hits: raise ValueError("Could not converge any mpmath volumes") # Return in the specified precision mp.mp.dps = dps sort_fun = lambda x: (x.real, x.imag) return tuple(sorted(hits, key=sort_fun))
def __init__(self,rang=10,acc=100): # Generates the coefficients of Legendre polynomial of n-th order. # acc is the number of decimal characters of the coefficients. # self.cf is the list with coefficients. self.rang = rang self.acc = mp.dps = acc cn = mpf(0.0) k = mpf(0) n = mpf(rang) m = mpf(n/2) cf = [] for k in range(n+1): cn = (- 1)**(n+k)*factorial(n+k)/(factorial(nk)*factorial(k)*factorial(k)) cf.append(cn) cf.reverse() # Generates the coefficients of of the implicit Runge-Kutta scheme of Gauss-Legendre type. # acc is the number of the decimal characters of the coefficients. # Gives back the cortege (r,b,a), the terms of which correspond to Butcher scheme # # r1 | a11 . . . а1n # . | . . # . | . . # . | . . # rn | an1 . . . ann # ---+-------------- # | b1 . . . bn self.r = polyroots(cf) A1 = matrix(rang) for j in range(n): for k in range(n): A1[k,j] = self.r[j]**k bn = [] for j in range(n): bn.append(mpf(1.0)/mpf(j+1)) B = matrix(bn) self.b = lu_solve(A1,B) self.a = matrix(rang) for i in range(1,n+1): A1 = matrix(rang) cil = [] for l in range(1,n+1): cil.append(mpf(self.r[i- 1])**l/mpf(l)) for j in range(n): A1[l-1,j] = self.r[j]**(l-1) Cil = matrix(cil) an = lu_solve(A1,Cil) for k in range(n): self.a[i-1,k] = an[k] def init(self,f,t,h,initvalues): self.size = len(initvalues) self.f = f 31 self.t = t self.h = h self.yb = matrix(initvalues) self.ks = matrix(self.size,self.rang) for k in range(self.size): for i in range(self.rang): self.ks[k,i] = self.r[i] self.tn = matrix(1,self.rang) for i in range(self.rang): self.tn[i] = t + h*self.r[i] self.y = matrix(self.size,self.rang) for k in range(self.size): for i in range(self.rang): self.y[k,i] = self.yb[k] temp = mpf(0.0) for j in range(self.rang): temp += self.a[i,j]*self.ks[k,j] self.y[k,i] += temp self.yn = matrix(self.yb) def iterate(self,tn,y,yn,ks): # Generates the coefficients of the implicit Runge-Kutta scheme for the given step # with the method of the simple iteration with an initial value, coinciding with the coefficients, # calculated at the previous step. At sufficiently small step this must # work. There exists such a value of the step, Under which convergence is guaranteed. # No automatic re-setup of the step is foreseen in this procedure. mp.dps = self.acc y0 = matrix(yn) norme = mpf(1.0) #eps0 = pow(eps,mpf(3.0)/mpf(4.0)) eps0 = sqrt(eps) ks1 = matrix(self.size,self.rang) yt = matrix(1,self.size) count = 0 while True: count += 1 for i in range(self.rang): for k in range(self.size): yt[k] = y[k,i] for k in range(self.size): ks1[k,i] = self.f(tn,yt)[k] norme = mpf(0.0) 2 for k in range(self.size): for i in range(self.rang): norme += (ks1[k,i]- ks[k,i])*(ks1[k,i]-ks[k,i]) norme = sqrt(norme) for k in range(self.size): for i in range(self.rang): ks[k,i] = ks1[k,i] for k in range(self.size): for i in range(self.rang): y[k,i] = y0[k] for j in range(self.rang): y[k,i] += self.h*self.a[i,j]*ks[k,j] if norme <= eps0: break if count >= 100: print unicode('No convergence','UTF-8') exit(0) return ks1 def step(self): mp.dps = self.acc self.ks = self.iterate(self.tn,self.y,self.yn,self.ks) for k in range(self.size): for i in range(self.rang): self.yn[k] += self.h*self.b[i]*self.ks[k,i] for k in range(self.size): for i in range(self.rang): self.y[k,i] = self.yn[k] for j in range(self.rang): self.y[k,i] += self.a[i,j]*self.ks[k,j] self.t += self.h for i in range(self.rang): self.tn[i] = self.t + self.h*self.r[i] return self.yn
def __init__(self,eps,x0,v0): from numpy import dot from mpmath import polyroots, mpf, mpc, sqrt, atan2, polyval from weierstrass_elliptic import weierstrass_elliptic as we if eps <= 0: raise ValueError('thrust must be strictly positive') eps = mpf(eps) # Unitary grav. parameter. mu = mpf(1.) x,y,z = [mpf(x) for x in x0] vx,vy,vz = [mpf(v) for v in v0] r = sqrt(x**2 + y**2 + z**2) xi = sqrt(r+z) eta = sqrt(r-z) phi = atan2(y,x) vr = dot(v0,x0) / r vxi = (vr + vz) / (2 * sqrt(r+z)) veta = (vr - vz) / (2 * sqrt(r-z)) vphi = (vy*x - vx*y) / (x**2 + y**2) pxi = (xi**2 + eta**2) * vxi peta = (xi**2 + eta**2) * veta pphi = xi**2*eta**2*vphi if pphi == 0: raise ValueError('bidimensional case') # Energy constant. h = (pxi**2 + peta**2) / (2*(xi**2 + eta**2)) + pphi**2 / (2*xi**2*eta**2) - (2 * mu) / (xi**2+eta**2) - eps * (xi**2 - eta**2) / 2 # Alpha constants. alpha1 = -eps * xi**4 / 2 - h * xi**2 + pxi**2 / 2 + pphi**2 / (2*xi**2) alpha2 = eps * eta**4 / 2 - h * eta**2 + peta**2 / 2 + pphi**2 / (2*eta**2) # Analysis of the cubic polynomials in the equations for pxi and peta. roots_xi, _ = polyroots([8*eps,8*h,4*alpha1,-pphi**2],error=True,maxsteps=100) roots_eta, _ = polyroots([-8*eps,8*h,4*alpha2,-pphi**2],error=True,maxsteps=100) # NOTE: these are all paranoia checks that could go away if we used the exact cubic formula. if not (all([isinstance(x,mpf) for x in roots_xi]) or (isinstance(roots_xi[0],mpf) and isinstance(roots_xi[1],mpc) and isinstance(roots_xi[2],mpc))): raise ValueError('invalid xi roots detected: ' + str(roots_xi)) if not (all([isinstance(x,mpf) for x in roots_eta]) or (isinstance(roots_eta[0],mpf) and isinstance(roots_eta[1],mpc) and isinstance(roots_eta[2],mpc))): raise ValueError('invalid eta roots detected: ' + str(roots_eta)) # For xi we need to understand which of the real positive roots will be or was reached # given the initial condition. rp_roots_extract = lambda x: isinstance(x,mpf) and x > 0 rp_roots_xi = [sqrt(2 * _) for _ in filter(rp_roots_extract,roots_xi)] rp_roots_eta = [sqrt(2. * _) for _ in filter(rp_roots_extract,roots_eta)] # Paranoia. if not len(rp_roots_xi) in [1,3]: raise ValueError('invalid xi roots detected: ' + str(roots_xi)) if len(rp_roots_eta) != 2: raise ValueError('invalid eta roots detected: ' + str(roots_eta)) # We choose as reachable/reached roots always those corresponding to the "pericentre" # for the two coordinates. if len(rp_roots_xi) == 1: # Here there's really no choice, only 1 root available. rr_xi = rp_roots_xi[0] else: # If motion is unbound, take the only root, otherwise take the smallest of the # two roots of the bound motion. rr_xi = rp_roots_xi[-1] if xi >= rp_roots_xi[-1] else rp_roots_xi[0] # No choice to be made here. rr_eta = rp_roots_eta[0] # Store parameters and constants. self.__init_coordinates = [xi,eta,phi] self.__init_momenta = [pxi,peta,pphi] self.__eps = eps self.__h = h self.__alpha1 = alpha1 self.__alpha2 = alpha2 self.__rp_roots_xi = rp_roots_xi self.__rp_roots_eta = rp_roots_eta self.__rr_xi = rr_xi self.__rr_eta = rr_eta self.__roots_xi = roots_xi self.__roots_eta = roots_eta # Create the Weierstrass objects for xi and eta. a1, a2, a3, a4 = 2*eps, (4 * h)/3, alpha1, -pphi**2 g2 = -4 * a1 * a3 + 3 * a2**2 g3 = 2 * a1 * a2 * a3 - a2**3 - a1**2*a4 self.__f_xi = [4*a1,6*a2,4*a3,a4] self.__fp_xi = [12*a1,12*a2,4*a3] self.__fpp_xi = [24*a1,12*a2] self.__w_xi = we(g2,g3) # Eta. a1,a3 = -a1,alpha2 g2 = -4 * a1 * a3 + 3 * a2**2 g3 = 2 * a1 * a2 * a3 - a2**3 - a1**2*a4 self.__f_eta = [4*a1,6*a2,4*a3,a4] self.__fp_eta = [12*a1,12*a2,4*a3] self.__fpp_eta = [24*a1,12*a2] self.__w_eta = we(g2,g3) # Compute the taus. tau_xi = self.__compute_tau_xi() tau_eta = self.__compute_tau_eta() self.__tau_xi = tau_xi self.__tau_eta = tau_eta # Store the real periods. self.__T_xi = self.__w_xi.periods[0] self.__T_eta = self.__w_eta.periods[0] # Delta bound (for debugging). xi_roots = self.__w_xi.roots # Determine the root corresponding to the real half-period. e_R = min(xi_roots,key = lambda x: abs(self.__w_xi.P(self.__T_xi/2) - x)) self.__Dbound = e_R - polyval(self.__fpp_xi,xi**2/2) / 24
def PolynomialSolver(polynomial): assert isinstance(polynomial, Polynomial) assert polynomial.coefficientType(mpmath.mpc) == mpmath.mpc return [ mpmath.mpc(x) for x in mpmath.polyroots(polynomial.getCoefficients(mpmath.mpc))]
def solve_eq(self): c = [self._c8(),self._c7(),self._c6(),self._c5(),self._c4(),self._c3(),self._c2(),self._c1(),self._c0()] self.omega_tab = mp.polyroots(c) self.omega = sorted(self.omega_tab,key=lambda x: x.imag,reverse=True)[0] return sorted(self.omega_tab,key=lambda x: x.imag,reverse=True)