{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP #-}
module Physics.Learn.BeamStack
(
BeamStack()
, randomBeam
, split
, recombine
, applyBField
, dropBeam
, flipBeams
, numBeams
, detect
, splitX
, splitY
, splitZ
, applyBFieldX
, applyBFieldY
, applyBFieldZ
, recombineX
, recombineY
, recombineZ
, xpFilter
, xmFilter
, zpFilter
, zmFilter
)
where
import Physics.Learn.QuantumMat
( zp
, zm
, nm
, np
, couter
, oneQubitMixed
)
import Numeric.LinearAlgebra
( C
, Vector
, Matrix
, iC
, (<>)
, kronecker
, fromLists
, toList
, toLists
, scale
, size
, takeDiag
, ident
, tr
)
import Data.Complex
( Complex(..)
, realPart
, imagPart
)
import Data.List
( intercalate
)
#if MIN_VERSION_base(4,11,0)
import Prelude hiding ((<>))
#endif
data BeamStack = BeamStack (Matrix C)
showOneBeam :: Double -> String
showOneBeam r = "Beam of intensity " ++ show r
instance Show BeamStack where
show b = intercalate "\n" $ map showOneBeam (detect b)
randomBeam :: BeamStack
randomBeam = BeamStack oneQubitMixed
extendWithZeros :: Matrix C -> Matrix C
extendWithZeros m
= let (_,q) = size m
ml = toLists m
in fromLists $ map (++ [0,0]) ml
++ [replicate (q+2) 0, replicate (q+2) 0]
reduceMat :: Matrix C -> Matrix C
reduceMat m
= let (p,q) = size m
ml = toLists m
in fromLists $ take (p-2) $ map (take (q-2)) ml
checkedRealPart :: C -> Double
checkedRealPart c
= let eps = 1e-14
in if imagPart c < eps
then realPart c
else error $ "checkRealPart: imagPart = " ++ show (imagPart c)
detect :: BeamStack -> [Double]
detect (BeamStack m)
= addAlternate $ toList $ takeDiag m
addAlternate :: [C] -> [Double]
addAlternate [] = []
addAlternate [_] = error "addAlternate needs even number of elements"
addAlternate (x:y:xs) = checkedRealPart (x+y) : addAlternate xs
dropBeam :: BeamStack -> BeamStack
dropBeam (BeamStack m) = BeamStack (reduceMat m)
numBeams :: BeamStack -> Int
numBeams (BeamStack m)
= let (p,_) = size m
in p `div` 2
flipBeams :: BeamStack -> BeamStack
flipBeams (BeamStack m)
= let (d,_) = size m
fl = flipMat d
in BeamStack $ fl <> m <> tr fl
flipMat :: Int -> Matrix C
flipMat d = bigM d (fromLists [[0,0,1,0]
,[0,0,0,1]
,[1,0,0,0]
,[0,1,0,0]])
bigM2 :: Int -> Matrix C -> Matrix C
bigM2 d m
| d < 2 = error "bigM2 requires d >= 2"
| odd d = error "bigM2 requires even d"
| otherwise = fromLists $ map (++ [0,0]) (toLists (ident (d-2)))
++ map (replicate (d-2) 0 ++) (toLists m)
bigM :: Int -> Matrix C -> Matrix C
bigM d m
| d < 4 = error "bigM requires d >= 4"
| odd d = error "bigM requires even d"
| otherwise = fromLists $ map (++ [0,0,0,0]) (toLists (ident (d-4)))
++ map (replicate (d-4) 0 ++) (toLists m)
s :: Double -> Double -> Matrix C
s theta phi = kronecker (u `couter` u) (np theta phi `couter` np theta phi)
+ kronecker (l `couter` u) (nm theta phi `couter` nm theta phi)
+ kronecker (u `couter` l) (nm theta phi `couter` nm theta phi)
+ kronecker (l `couter` l) (np theta phi `couter` np theta phi)
u :: Vector C
u = zp
l :: Vector C
l = zm
split :: Double -> Double -> BeamStack -> BeamStack
split theta phi (BeamStack m)
= let m' = extendWithZeros m
(p,_) = size m'
ss = bigM p (s theta phi)
in BeamStack $ ss <> m' <> tr ss
recombine :: Double -> Double -> BeamStack -> BeamStack
recombine theta phi (BeamStack m)
= let (d,_) = size m
ss = bigM d (s theta phi)
in dropBeam $ BeamStack $ ss <> m <> tr ss
mag2x2 :: Double -> Double -> Double -> Matrix C
mag2x2 theta phi omegaT
= let z = iC * (omegaT :+ 0) / 2
np' = np theta phi
nm' = nm theta phi
in scale (exp z ) (np' `couter` np')
+ scale (exp (-z)) (nm' `couter` nm')
applyBField :: Double -> Double -> Double -> BeamStack -> BeamStack
applyBField theta phi omegaT (BeamStack m)
= let (d,_) = size m
uu = bigM2 d (mag2x2 theta phi omegaT)
in BeamStack $ uu <> m <> tr uu
splitX :: BeamStack -> BeamStack
splitX = split (pi/2) 0
splitY :: BeamStack -> BeamStack
splitY = split (pi/2) (pi/2)
splitZ :: BeamStack -> BeamStack
splitZ = split 0 0
applyBFieldX :: Double -> BeamStack -> BeamStack
applyBFieldX = applyBField (pi/2) 0
applyBFieldY :: Double -> BeamStack -> BeamStack
applyBFieldY = applyBField (pi/2) (pi/2)
applyBFieldZ :: Double -> BeamStack -> BeamStack
applyBFieldZ = applyBField 0 0
recombineX :: BeamStack -> BeamStack
recombineX = recombine (pi/2) 0
recombineY :: BeamStack -> BeamStack
recombineY = recombine (pi/2) (pi/2)
recombineZ :: BeamStack -> BeamStack
recombineZ = recombine 0 0
xpFilter :: BeamStack -> BeamStack
xpFilter = dropBeam . splitX
xmFilter :: BeamStack -> BeamStack
xmFilter = dropBeam . flipBeams . splitX
zpFilter :: BeamStack -> BeamStack
zpFilter = dropBeam . splitZ
zmFilter :: BeamStack -> BeamStack
zmFilter = dropBeam . flipBeams . splitZ