module Math.Weierstrass
( halfPeriods,
ellipticInvariants,
weierstrassP,
weierstrassPdash,
weierstrassPinv,
weierstrassSigma,
weierstrassZeta
) where
import Data.Complex ( Complex(..) )
import Internal ( (%^%) )
import Math.Eisenstein ( eisensteinE4,
eisensteinE6,
kleinJinv,
jtheta1DashDashDash0 )
import Math.JacobiTheta ( jtheta2,
jtheta3,
jtheta1,
jtheta4,
jtheta1Dash )
import Math.Gamma ( gamma )
import Math.EllipticIntegrals ( carlsonRF' )
i_ :: Complex Double
i_ = 0.0 :+ 1.0
eisensteinG4 :: Complex Double -> Complex Double
eisensteinG4 tau = pi %^% 4 / 45 * eisensteinE4 tau
eisensteinG6_over_eisensteinG4 :: Complex Double -> Complex Double
eisensteinG6_over_eisensteinG4 tau =
2 * pi * pi / 21 * eisensteinE6 tau / eisensteinE4 tau
omega1_and_tau ::
Complex Double -> Complex Double -> (Complex Double, Complex Double)
omega1_and_tau g2 g3 = (omega1, tau)
where
(omega1, tau)
| g2 == 0 =
(
gamma (1/3) %^% 3 / (4 * pi * g3 ** (1/6)),
0.5 :+ (sqrt 3 / 2)
)
| g3 == 0 =
(
i_ * sqrt(sqrt(3.75 * eisensteinG4 tau' / g2)),
tau'
)
| otherwise =
(
sqrt(7 * g2 * eisensteinG6_over_eisensteinG4 tau' / (12 * g3)),
tau'
)
where
g2cube = g2 * g2 * g2
j = 1728 * g2cube / (g2cube - 27 * g3 * g3)
tau' = kleinJinv j
-- | Half-periods from elliptic invariants.
halfPeriods ::
Complex Double -- ^ g2
-> Complex Double -- ^ g3
-> (Complex Double, Complex Double) -- ^ omega1, omega2
halfPeriods g2 g3 = (omega1, tau * omega1)
where
(omega1, tau) = omega1_and_tau g2 g3
g_from_omega1_and_tau ::
Complex Double -> Complex Double -> (Complex Double, Complex Double)
g_from_omega1_and_tau omega1 tau = (g2, g3)
where
q = exp (i_ * pi * tau)
j2 = jtheta2 0 q
j3 = jtheta3 0 q
j2pow4 = j2 %^% 4
j2pow8 = j2pow4 * j2pow4
j2pow12 = j2pow4 * j2pow8
j3pow4 = j3 %^% 4
j3pow8 = j3pow4 * j3pow4
j3pow12 = j3pow4 * j3pow8
g2 = 4/3 * (pi / 2 / omega1) %^% 4 * (j2pow8 - j2pow4 * j3pow4 + j3pow8)
g3 = 8/27 * (pi / 2 / omega1) %^% 6 *
(j2pow12 - ((1.5 * j2pow8 * j3pow4) + (1.5 * j2pow4 * j3pow8)) + j3pow12)
-- | Elliptic invariants from half-periods.
ellipticInvariants ::
Complex Double -- ^ omega1
-> Complex Double -- ^ omega2
-> (Complex Double, Complex Double) -- ^ g2, g3
ellipticInvariants omega1 omega2 =
g_from_omega1_and_tau omega1 (omega2 / omega1)
weierstrassP_from_tau :: Complex Double -> Complex Double -> Complex Double
weierstrassP_from_tau z tau =
(pi * j2 * j3 * j4 / j1) %^% 2 - pi * pi * (j2 %^% 4 + j3 %^% 4) / 3
where
q = exp (i_ * pi * tau)
j2 = jtheta2 0 q
j3 = jtheta3 0 q
z' = pi * z
j1 = jtheta1 z' q
j4 = jtheta4 z' q
weierstrassP_from_omega ::
Complex Double -> Complex Double -> Complex Double -> Complex Double
weierstrassP_from_omega z omega1 omega2 =
weierstrassP_from_tau
(z / omega1 / 2) (omega2 / omega1) / (4 * omega1 * omega1)
-- | Weierstrass p-function
weierstrassP ::
Complex Double -- ^ z
-> Complex Double -- ^ elliptic invariant g2
-> Complex Double -- ^ elliptic invariant g3
-> Complex Double
weierstrassP z g2 g3 = weierstrassP_from_omega z omega1 omega2
where
(omega1, omega2) = halfPeriods g2 g3
-- | Derivative of Weierstrass p-function
weierstrassPdash ::
Complex Double -- ^ z
-> Complex Double -- ^ elliptic invariant g2
-> Complex Double -- ^ elliptic invariant g3
-> Complex Double
weierstrassPdash z g2 g3 = 2 / (w1 %^% 3) * j2 * j3 * j4 * f
where
(omega1, omega2) = halfPeriods g2 g3
w1 = 2 * omega1 / pi
tau = omega2 / omega1
q = exp (i_ * pi * tau)
z' = z / w1
j1 = jtheta1 z' q
j2 = jtheta2 z' q
j3 = jtheta3 z' q
j4 = jtheta4 z' q
j1dash = jtheta1Dash 0 q
j2zero = jtheta2 0 q
j3zero = jtheta3 0 q
j4zero = jtheta4 0 q
f = j1dash %^% 3 / (j1 %^% 3 * j2zero * j3zero * j4zero)
-- | Inverse of Weierstrass p-function
weierstrassPinv ::
Complex Double -- ^ w
-> Complex Double -- ^ elliptic invariant g2
-> Complex Double -- ^ elliptic invariant g3
-> Complex Double
weierstrassPinv w g2 g3 = carlsonRF' 1e-14 (w - e1) (w - e2) (w - e3)
where
(omega1, omega2) = halfPeriods g2 g3
e1 = weierstrassP omega1 g2 g3
e2 = weierstrassP omega2 g2 g3
e3 = weierstrassP (-omega1 - omega2) g2 g3
-- | Weierstrass sigma function
weierstrassSigma ::
Complex Double -- ^ z
-> Complex Double -- ^ elliptic invariant g2
-> Complex Double -- ^ elliptic invariant g3
-> Complex Double
weierstrassSigma z g2 g3 = w1 * exp (h * z * z1 / pi) * j1 / j1dash
where
(omega1, omega2) = halfPeriods g2 g3
tau = omega2 / omega1
q = exp (i_ * pi * tau)
w1 = -2 * omega1 / pi
z1 = z / w1
j1 = jtheta1 z1 q
j1dash = jtheta1Dash 0 q
h = - pi / (6 * w1) * jtheta1DashDashDash0 tau / j1dash
-- | Weierstrass zeta function
weierstrassZeta ::
Complex Double -- ^ z
-> Complex Double -- ^ elliptic invariant g2
-> Complex Double -- ^ elliptic invariant g3
-> Complex Double
weierstrassZeta z g2 g3 = - eta1 * z + p * lj1dash
where
(omega1, omega2) = halfPeriods g2 g3
tau = omega2 / omega1
q = exp (i_ * pi * tau)
w1 = - omega1 / pi
p = 0.5 / w1
j1dash = jtheta1Dash 0 q
eta1 = p * jtheta1DashDashDash0 tau / (6 * w1 * j1dash)
pz = p * z
lj1dash = jtheta1Dash pz q / jtheta1 pz q