def test_path(self):
        CPF = ComplexPathFactory(self.f1, base_point=-2, kappa=1)
        b = CPF.discriminant_points[0]
        R = CPF.radius(b)
        self.assertAlmostEqual(R, 1.0)

        # straight line path from (-2,1) to (1,-2). this intersects the circle
        # of radius 1 about the origin at (-1,0) goes around to (0,-1).
        #
        # this test goes below the circle
        z0 = -2 + 1.j
        z1 = 1 - 2.j
        gamma = CPF.path(z0, z1)
        segments = gamma.segments
        self.assertEqual(segments[0], ComplexLine(z0, -1))
        self.assertEqual(segments[1], ComplexArc(1, 0, -pi, pi / 2))
        self.assertEqual(segments[2], ComplexLine(-1.j, z1))

        # straight line path from (-1,2) to (2,-1). this intersects the circle
        # of radius 1 about the origin at (0,1) goes around to (1,0).
        #
        # this test goes below the circle
        z0 = -1 + 2.j
        z1 = 2 - 1.j
        gamma = CPF.path(z0, z1)
        segments = gamma.segments
        self.assertEqual(segments[0], ComplexLine(z0, 1.j))
        self.assertEqual(segments[1], ComplexArc(1, 0, pi / 2, -pi / 2))
        self.assertEqual(segments[2], ComplexLine(1, z1))
 def test_arc_derivative(self):
     # arc from theta=0 to theta=pi/2 on the unit circle
     gamma = ComplexArc(1, 0, 0, pi/2)
     scale = 1.j*pi/2
     self.assertAlmostEqual(gamma.derivative(0), scale)
     self.assertAlmostEqual(gamma.derivative(0.5), scale*exp(1.j*pi/4))
     self.assertAlmostEqual(gamma.derivative(0.75), scale*exp(1.j*3*pi/8))
     self.assertAlmostEqual(gamma.derivative(1), scale*exp(1.j*pi/2))
 def test_single_arc(self):
     gamma = ComplexArc(1,0,pi/5,3*pi/5)
     gamma_rev = gamma.reverse()
     self.assertAlmostEqual(gamma(0.0), gamma_rev(1.0))
     self.assertAlmostEqual(gamma(0.1), gamma_rev(0.9))
     self.assertAlmostEqual(gamma(0.25), gamma_rev(0.75))
     self.assertAlmostEqual(gamma(0.50), gamma_rev(0.50))
     self.assertAlmostEqual(gamma(0.75), gamma_rev(0.25))
     self.assertAlmostEqual(gamma(1.0), gamma_rev(0.0))
Exemple #4
0
 def test_single_arc(self):
     gamma = ComplexArc(1, 0, pi / 5, 3 * pi / 5)
     gamma_rev = gamma.reverse()
     self.assertAlmostEqual(gamma(0.0), gamma_rev(1.0))
     self.assertAlmostEqual(gamma(0.1), gamma_rev(0.9))
     self.assertAlmostEqual(gamma(0.25), gamma_rev(0.75))
     self.assertAlmostEqual(gamma(0.50), gamma_rev(0.50))
     self.assertAlmostEqual(gamma(0.75), gamma_rev(0.25))
     self.assertAlmostEqual(gamma(1.0), gamma_rev(0.0))
Exemple #5
0
    def test_equality(self):
        gamma0 = ComplexLine(-1, 0)
        gamma1 = ComplexLine(-1, 0)
        self.assertEqual(gamma0, gamma1)

        gamma0 = ComplexArc(1, 0, 0, pi)
        gamma1 = ComplexArc(1, 0, 0, pi)
        self.assertEqual(gamma0, gamma1)

        gamma0 = ComplexRay(-1)
        gamma1 = ComplexRay(-1)
        self.assertEqual(gamma0, gamma1)
