# Path: cxroots/Paths.py
# class ComplexArc(ComplexPath):
#     r"""
#     A circular arc :math:`z` with center z0, radius R, initial angle t0
#     and change of angle dt.  The arc is parameterised by
# 
#     ..math::
# 
#         z(t) = R e^{i(t0 + t dt)} + z0, \quad 0\leq t \leq 1
# 
#     Parameters
#     ----------
#     z0 : complex
#     R : float
#     t0 : float
#     dt : float
#     """
# 
#     def __init__(self, z0, R, t0, dt):
#         self.z0, self.R, self.t0, self.dt = z0, R, t0, dt
#         self.dzdt = lambda t: 1j * self.dt * self.R * exp(1j * (self.t0 + t * self.dt))
#         super(ComplexArc, self).__init__()
# 
#     def __str__(self):
#         return "ComplexArc: z0=%.3f, R=%.3f, t0=%.3f, dt=%.3f" % (
#             self.z0,
#             self.R,
#             self.t0,
#             self.dt,
#         )
# 
#     def __call__(self, t):
#         r"""
#         The function :math:`z(t) = R e^{i(t_0 + t dt)} + z_0`.
# 
#         Parameters
#         ----------
#         t : float
#             A real number :math:`0\leq t \leq 1`.
# 
#         Returns
#         -------
#         complex
#             A point on the arc in the complex plane.
#         """
#         return self.R * exp(1j * (self.t0 + t * self.dt)) + self.z0
# 
#     def distance(self, z):
#         """
#         Distance from the point z to the closest point on the arc.
# 
#         Parameters
#         ----------
#         z : complex
# 
#         Returns
#         -------
#         float
#             The distance from z to the point on the arc which is closest
#             to z.
#         """
#         theta = np.angle(z - self.z0)  # np.angle maps to (-pi,pi]
#         theta = (theta - self.t0) % (2 * pi) + self.t0  # put theta in [t0,t0+2pi)
# 
#         if (self.dt > 0 and self.t0 < theta < self.t0 + self.dt) or (
#             self.dt < 0 and self.t0 + self.dt < theta - 2 * pi < self.t0
#         ):
#             # the closest point to z lies on the arc
#             return abs(self.R * exp(1j * theta) + self.z0 - z)
#         else:
#             # the closest point to z is one of the endpoints
#             return min(abs(self(0) - z), abs(self(1) - z))
# 
# class ComplexLine(ComplexPath):
#     r"""
#     A straight line :math:`z` in the complex plane from a to b
#     parameterised by
# 
#     ..math::
# 
#         z(t) = a + (b-a)t, \quad 0\leq t \leq 1
# 
# 
#     Parameters
#     ----------
#     a : float
#     b : float
#     """
# 
#     def __init__(self, a, b):
#         self.a, self.b = a, b
#         self.dzdt = lambda t: self.b - self.a
#         super(ComplexLine, self).__init__()
# 
#     def __str__(self):
#         return "ComplexLine from %.3f+%.3fi to %.3f+%.3fi" % (
#             self.a.real,
#             self.a.imag,
#             self.b.real,
#             self.b.imag,
#         )
# 
#     def __call__(self, t):
#         r"""
#         The function :math:`z(t) = a + (b-a)t`.
# 
#         Parameters
#         ----------
#         t : float
#             A real number :math:`0\leq t \leq 1`.
# 
#         Returns
#         -------
#         complex
#             A point on the line in the complex plane.
#         """
#         return self.a + t * (self.b - self.a)
# 
#     def distance(self, z):
#         """
#         Distance from the point z to the closest point on the line.
# 
#         Parameters
#         ----------
#         z : complex
# 
#         Returns
#         -------
#         float
#             The distance from z to the point on the line which is
#             closest to z.
#         """
#         # convert complex numbers to vectors
#         A = np.array([self.a.real, self.a.imag])
#         B = np.array([self.b.real, self.b.imag])
#         Z = np.array([z.real, z.imag])
# 
#         # the projection of the point z onto the line a -> b is where
#         # the parameter t is
#         t = (Z - A).dot(B - A) / abs((B - A).dot(B - A))
# 
#         # but the line segment only has 0 <= t <= 1
#         t = t.clip(0, 1)
# 
#         # so the point on the line segment closest to z is
#         c = self(t)
#         return abs(c - z)


import pytest
import numpy as np
from numpy import pi
from numpy.random import uniform
from cxroots.Paths import ComplexArc, ComplexLine
from datetime import date



# have a common seed for each testing process

today = date.today()
np.random.seed(today.year * today.month * today.day)


@pytest.mark.parametrize("a", uniform(-10, 10, size=3) + 1j * uniform(-10, 10, size=3))
@pytest.mark.parametrize("b", uniform(-10, 10, size=3) + 1j * uniform(-10, 10, size=3))
@pytest.mark.parametrize("P", uniform(-10, 10, size=3) + 1j * uniform(-10, 10, size=3))
def test_distance_line(a, b, P):
    t = np.linspace(0, 1, 100001)

