jacobi-theta-0.1.2.0: src/Math/JacobiTheta.hs
module Math.JacobiTheta
(
jtheta1Dash,
jtheta1,
jtheta2,
jtheta3,
jtheta4
)
where
import Data.Complex
type Cplx = Complex Double
i_ :: Cplx
i_ = 0.0 :+ 1.0
machinePrecision :: Double
machinePrecision = 2**(-52)
areClose :: Cplx -> Cplx -> Bool
areClose z1 z2 = magnitude (z1 - z2) < epsilon * h
where
epsilon = 2.0 * machinePrecision
magn2 = magnitude z2
h = if magn2 < epsilon then 1.0 else max (magnitude z1) magn2
square :: Cplx -> Cplx
square z = z * z
jtheta1Alt1 :: Cplx -> Cplx -> Cplx
jtheta1Alt1 z q =
go 0 (0.0 :+ 0.0) 1.0 (1.0 / qsq) 1.0
where
qsq = q * q
go :: Int -> Cplx -> Cplx -> Cplx -> Cplx -> Cplx
go n out alt q_2n q_n_np1
| n > 3000 = error "Reached 3000 iterations."
| areClose out outnew = 2.0 * sqrt (sqrt q) * out
| otherwise = go (n + 1) outnew (-alt) q_2np1 q_np1_np2
where
q_2np1 = q_2n * qsq
q_np1_np2 = q_n_np1 * q_2np1
n' = fromIntegral n
k = 2.0 * n' + 1.0
outnew = out + alt * q_np1_np2 * sin (k * z)
-- jtheta1(z, tau) = jtheta1Alt2 (z/pi) (-i_ * tau/pi)
jtheta1Alt2 :: Cplx -> Cplx -> Cplx
jtheta1Alt2 z' t' =
let nm = round (0.5 - realPart z') in
let np = nm + 1 in
go nm np (0.0 :+ 0.0) (if even np then (-1, 1) else (1, -1))
where
go :: Int -> Int -> Cplx -> (Cplx, Cplx) -> Cplx
go nminus nplus series (altm, altp)
| nplus - nminus > 3000 = error "Reached 3000 iterations."
| (nplus - nminus > 2) && areClose series newseries =
series / sqrt (pi * t')
| otherwise = go (nminus - 1) (nplus + 1) newseries (-altm, -altp)
where
nminus' = fromIntegral nminus
nplus' = fromIntegral nplus
termm = altm * exp (- square (nminus' - 0.5 + z') / t')
termp = altp * exp (- square (nplus' - 0.5 + z') / t')
newseries = series + termm + termp
--falpha :: Cplx -> Cplx -> Cplx
--falpha z tau =
-- sqrt (-i_ * tau) * exp (i_ / tau * z * z / pi)
jtheta1Alt :: Cplx -> Cplx -> Cplx
jtheta1Alt z tau =
if imagPart tau > 1.3
then
jtheta1Alt1 z (exp (i_ * pi * tau))
-- let w = pi * tau in
-- i_ * jtheta1Alt2 (z / w) (i_ / w) / falpha z tau
else
let t = - i_ * tau / pi in
jtheta1Alt2 (z / pi) t
-- i_ * jtheta1Alt1 (z / tau) (exp (-i_ * pi / tau)) / falpha z tau
tauFromQ :: Cplx -> Cplx
tauFromQ q = -i_ * log q / pi
checkQ :: Cplx -> Cplx
checkQ q
| magnitude q >= 1 =
error "The modulus of the nome must be smaller than one."
| imagPart q == 0 && realPart q <= 0 =
error "If the nome is real, it must be positive."
| otherwise = q
getTauFromQ :: Cplx -> Cplx
getTauFromQ = tauFromQ . checkQ
expM :: Cplx -> Cplx -> Cplx
expM z tau = exp (i_ * (z + tau * pi/4))
-- | First Jacobi theta function
jtheta1 ::
Complex Double -- ^ z
-> Complex Double -- ^ q, the nome
-> Complex Double
jtheta1 z q = jtheta1Alt z (getTauFromQ q)
-- | Second Jacobi theta function
jtheta2 ::
Complex Double -- ^ z
-> Complex Double -- ^ q, the nome
-> Complex Double
jtheta2 z = jtheta1 (z + pi/2)
-- | Third Jacobi theta function
jtheta3 ::
Complex Double -- ^ z
-> Complex Double -- ^ q, the nome
-> Complex Double
jtheta3 z q = jtheta2 (z - pi/2 * tau) q * expM (-z) tau
where
tau = tauFromQ q
-- | Fourth Jacobi theta function
jtheta4 ::
Complex Double -- ^ z
-> Complex Double -- ^ q, the nome
-> Complex Double
jtheta4 z = jtheta3 (z + pi/2)
-- | Derivative of the first Jacobi theta function
jtheta1Dash ::
Complex Double -- ^ z
-> Complex Double -- ^ q, the nome
-> Complex Double
jtheta1Dash z q =
go 0 (0.0 :+ 0.0) 1.0 (1.0 / qsq) 1.0
where
q' = checkQ q
qsq = q' * q'
go :: Int -> Cplx -> Cplx -> Cplx -> Cplx -> Cplx
go n out alt q_2n q_n_np1
| n > 3000 = error "Reached 3000 iterations."
| areClose out outnew = 2.0 * sqrt (sqrt q) * out
| otherwise = go (n + 1) outnew (-alt) q_2np1 q_np1_np2
where
q_2np1 = q_2n * qsq
q_np1_np2 = q_n_np1 * q_2np1
n' = fromIntegral n
k = 2.0 * n' + 1.0
outnew = out + k * alt * q_np1_np2 * cos (k * z)