Exemple #6
0
    def monodromy_path_infinity(self, nrots=1):
        """Returns the complex path starting at the base point, going around
        infinity `nrots` times, and returning to the base point.

        This path is sure to not only encircle all of the discriminant
        points but also stay sufficiently outside the bounding circles
        of the points.

        Parameters
        ----------
        nrots : integer, (default `1`)
            The number of rotations around infinity.

        Returns
        -------
        RiemannSurfacePath
            The complex path encircling infinity.

        """
        path = []

        # determine the radius R of the circle, centered at the origin,
        # encircling all of the discriminant points and the bounding circles
        b = self.discriminant_points
        R = numpy.abs(self.base_point)
        for bi in b:
            radius = self.radius(bi)
            Ri = numpy.abs(bi) + 2*radius  # to be safely away
            R = Ri if Ri > R else R

        # the path begins with a line starting at the base point and ending at
        # the point -R (where the circle will begin)
        path = ComplexLine(self.base_point, -R)

        # the positive direction around infinity is equal to the
        # negative direction around the origin
        dtheta = -numpy.pi if nrots > 0 else numpy.pi
        for _ in range(abs(nrots)):
            path += ComplexArc(R, 0, numpy.pi, dtheta)
            path += ComplexArc(R, 0, 0, dtheta)

        # return to the base point
        path += ComplexLine(-R, self.base_point)

        # determine if the circle actually touches the base point. this occurs
        # when the base point is further away from the origin than the bounding
        # circles of discriminant points. in this case, the path only consists
        # of the arcs defining the circle
        if abs(self.base_point + R) < 1e-15:
            path = ComplexPath(path.segments[1:-1])
        return path
Exemple #7
0
 def test_arc(self):
     # arc from theta=0 to theta=pi/2 on the unit circle
     gamma = ComplexArc(1, 0, 0, pi / 2)
     self.assertAlmostEqual(gamma(0), 1)
     self.assertAlmostEqual(gamma(0.5), exp(1.j * pi / 4))
     self.assertAlmostEqual(gamma(0.75), exp(1.j * 3 * pi / 8))
     self.assertAlmostEqual(gamma(1), exp(1.j * pi / 2))
Exemple #8
0
    def test_analytic_continuation_X1(self):
        gammax = ComplexLine(1, 0)
        y0 = [-1, 1]
        gamma = RiemannSurfacePathPuiseux(self.X1, gammax, y0)

        y = gamma.get_y(0)
        self.assertAlmostEqual(y[0], -1)
        self.assertAlmostEqual(y[1], 1)

        y = gamma.get_y(0.5)
        self.assertAlmostEqual(y[0], -sqrt(complex(0.5)))
        self.assertAlmostEqual(y[1], sqrt(complex(0.5)))

        y = gamma.get_y(0.75)
        self.assertAlmostEqual(y[0], -sqrt(complex(0.25)))
        self.assertAlmostEqual(y[1], sqrt(complex(0.25)))

        y = gamma.get_y(1)
        self.assertAlmostEqual(y[0], 0)
        self.assertAlmostEqual(y[1], 0)

        gammax = ComplexArc(2, 2, 0, pi)
        y0 = [-2, 2]
        gamma = RiemannSurfacePathPuiseux(self.X1, gammax, y0)

        y = gamma.get_y(0)
        self.assertAlmostEqual(y[0], -2)
        self.assertAlmostEqual(y[1], 2)

        y = gamma.get_y(1)
        self.assertAlmostEqual(y[0], 0)
        self.assertAlmostEqual(y[1], 0)
