def mclaren_03(): degree = 7 # the positive roots of # z^6 - z^4 + 0.2*z^2 - 1/105 = 0, # i.e., the square roots of the roots of # z^3 - z^2 + 0.2*z^1 - 1/105 = 0, r2, s2, t2 = mp.polyroots([1, -1, frac(1, 5), -frac(1, 105)]) r = sqrt(r2) s = sqrt(s2) t = sqrt(t2) u = numpy.array([+r, -r, +s, -s, +t, -t]) v = numpy.array([+s, +t, +t, +r, +r, +s]) w = numpy.array([+t, +s, +r, +t, +s, +r]) data = [ (frac(1, 24), numpy.column_stack([+u, +v, +w])), (frac(1, 24), numpy.column_stack([+u, -v, -w])), (frac(1, 24), numpy.column_stack([+u, +w, -v])), (frac(1, 24), numpy.column_stack([+u, -w, +v])), ] points, weights = untangle(data) azimuthal_polar = cartesian_to_spherical_sympy(points) return U3Scheme("McLaren 3", weights, points, azimuthal_polar, degree, source)
def mclaren_04(): degree = 8 # the positive roots of # z^6 - z^4 + 5/21 * z^2 - 5/441 = 0, # i.e., the square roots of the roots of # z^3 - z^2 + 5/21 * z^1 - 5/441 = 0, r2, s2, t2 = mp.polyroots([1, -1, frac(5, 21), -frac(5, 441)]) r = sqrt(r2) s = sqrt(s2) t = sqrt(t2) u = numpy.array([+r, -r, +s, -s, +t, -t]) v = numpy.array([+s, +t, +t, +r, +r, +s]) w = numpy.array([+t, +s, +r, +t, +s, +r]) data = [ (frac(16, 600), fsd(3, (1, 1))), (frac(21, 600), numpy.column_stack([+u, +v, +w])), (frac(21, 600), numpy.column_stack([+u, -v, -w])), (frac(21, 600), numpy.column_stack([+u, +w, -v])), (frac(21, 600), numpy.column_stack([+u, -w, +v])), ] points, weights = untangle(data) azimuthal_polar = cartesian_to_spherical_sympy(points) return SphereScheme("McLaren 1", weights, points, azimuthal_polar, degree, citation)
def _stroud_1964(variant_a, n): degree = 3 if n == 2: # The roots sum up to 1 r, s, t = mp.polyroots([1, -1, 0.25, -1.0 / 60.0]) data = [(1.0 / (n * (n + 1)), rd(n + 1, [(r, 1), (s, 1), (t, 1)]))] else: assert n > 2 # Stroud's book only gives numerical values for certain n; the article explains # it in more detail, namely: r is a root of a polynomial of degree 3. rts = numpy.sort( numpy.roots([n + 1, -3, 3 / (n + 2), -1 / ((n + 2) * (n + 3))])) # all roots are real-valued if n > 8: assert not variant_a, "Choose variant b for n >= 9." r = rts[0] if variant_a else rts[1] # s and t are zeros of a polynomial of degree 2 s, t = numpy.sort( numpy.roots([ 1, -(1 - (n - 1) * r), n / (2 * (n + 2)) - (n - 1) * r + n * (n - 1) / 2 * r**2, ])) data = [(1 / (n * (n + 1)), rd(n + 1, [(r, n - 1), (s, 1), (t, 1)]))] points, weights = untangle(data) name = "Stroud 1964{}".format("a" if variant_a else "b") return TnScheme(name, n, weights, points, degree, source)
def __init__(self, npts): # Legendre poly lp = lambda x: mp.legendre(npts - 1, x) # Coefficients of lp cf = mp.taylor(lp, 0, npts - 1) # Coefficients of dlp/dx dcf = [i*c for i, c in enumerate(cf[1:], start=1)] self.points = [mp.mpf(-1)] + mp.polyroots(dcf[::-1]) + [mp.mpf(1)] self.weights = [2/(npts*(npts - 1)*lp(p)**2) for p in self.points]
def compute_border_sizes(dims, phi, mat=False): """Compute optimal border sizes for a mat window mesuring dims[0] x dims[1]. Returns a tuple (top_left_right_border, bottom_border). The computed top, left and right borders have the same value. The computed bottom border is bigger to compensate for the optical illusion of the picture "sinking" in the frame. The values are computed so that the mat's surface is the window's surface times `phi`. Passing `mat=True` causes the computation to be reversed: the borders are computed from a mat size. """ x, y = dims if mat: # dims are mat's dims coeffs = [ -2 * phi, 5 * x * phi + 2 * y * phi, -2 * x * x * phi - 3 * x * y * phi + x * y, x * x * y * (phi - 1), ] else: # dims are window's dims coeffs = [ 6, 7 * x + 2 * y, x * ((3 - phi) * y + 2 * x), (1 - phi) * mp.power(x, 2) * y, ] roots = mp.polyroots(coeffs, 50) roots = [root for root in roots if mp.im(root) == mp.mpf(0)] # If multiple solutions, keep the one with smalest borders first roots.sort() sols = [ # (root, root + mp.power(root, 2) / (x + root)) (root, root + _A(root, x, mat)) for root in roots ] # Shouldn't happen if len(roots) < 1: raise Exception("Error, could not find solution for borders") elif len(roots) > 1: click.echo("*Warning: multiple solutions. Keeping smallest border.", err=True) return sols[0]
def order_from_nspts(cls, nspts): # Obtain the coefficients for the poly: P(n) - nspts = 0 coeffs = list(cls.npts_coeffs) coeffs[-1] -= cls.npts_cdenom*int(nspts) # Solve to obtain the order (a positive integer) roots = mp.polyroots(coeffs) roots = [int(x) for x in roots if mp.isint(x) and x > 0] if roots: return roots[0] else: raise ValueError('Invalid number of shape points')
def order_from_nspts(cls, nspts): # Obtain the coefficients for the poly: P(n) - nspts = 0 coeffs = list(cls.npts_coeffs) coeffs[-1] -= cls.npts_cdenom * nspts # Solve to obtain the order (a positive integer) roots = mp.polyroots(coeffs) roots = [int(x) for x in roots if mp.isint(x) and x > 0] if roots: return roots[0] else: raise ValueError('Invalid number of shape points')
def mclaren_04(): degree = 8 # the positive roots of # z^6 - z^4 + 5/21 * z^2 - 5/441 = 0, # i.e., the square roots of the roots of # z^3 - z^2 + 5/21 * z^1 - 5/441 = 0, r2, s2, t2 = mp.polyroots([1, -1, frac(5, 21), -frac(5, 441)]) r = sqrt(r2) s = sqrt(s2) t = sqrt(t2) data = {"a1": [frac(16, 600)], "rst_weird": [frac(21, 600), r, s, t]} return U3Scheme("McLaren 4", data, degree, source)
def mclaren_03(): degree = 7 # the positive roots of # z^6 - z^4 + 0.2*z^2 - 1/105 = 0, # i.e., the square roots of the roots of # z^3 - z^2 + 0.2*z^1 - 1/105 = 0, r2, s2, t2 = mp.polyroots([1, -1, frac(1, 5), -frac(1, 105)]) r = sqrt(r2) s = sqrt(s2) t = sqrt(t2) data = {"rst_weird": [frac(1, 24), r, s, t]} return U3Scheme("McLaren 3", data, degree, source)
def __init__(self, n, variant, symbolic=False): assert variant in ['a', 'b'] frac = sympy.Rational if symbolic else lambda x, y: x / y roots = mp.polyroots if symbolic else numpy.roots self.dim = n self.degree = 3 if n == 2: # The roots sum up to 1 r, s, t = mp.polyroots([1, -1, frac(1, 4), -frac(1, 60)]) data = [ (frac(1, n * (n + 1)), rd(n + 1, [(r, 1), (s, 1), (t, 1)])), ] else: assert n > 2 # Stroud's book only gives numerical values for certain n; the # article explains it in more detail, namely: r is a root of a # polynomial of degree 3. rts = numpy.sort( roots([n + 1, -3, frac(3, n + 2), -frac(1, (n + 2) * (n + 3))])) # all roots are real-valued if n > 8: assert variant == 'b', 'Choose variant b for n >= 9.' r = rts[0] if variant == 'a' else rts[1] # s and t are zeros of a polynomial of degree 2 s, t = numpy.sort( roots([ 1, -(1 - (n - 1) * r), frac(n, 2 * (n + 2)) - (n - 1) * r + frac(n * (n - 1), 2) * r**2 ])) data = [ (frac(1, n * (n + 1)), rd(n + 1, [(r, n - 1), (s, 1), (t, 1)])), ] self.bary, self.weights = untangle(data) self.points = self.bary[:, 1:] return
def test(wx, wy): phi = (1 + mp.sqrt(5)) / 2 coeffs = [ 6, 7 * wx + 2 * wy, wx * ((3 - phi) * wy + 2 * wx), (1 - phi) * mp.power(wx, 2) * wy ] roots = mp.polyroots(coeffs, 15) roots = [root for root in roots if mp.im(root) == mp.mpf(0)] if len(roots) < 1: raise Exception("Error, could not find solution for borders") elif len(roots) > 1: raise Exception("Error, multiple possible solutions for borders") b = roots[0] bottom = b + mp.power(b, 2) / (wx + b) return b, bottom
def __init__(self, npts): roots = mp.polyroots([1, 1, 0, -2*npts]) roots = [int(x) for x in roots if mp.isint(x) and x > 0] if not roots: raise ValueError('Invalid number of points for quad rule') tname, lname = self.name.split('*') trulecls = subclass_where(BaseTriQuadRule, name=tname) trule = trulecls(roots[0]*(roots[0] + 1) // 2) lrulecls = subclass_where(BaseLineQuadRule, name=lname) lrule = lrulecls[lname](roots[0]) self.points = [(t[0], t[1], l) for l in lrule.points for t in trule.points] if hasattr(trule, 'weights') and hasattr(lrule, 'weights'): self.weights = [i*j for j in lrule.weights for i in trule.weights]
from mpmath import mp mp.dps = 5 wx = mp.mpf('9'); wy = mp.mpf('6') phi = (1 + mp.sqrt(5)) / 2 phi = mp.power(phi, 2) coeffs = [ 6, 7 * wx + 2 * wy, wx * ((3 - phi)*wy + 2*wx), (1 - phi) * mp.power(wx, 2) * wy ] roots = mp.polyroots(coeffs, 15) b = [root for root in roots if mp.im(root) == mp.mpf(0)][0] bottom = b + mp.power(b, 2) / (wx + b) print( "Print dimensions: {wx!s} x {wy!s}\n" "Resulting border: {b!s}\n" "Resulting bottom border: {bottom!s}" .format(wx=wx, wy=wy, b=b, bottom=bottom) ) v = dict( mat_l=0 - b, mat_t=b, mat_w=wx + 2 * b, mat_h=-1 * (wy + b + bottom), )
def _sortbnccu(self, lbd): """Solve normalized cusp curve equation and sort branches""" if lbd <= mp.mpf(0.): # solve cusp equation for saddle point (lbd = 0) a3 = mp.mpf(1.) a2 = mp.mpf(3.) / mp.mpf(1. + self.q) a1 = mp.mpf(3.) / mp.mpf(1. + self.q) a0 = mp.mpf(1.) / mp.mpf(1. + self.q) zn = np.array(mp.polyroots([a3, a2, a1, a0], maxsteps=60, extraprec=self.extraprec), dtype=np.complex128) arg = np.argsort(np.imag(zn)) sort = zn[arg] b2 = complex(sort[0]) b4 = b2 b5 = complex(sort[1]) b6 = b5 b1 = complex(sort[2]) b3 = b1 # bn, sn bn = np.array([b1, b2, b3, b4, b5, b6]) sn = np.sqrt( np.abs(1. / (1. + self.q) * (1. / bn**2 + self.q / (bn + 1.)**2))) elif lbd == mp.mpf(1.): # solve cusp equation for 4 non-∞ branches (lbd = 1) L = mp.mpf(1.) / mp.mpf(1. + self.q) a4 = mp.mpf(3. * (5. * (1. - L) + 2. * (1. - 3. * L) * self.q - L * self.q**2)) a3 = mp.mpf(2. * (10. * (1. - L) + (1. - 6. * L) * self.q)) a2 = mp.mpf(3. * (5. * (1. - L) - L * self.q)) a1 = mp.mpf(6. * (1. - L)) a0 = mp.mpf(1. - L) zn = np.array(mp.polyroots([a4, a3, a2, a1, a0], maxsteps=60, extraprec=self.extraprec), dtype=np.complex128) # b1 arg = np.argmax(np.imag(zn)) b1 = complex(zn[arg]) zn = np.delete(zn, arg) # b2 arg = np.argmin(np.imag(zn)) b2 = complex(zn[arg]) zn = np.delete(zn, arg) # b3, b4 b3 = np.inf b4 = -np.inf # b5, b6 arg = np.argsort(np.real(zn)) sort = zn[arg] b5, b6 = complex(sort[0]), complex(sort[1]) # bn, sn bn = np.array([b1, b2, b3, b4, b5, b6]) sn = np.zeros(6, dtype=np.float_) # s -> 0. for zn -> ∞ sn[[0, 1, 4, 5]] = np.sqrt( np.abs(1. / (1. + self.q) * (1. / bn[[0, 1, 4, 5]]**2 + self.q / (bn[[0, 1, 4, 5]] + 1.)**2))) elif lbd == mp.mpf(1. + self.q): # solve cusp equation for primary lens position (lbd = 1+q) a4 = mp.mpf(-self.q * (1. + self.q)**2) a3 = mp.mpf(-6. * self.q * (1. + self.q)) a2 = mp.mpf(-3. * self.q * (self.q + 4.)) a1 = mp.mpf(-10. * self.q) a0 = mp.mpf(-3. * self.q) zn = np.array(mp.polyroots([a4, a3, a2, a1, a0], maxsteps=60, extraprec=self.extraprec), dtype=np.complex128) # b1 arg = np.argmax(np.imag(zn)) b1 = complex(zn[arg]) zn = np.delete(zn, arg) # b2 arg = np.argmin(np.imag(zn)) b2 = complex(zn[arg]) zn = np.delete(zn, arg) # b4, b5 arg = np.argsort(np.real(zn)) sort = zn[arg] b4, b5 = complex(sort[0]), complex(sort[1]) # b3, b6 b3 = 0j b6 = 0j # bn, sn bn = np.array([b1, b2, b3, b4, b5, b6]) sn = np.zeros(6, dtype=np.float_) sn[[2, 5]] = np.inf # s -> ∞ for zn -> 0. sn[[0, 1, 3, 4]] = np.sqrt( np.abs(1. / (1. + self.q) * (1. / bn[[0, 1, 3, 4]]**2 + self.q / (bn[[0, 1, 3, 4]] + 1.)**2))) elif lbd == mp.mpf(1. + 1. / self.q): # solve cusp equation for secondary lens position (lbd = 1+1/q) a4 = mp.mpf(-2. - 1. / self.q - self.q) a3 = mp.mpf(6. * (1. + self.q)) a2 = mp.mpf(-3. * (1. + 4. * self.q)) a1 = mp.mpf(10. * self.q) a0 = mp.mpf(-3. * self.q) Zn = np.array(mp.polyroots([a4, a3, a2, a1, a0], maxsteps=60, extraprec=self.extraprec), dtype=np.complex128) # Zn = zn + 1. # b1, b3 arg = np.where(np.imag(Zn) > 0.) B = Zn[arg] arg = np.argmin(np.real(B)) b1 = complex(B[arg]) - 1. # Zn = zn + 1. arg = np.argmax(np.real(B)) b3 = complex(B[arg]) - 1. # Zn = zn + 1. # b2, b6 b2 = np.conj(b1) b6 = np.conj(b3) # b4, b5 b4 = 0j - 1. # Zn = zn + 1. b5 = 0j - 1. # Zn = zn + 1. # bn, sn bn = np.array([b1, b2, b3, b4, b5, b6]) sn = np.zeros(6, dtype=np.float_) sn[[3, 4]] = np.inf # s -> ∞ for zn -> -1. sn[[0, 1, 2, 5]] = np.sqrt( np.abs(1. / (1. + self.q) * (1. / bn[[0, 1, 2, 5]]**2 + self.q / (bn[[0, 1, 2, 5]] + 1.)**2))) elif lbd == mp.mpf(np.inf): # solve cusp equation for maximum of Jacobian (lbd = ∞) # b1, b3, b5 b1 = -1. / (1. + self.q) * np.complex(1., -np.sqrt(self.q)) b3, b5 = b1, b1 # b2, b4, b6 b2 = np.conj(b1) b4, b6 = b2, b2 # bn, sn bn = np.array([b1, b2, b3, b4, b5, b6]) sn = np.zeros(6, dtype=np.float_) else: # solve cusp equation for intervals with high precision L = mp.mpf(lbd) / mp.mpf(1. + self.q) a6 = mp.mpf(1. - L + (2. - 3. * L) * self.q + (1. - 3. * L) * self.q**2 - L * self.q**3) a5 = mp.mpf(6. * (1. - L + (1. - 2. * L) * self.q - L * self.q**2)) a4 = mp.mpf(3. * (5. * (1. - L) + 2. * (1. - 3. * L) * self.q - L * self.q**2)) a3 = mp.mpf(2. * (10. * (1. - L) + (1. - 6. * L) * self.q)) a2 = mp.mpf(3. * (5. * (1. - L) - L * self.q)) a1 = mp.mpf(6. * (1. - L)) a0 = mp.mpf(1. - L) zn = np.array(mp.polyroots([a6, a5, a4, a3, a2, a1, a0], maxsteps=60, extraprec=self.extraprec), dtype=np.complex128) # Values comparisons between lbd (high precision) and high precision numbers if mp.mpf(0.) < lbd < mp.mpf(1.): # 0 < lbd < 1 (saddle -> ∞) # b3 # arg = np.argmax([mp.im(i) for i in zn]) arg = np.argmax(np.imag(zn)) b3 = complex(zn[arg]) zn = np.delete(zn, arg) # b4 arg = np.argmin(np.imag(zn)) b4 = complex(zn[arg]) zn = np.delete(zn, arg) # b1 arg = np.argmax(np.imag(zn)) b1 = complex(zn[arg]) zn = np.delete(zn, arg) # b2 arg = np.argmin(np.imag(zn)) b2 = complex(zn[arg]) zn = np.delete(zn, arg) # b5, b6 arg = np.argsort(np.real(zn)) sort = zn[arg] b5, b6 = complex(sort[0]), complex(sort[1]) elif mp.mpf(1.) < lbd < mp.mpf(1. + self.q): # 1 < lbd < 1/mu_1 = 1+q (∞ -> left lens pos) # b1 arg = np.argmax(np.imag(zn)) b1 = complex(zn[arg]) zn = np.delete(zn, arg) # b2 arg = np.argmin(np.imag(zn)) b2 = complex(zn[arg]) zn = np.delete(zn, arg) # b3, b4, b5, b6 arg = np.argsort(np.real(zn)) sort = zn[arg] b4, b5, b6, b3 = complex(sort[0]), complex(sort[1]), complex( sort[2]), complex(sort[3]) elif mp.mpf(1. + self.q ) < lbd < mp.mpf(1.) + mp.mpf(1.) / mp.mpf(self.q): # 1/mu_1 = 1+q < lbd < 1/mu_2 = 1+1/q (lef lens -> right lens) # b4, b5 arg = np.argsort(np.imag(zn)) sort = zn[arg] B = sort[[2, 3]] zn = np.delete(zn, arg[[2, 3]]) arg = np.argsort(np.real(B)) sort = sort[arg] b4, b5 = complex(B[0]), complex(B[1]) # b1, b3 arg = np.where(np.imag(zn) > 0.) B = zn[arg] arg = np.argsort(np.real(B)) sort = B[arg] b1, b3 = complex(sort[0]), complex(sort[1]) # b2, b6 b2, b6 = np.conj(b1), np.conj(b3) elif mp.mpf(1.) + mp.mpf(1.) / mp.mpf(self.q) < lbd: # 1/mu_2 = 1+1/q < lbd (right lens -> max jacobian) # b1, b3, b5 arg = np.where(np.imag(zn) > 0.) B = zn[arg] arg = np.argmax(np.real(B)) b3 = complex(B[arg]) B = np.delete(B, arg) arg = np.argsort(np.imag(B)) C = B[arg] # Using a patch to lead the cumpute out of an unphysical case (images at infinite distance) if np.size(C) == 2: b5, b1 = complex(C[0]), complex(C[1]) else: b5 = complex(C[0]) b1 = np.complex(-0.999999, 0.0000001) # b2, b4, b6 b2, b4, b6 = np.conj(b1), np.conj(b5), np.conj(b3) # bn, sn bn = np.array([b1, b2, b3, b4, b5, b6]) sn = np.sqrt( np.abs(1. / (1. + self.q) * (1. / bn**2 + self.q / (bn + 1.)**2))) return bn, sn
def __init__(self, npts): # Legendre poly lp = lambda x: mp.legendre(npts, x) self.points = mp.polyroots(mp.taylor(lp, 0, npts)[::-1]) self.weights = [2/((1 - p*p)*mp.diff(lp, p)**2) for p in self.points]