# Path: cxroots/Paths.py
# class ComplexArc(ComplexPath):
#     r"""
#     A circular arc :math:`z` with center z0, radius R, initial angle t0
#     and change of angle dt.  The arc is parameterised by
# 
#     ..math::
# 
#         z(t) = R e^{i(t0 + t dt)} + z0, \quad 0\leq t \leq 1
# 
#     Parameters
#     ----------
#     z0 : complex
#     R : float
#     t0 : float
#     dt : float
#     """
# 
#     def __init__(self, z0, R, t0, dt):
#         self.z0, self.R, self.t0, self.dt = z0, R, t0, dt
#         self.dzdt = lambda t: 1j * self.dt * self.R * exp(1j * (self.t0 + t * self.dt))
#         super(ComplexArc, self).__init__()
# 
#     def __str__(self):
#         return "ComplexArc: z0=%.3f, R=%.3f, t0=%.3f, dt=%.3f" % (
#             self.z0,
#             self.R,
#             self.t0,
#             self.dt,
#         )
# 
#     def __call__(self, t):
#         r"""
#         The function :math:`z(t) = R e^{i(t_0 + t dt)} + z_0`.
# 
#         Parameters
#         ----------
#         t : float
#             A real number :math:`0\leq t \leq 1`.
# 
#         Returns
#         -------
#         complex
#             A point on the arc in the complex plane.
#         """
#         return self.R * exp(1j * (self.t0 + t * self.dt)) + self.z0
# 
#     def distance(self, z):
#         """
#         Distance from the point z to the closest point on the arc.
# 
#         Parameters
#         ----------
#         z : complex
# 
#         Returns
#         -------
#         float
#             The distance from z to the point on the arc which is closest
#             to z.
#         """
#         theta = np.angle(z - self.z0)  # np.angle maps to (-pi,pi]
#         theta = (theta - self.t0) % (2 * pi) + self.t0  # put theta in [t0,t0+2pi)
# 
#         if (self.dt > 0 and self.t0 < theta < self.t0 + self.dt) or (
#             self.dt < 0 and self.t0 + self.dt < theta - 2 * pi < self.t0
#         ):
#             # the closest point to z lies on the arc
#             return abs(self.R * exp(1j * theta) + self.z0 - z)
#         else:
#             # the closest point to z is one of the endpoints
#             return min(abs(self(0) - z), abs(self(1) - z))
# 
# class ComplexLine(ComplexPath):
#     r"""
#     A straight line :math:`z` in the complex plane from a to b
#     parameterised by
# 
#     ..math::
# 
#         z(t) = a + (b-a)t, \quad 0\leq t \leq 1
# 
# 
#     Parameters
#     ----------
#     a : float
#     b : float
#     """
# 
#     def __init__(self, a, b):
#         self.a, self.b = a, b
#         self.dzdt = lambda t: self.b - self.a
#         super(ComplexLine, self).__init__()
# 
#     def __str__(self):
#         return "ComplexLine from %.3f+%.3fi to %.3f+%.3fi" % (
#             self.a.real,
#             self.a.imag,
#             self.b.real,
#             self.b.imag,
#         )
# 
#     def __call__(self, t):
#         r"""
#         The function :math:`z(t) = a + (b-a)t`.
# 
#         Parameters
#         ----------
#         t : float
#             A real number :math:`0\leq t \leq 1`.
# 
#         Returns
#         -------
#         complex
#             A point on the line in the complex plane.
#         """
#         return self.a + t * (self.b - self.a)
# 
#     def distance(self, z):
#         """
#         Distance from the point z to the closest point on the line.
# 
#         Parameters
#         ----------
#         z : complex
# 
#         Returns
#         -------
#         float
#             The distance from z to the point on the line which is
#             closest to z.
#         """
#         # convert complex numbers to vectors
#         A = np.array([self.a.real, self.a.imag])
#         B = np.array([self.b.real, self.b.imag])
#         Z = np.array([z.real, z.imag])
# 
#         # the projection of the point z onto the line a -> b is where
#         # the parameter t is
#         t = (Z - A).dot(B - A) / abs((B - A).dot(B - A))
# 
#         # but the line segment only has 0 <= t <= 1
#         t = t.clip(0, 1)
# 
#         # so the point on the line segment closest to z is
#         c = self(t)
#         return abs(c - z)


# Path: cxroots/tests/test_paths.py
import pytest
import numpy as np
from numpy import pi
from numpy.random import uniform
from cxroots.Paths import ComplexArc, ComplexLine
from datetime import date




# have a common seed for each testing process

today = date.today()
np.random.seed(today.year * today.month * today.day)


@pytest.mark.parametrize("a", uniform(-10, 10, size=3) + 1j * uniform(-10, 10, size=3))
@pytest.mark.parametrize("b", uniform(-10, 10, size=3) + 1j * uniform(-10, 10, size=3))
@pytest.mark.parametrize("P", uniform(-10, 10, size=3) + 1j * uniform(-10, 10, size=3))
def test_distance_line(a, b, P):
    t = np.linspace(0, 1, 100001)

    C = ComplexLine(a, b)