Exemple #9
0
    def test_simple_arc(self):
        gammax = ComplexArc(1, 0, 0, pi)
        gamma = RiemannSurfacePathSmale(self.X1, gammax, [-1, 1])
        nu = lambda x, y: y
        nu_gamma = gamma.parameterize(nu)

        val = nu_gamma(0.0)
        test = gammax.derivative(0.0) * (-1)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.5)
        test = gammax.derivative(0.5) * (-sqrt(1.j))
        self.assertAlmostEqual(val, test)

        val = nu_gamma(1.0)
        test = gammax.derivative(1.0) * (-1.j)
        self.assertAlmostEqual(val, test)
    def test_simple_arc(self):
        gammax = ComplexArc(1,0,0,pi)
        gamma = RiemannSurfacePathSmale(self.X1, gammax, [-1,1])
        nu = lambda x,y: y
        nu_gamma = gamma.parameterize(nu)

        val = nu_gamma(0.0)
        test = gammax.derivative(0.0)*(-1)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.5)
        test = gammax.derivative(0.5)*(-sqrt(1.j))
        self.assertAlmostEqual(val, test)

        val = nu_gamma(1.0)
        test = gammax.derivative(1.0)*(-1.j)
        self.assertAlmostEqual(val, test)
    def test_primitive_arc_smale(self):
        PF = RiemannSurfacePathFactory(self.X1, base_point=-1,
                                       base_sheets=[-1.j,1.j])
        gamma_x = ComplexArc(1, 0, pi, pi)
        gamma = PF.RiemannSurfacePath_from_complex_path(gamma_x)
        self.assertAlmostEqual(gamma.get_x(1.0), 1)
        self.assertAlmostEqual(gamma.get_y(1.0)[0], 1)
        self.assertAlmostEqual(gamma.get_y(1.0)[1], -1)

        # swap the base sheets
        PF = RiemannSurfacePathFactory(self.X1, base_point=-1,
                                       base_sheets=[1.j,-1.j])
        gamma_x = ComplexArc(1, 0, pi, pi)
        gamma = PF.RiemannSurfacePath_from_complex_path(gamma_x)
        self.assertAlmostEqual(gamma.get_x(1.0), 1)
        self.assertAlmostEqual(gamma.get_y(1.0)[0], -1)
        self.assertAlmostEqual(gamma.get_y(1.0)[1], 1)
Exemple #12
0
 def test_indexing(self):
     gamma0 = ComplexLine(-1, 0)
     gamma1 = ComplexLine(0, 1.j)
     gamma2 = ComplexArc(1, 0, pi / 2, -pi / 2)
     gamma = gamma0 + gamma1 + gamma2
     self.assertEqual(gamma.segments, [gamma0, gamma1, gamma2])
     self.assertEqual(gamma[0], gamma0)
     self.assertEqual(gamma[1], gamma1)
     self.assertEqual(gamma[2], gamma2)
Exemple #13
0
 def test_composite(self):
     x1 = (sqrt(2) + sqrt(2) * 1.j) / 2
     gamma = ComplexLine(0, x1) + ComplexArc(1, 0, pi / 4, 3 * pi / 5)
     gamma_rev = gamma.reverse()
     self.assertAlmostEqual(gamma(0.0), gamma_rev(1.0))
     self.assertAlmostEqual(gamma(0.1), gamma_rev(0.9))
     self.assertAlmostEqual(gamma(0.25), gamma_rev(0.75))
     self.assertAlmostEqual(gamma(0.50), gamma_rev(0.50))
     self.assertAlmostEqual(gamma(0.75), gamma_rev(0.25))
     self.assertAlmostEqual(gamma(1.0), gamma_rev(0.0))
Exemple #14
0
    def monodromy_path(self, bi, nrots=1):
        """Returns the complex path starting from the base point, going around the
        discriminant point `bi` `nrots` times, and returning to the base
        x-point.

        The sign of `nrots` indicates the sign of the direction.

        Parameters
        ----------
        bi : complex
            A discriminant point.
        nrots : integer (default `1`)
            A number of rotations around this discriminant point.

        Returns
        -------
        path : ComplexPath
            A complex path representing the monodromy path with `nrots`
            rotations about the discriminant point `bi`.

        """
        if bi in [infinity, numpy.Infinity, 'oo']:
            return self.monodromy_path_infinity(nrots=nrots)

        path_to_bi = self.path_to_discriminant_point(bi)

        # determine the rotational path around the discriminant point
        z = path_to_bi(1.0)
        bi = complex(bi)
        Ri = self.radius(bi)
        theta = angle(z - bi)
        dtheta = numpy.pi if nrots > 0 else -numpy.pi
        circle = ComplexArc(Ri, bi, theta, dtheta) + \
                 ComplexArc(Ri, bi, theta + dtheta, dtheta)
        path_around_bi = circle
        for _ in range(abs(nrots)-1):
            path_around_bi += circle

        # the monodromy path is the sum of the path to the point, the
        # rotational part, and the return path to the base point
        path = path_to_bi + path_around_bi + path_to_bi.reverse()
        return path
Exemple #15
0
    def tests_monodromy(self):
        gammax = ComplexArc(1, 0, 0, 2 * pi)
        y0 = [-1, 1]
        gamma = RiemannSurfacePathSmale(self.X1, gammax, y0)

        y = gamma.get_y(0.0)
        self.assertAlmostEqual(y[0], -1)
        self.assertAlmostEqual(y[1], 1)

        y = gamma.get_y(1.0)
        self.assertAlmostEqual(y[0], 1)
        self.assertAlmostEqual(y[1], -1)
    def test_simple_composite(self):
        gammax1 = ComplexLine(4,1)
        gamma1 = RiemannSurfacePathSmale(self.X1, gammax1, [-2,2])
        gammax2 = ComplexArc(1,0,0,pi)
        gamma2 = RiemannSurfacePathSmale(self.X1, gammax2, [-1,1])
        gamma = gamma1 + gamma2
        nu = lambda x,y: y
        nu_gamma = gamma.parameterize(nu)

        val = nu_gamma(0.0)
        test = gammax1.derivative(0.0)*(-2)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.25)
        test = gammax1.derivative(0.5)*(-sqrt(2.5))
        self.assertAlmostEqual(val, test)

        eps = 1e-12
        val = nu_gamma(0.5-eps)
        test = gammax1.derivative(1.0-eps/2)*(-1)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.5)
        test = gammax2.derivative(0.0)*(-1)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.5+eps)
        test = gammax2.derivative(eps/2)*(-1)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.75)
        test = gammax2.derivative(0.5)*(-sqrt(1.j))
        self.assertAlmostEqual(val, test)

        val = nu_gamma(1.0)
        test = gammax2.derivative(1.0)*(-1.j)
        self.assertAlmostEqual(val, test)
Exemple #17
0
    def test_iteration_reverse(self):
        gamma0 = ComplexLine(-1, 0)
        gamma1 = ComplexLine(0, 1.j)
        gamma2 = ComplexArc(1, 0, pi / 2, -pi / 2)
        gamma = gamma0 + gamma1 + gamma2

        index = 0
        for segment in gamma[::-1]:
            if index == 0:
                self.assertEqual(segment, gamma2)
            elif index == 1:
                self.assertEqual(segment, gamma1)
            elif index == 2:
                self.assertEqual(segment, gamma0)
            index += 1
Exemple #18
0
 def test_arc_derivative(self):
     # arc from theta=0 to theta=pi/2 on the unit circle
     gamma = ComplexArc(1, 0, 0, pi / 2)
     scale = 1.j * pi / 2
     self.assertAlmostEqual(gamma.derivative(0), scale)
     self.assertAlmostEqual(gamma.derivative(0.5),
                            scale * exp(1.j * pi / 4))
     self.assertAlmostEqual(gamma.derivative(0.75),
                            scale * exp(1.j * 3 * pi / 8))
     self.assertAlmostEqual(gamma.derivative(1), scale * exp(1.j * pi / 2))
Exemple #19
0
    def test_simple_composite(self):
        gammax1 = ComplexLine(4, 1)
        gamma1 = RiemannSurfacePathSmale(self.X1, gammax1, [-2, 2])
        gammax2 = ComplexArc(1, 0, 0, pi)
        gamma2 = RiemannSurfacePathSmale(self.X1, gammax2, [-1, 1])
        gamma = gamma1 + gamma2
        nu = lambda x, y: y
        nu_gamma = gamma.parameterize(nu)

        val = nu_gamma(0.0)
        test = gammax1.derivative(0.0) * (-2)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.25)
        test = gammax1.derivative(0.5) * (-sqrt(2.5))
        self.assertAlmostEqual(val, test)

        eps = 1e-12
        val = nu_gamma(0.5 - eps)
        test = gammax1.derivative(1.0 - eps / 2) * (-1)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.5)
        test = gammax2.derivative(0.0) * (-1)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.5 + eps)
        test = gammax2.derivative(eps / 2) * (-1)
        self.assertAlmostEqual(val, test)

        val = nu_gamma(0.75)
        test = gammax2.derivative(0.5) * (-sqrt(1.j))
        self.assertAlmostEqual(val, test)

        val = nu_gamma(1.0)
        test = gammax2.derivative(1.0) * (-1.j)
        self.assertAlmostEqual(val, test)
Exemple #20
0
 def test_arc(self):
     gamma = ComplexArc(1, 0, pi, -pi)
     self.assertEqual(gamma.R, 1)
     self.assertEqual(gamma.w, 0)
     self.assertEqual(gamma.theta, pi)
     self.assertEqual(gamma.dtheta, -pi)
Exemple #21
0
    def avoiding_arc(self, w0, w1, b, R, orientation=None):
        """Returns the arc `(radius, center, starting_theta, dtheta)`, from the points
        `w0` and `w1` on the bounding circle around `bi`.

        The arc is constructed in such a way so that the monodromy properties
        of the path are conserved.

        Parameters
        ----------
        w0 : complex
            The starting point of the arc on the bounding circle of `bi`.
        w1 : complex
            The ending point of the arc on the bounding circle of `bi`.
        b : complex
            The discriminant point to avoid.
        R : double
            The radius of the bounding circle.

        Returns
        -------
        arc : ComplexArc
            An arc from `w0` to `w1` around `bi`.

        """
        w0 = complex(w0)
        w1 = complex(w1)
        b = complex(b)
        R = double(R)

        # ASSUMPTION: Re(w0) < Re(w1)
        if w0.real >= w1.real:
            raise ValueError('Cannot construct avoiding arc: all paths must '
                             'travel from left to right unless "reversed".')

        # ASSERTION: w0 and w1 lie on the circle of radius Ri centered at bi
        R0 = abs(w0 - b)
        R1 = abs(w1 - b)
        if abs(R0 - R) > 1e-13 or abs(R1 - R) > 1e-13:
            raise ValueError('Cannot construct avoiding arc: '
                             '%s and %s must lie on the bounding circle of '
                             'radius %s centered at %s'%(w0,w1,R,b))

        # degenerate case: w0, bi, w1 are co-linear
        #
        # if no orientation is provided then go above. otherwise, adhere to the
        # orientation: orientation = +1/-1 means the path goes above/below
        phi_w0_w1 = numpy.angle(w1-w0)
        phi_w0_b = numpy.angle(b-w0)
        if abs(phi_w0_w1 - phi_w0_b) < 1e-13:
            theta0 = numpy.angle(w0-b)
            dtheta = -numpy.pi  # default above
            if not orientation is None:
                dtheta *= orientation
            return ComplexArc(R, b, theta0, dtheta)

        # otherwise: w0, bi, w1 are not co-linear
        #
        # first determine if the line form w0 to w1 is above or below the
        # branch point bi. this will determine if dtheta is negative or
        # positive, respectively
        if phi_w0_b <= phi_w0_w1:
            dtheta_sign = -1
        else:
            dtheta_sign = 1

        # now determine the angle between w0 and w1 on the circle. since w0,
        # bi, and w1 are not colinear this angle must be normalized to be in
        # the interval (-pi,pi)
        theta0 = numpy.angle(w0 - b)
        theta1 = numpy.angle(w1 - b)
        dtheta = theta1 - theta0
        if dtheta > numpy.pi:
            dtheta = 2*numpy.pi - dtheta
        elif dtheta < -numpy.pi:
            dtheta = 2*numpy.pi + dtheta

        # sanity check: |dtheta| should be less than pi
        if abs(dtheta) >= numpy.pi:
            raise ValueError('Cannot construct avoiding arc: '
                             '|dtheta| must be less than pi.')

        dtheta = dtheta_sign * abs(dtheta)

        # finally, take orentation into account. orientation is a stronger
        # condition than the above computations.
        #
        # in the case when the signs of the orientation and the dtheta are
        # opposite then do nothing since: orentation = +1/-1 implies go
        # above/below implies dtheta negative/positive.
        #
        # when the signs are same then make adjustments:
        if not orientation is None:
            if orientation == 1 and dtheta > 0:
                dtheta = dtheta - 2*numpy.pi
            elif orientation == -1 and dtheta < 0:
                dtheta = 2*numpy.pi + dtheta

        # add the path from z0 to w1 going around bi
        arc = ComplexArc(R, b, theta0, dtheta)
        return arc