{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ConstraintKinds #-}

#ifndef O_LIQUID
{- LANGUAGE Safe -}
#endif

#if __GLASGOW_HASKELL__ == 810
-- Work around to fix GHC Issue #15304, issue popped up again in GHC 8.10, it should be fixed in GHC 8.12
-- This code is meant to reproduce MR 2608 for GHC 8.10
{-# OPTIONS_GHC -funfolding-keeness-factor=1 -funfolding-use-threshold=80 #-}
#endif

--------------------------------------------------------------------------------------------
-- |
-- Copyright   :  (C) 2018-2024 Nathan Waivio
-- License     :  BSD3
-- Maintainer  :  Nathan Waivio <nathan.waivio@gmail.com>
-- Stability   :  Stable
-- Portability :  unportable
--
-- Library implementing standard functions for the Jones Calculus in the Cl3 Library.
-- This implementation of the Jones Calculus is based on the convensions of SPIE's Field Guide to Polarization (ϕ = ω t − k z).
-- 
-- * E. Collett, Field Guide to Polarization, SPIE Field Guides vol. FG05, SPIE (2005). ISBN 0-8194-5868-6.
-- 
--  
-- = Jones Vectors
-- 
-- Within the system of the Bloch Sphere, the Jones Vectors in Cl3 are calculated
-- by generating the left ideal of the rotation of a unit vector to the 'e3' basis.
-- Standard form for for a versor is 'rot = exp $ (-i/2) * theta * u' for angle 'theta'
-- and the rotational axis unit vector 'u'.
--
--          Bloch Sphere Coordinates:
-- 
-- @
--                 e3
--                 |
--                 |____e2
--                / 
--               /
--              e1
-- @
--
--------------------------------------------

module Posit.Cl3.JonesCalculus
(
 -- * Jones Vectors
 hpv, vpv,
 dpv, apv,
 rpv, lpv,
 jv,
 -- * Jones Matrices
 hpm, vpm,
 dpm, apm,
 rpm, lpm,
 jm,
 hpmRot,
 -- * Wave Plates
 qwp, hwp,
 qwpRot, hwpRot,
 wp,
 wpRot,
 -- * Reflection
 refl,
#ifndef O_NO_RANDOM
 -- * Random Jones Vectors
 randJonesVec,
 randOrthogonalJonesVec,
#endif
 -- * Normalization Factorization
 factorize
) where



import Posit.Cl3 ( Cl3( R, V3, I)
                 , dag
                 , bar
                 , toR
                 , toV3
                 , toC
                 , project
                 , randUnitV3 )

-- import Posit hiding (R, phi)
import Posit.Internal.PositC



#ifndef O_NO_RANDOM
-- import safe Algebra.Geometric.Cl3 (randUnitV3)
import System.Random (RandomGen)
#endif

e0 :: PositC es => Cl3 es
e0 :: forall (es :: ES). PositC es => Cl3 es
e0 = Posit es -> Cl3 es
forall (es :: ES). PositC es => Posit es -> Cl3 es
R Posit es
1
e1 :: PositC es => Cl3 es
e1 :: forall (es :: ES). PositC es => Cl3 es
e1 = Posit es -> Posit es -> Posit es -> Cl3 es
forall (es :: ES).
PositC es =>
Posit es -> Posit es -> Posit es -> Cl3 es
V3 Posit es
1 Posit es
0 Posit es
0
e2 :: PositC es => Cl3 es
e2 :: forall (es :: ES). PositC es => Cl3 es
e2 = Posit es -> Posit es -> Posit es -> Cl3 es
forall (es :: ES).
PositC es =>
Posit es -> Posit es -> Posit es -> Cl3 es
V3 Posit es
0 Posit es
1 Posit es
0
e3 :: PositC es => Cl3 es
e3 :: forall (es :: ES). PositC es => Cl3 es
e3 = Posit es -> Posit es -> Posit es -> Cl3 es
forall (es :: ES).
PositC es =>
Posit es -> Posit es -> Posit es -> Cl3 es
V3 Posit es
0 Posit es
0 Posit es
1

i :: PositC es => Cl3 es
i :: forall (es :: ES). PositC es => Cl3 es
i = Posit es -> Cl3 es
forall (es :: ES). PositC es => Posit es -> Cl3 es
I Posit es
1

p1 :: PositF es => Cl3 es
p1 :: forall (es :: ES). PositF es => Cl3 es
p1 = Cl3 es
0.5 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (Cl3 es
forall (es :: ES). PositC es => Cl3 es
e0 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
+ Cl3 es
forall (es :: ES). PositC es => Cl3 es
e1)
p2 :: PositF es => Cl3 es
p2 :: forall (es :: ES). PositF es => Cl3 es
p2 = Cl3 es
0.5 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (Cl3 es
forall (es :: ES). PositC es => Cl3 es
e0 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
+ Cl3 es
forall (es :: ES). PositC es => Cl3 es
e2)
p3 :: PositF es => Cl3 es
p3 :: forall (es :: ES). PositF es => Cl3 es
p3 = Cl3 es
0.5 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (Cl3 es
forall (es :: ES). PositC es => Cl3 es
e0 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
+ Cl3 es
forall (es :: ES). PositC es => Cl3 es
e3)




-- | 'hpv' horizontally polarized Jones vector
hpv :: PositF es => Cl3 es
hpv :: forall (es :: ES). PositF es => Cl3 es
hpv = Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ Cl3 es
forall (es :: ES). PositC es => Cl3 es
e0 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3  -- e0 == exp $ (-i/2) * 0 * e2, any vector orthoganl to e3 could have been selected as the rotational axis because the angle is zero

-- | 'vpv' vertically polarized Jones vector
vpv :: PositF es => Cl3 es
vpv :: forall (es :: ES). PositF es => Cl3 es
vpv = Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ Cl3 es -> Cl3 es
forall a. Floating a => a -> a
exp ((-Cl3 es
forall (es :: ES). PositC es => Cl3 es
iCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall a. Floating a => a
pi Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositC es => Cl3 es
e2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3  -- e2 is selected to obtain the standard form, e1 or any vector orthoganl to e3 could have been selected

-- | 'dpv' diagonally polarized Jones vector
dpv :: PositF es => Cl3 es
dpv :: forall (es :: ES). PositF es => Cl3 es
dpv = Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ Cl3 es -> Cl3 es
forall a. Floating a => a -> a
exp ((-Cl3 es
forall (es :: ES). PositC es => Cl3 es
iCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (Cl3 es
forall a. Floating a => a
piCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositC es => Cl3 es
e2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3  -- rotate -e1 to e3 around rotational axis e2, an angle of pi/2

-- | 'apv' anti-diagonally polarized Jones vector
apv :: PositF es => Cl3 es
apv :: forall (es :: ES). PositF es => Cl3 es
apv = Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ Cl3 es -> Cl3 es
forall a. Floating a => a -> a
exp ((-Cl3 es
forall (es :: ES). PositC es => Cl3 es
iCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (Cl3 es
forall a. Floating a => a
piCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (-Cl3 es
forall (es :: ES). PositC es => Cl3 es
e2)) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3  -- rotate e1 to e3 around rotational axis -e2, an angle of pi/2

-- | 'rpv' right hand circularly polarized Jones vector
rpv :: PositF es => Cl3 es
rpv :: forall (es :: ES). PositF es => Cl3 es
rpv = Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ Cl3 es -> Cl3 es
forall a. Floating a => a -> a
exp ((-Cl3 es
forall (es :: ES). PositC es => Cl3 es
iCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (Cl3 es
forall a. Floating a => a
piCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (-Cl3 es
forall (es :: ES). PositC es => Cl3 es
e1)) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3  -- rotate -e2 to e3 around rotational axis -e1, and angle of pi/2

-- | 'lpv' left hand circularly polarized Jones vector
lpv :: PositF es => Cl3 es
lpv :: forall (es :: ES). PositF es => Cl3 es
lpv = Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ Cl3 es -> Cl3 es
forall a. Floating a => a -> a
exp ((-Cl3 es
forall (es :: ES). PositC es => Cl3 es
iCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (Cl3 es
forall a. Floating a => a
piCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositC es => Cl3 es
e1) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3  -- rotate e2 to e3 around rotational axis e1, an angle of pi/2

-- | 'jv' function that returns Jones vector from input vector unit vector
-- currently converts the input to a unit vector
jv :: Cl3 es -> Cl3 es
jv (Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum(Cl3 es -> Cl3 es) -> (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toV3 -> Cl3 es
v) | Cl3 es
v Cl3 es -> Cl3 es -> Bool
forall a. Eq a => a -> a -> Bool
== Cl3 es
forall (es :: ES). PositC es => Cl3 es
e3 = Cl3 es
forall (es :: ES). PositF es => Cl3 es
hpv
                      | Cl3 es
v Cl3 es -> Cl3 es -> Bool
forall a. Eq a => a -> a -> Bool
== -Cl3 es
forall (es :: ES). PositC es => Cl3 es
e3 = Cl3 es
forall (es :: ES). PositF es => Cl3 es
vpv
                      | Bool
otherwise = Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ Cl3 es -> Cl3 es
forall a. Floating a => a -> a
sqrt (Cl3 es
forall (es :: ES). PositC es => Cl3 es
e3 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
v) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3


-- | 'hpm' Horizontal Polarizer Jones Matrix
hpm :: PositF es => Cl3 es
hpm :: forall (es :: ES). PositF es => Cl3 es
hpm = Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3

-- | 'vpm' Vertical Polarizer Jones Matrix
vpm :: PositF es => Cl3 es
vpm :: forall (es :: ES). PositF es => Cl3 es
vpm = Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
bar Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3

-- | 'dpm' Diagonal Polarizer Jones Matrix
dpm :: PositF es => Cl3 es
dpm :: forall (es :: ES). PositF es => Cl3 es
dpm = Cl3 es
forall (es :: ES). PositF es => Cl3 es
p1

-- | 'apm' Anti-diagonal Polarizer Jones Matrix
apm :: PositF es => Cl3 es
apm :: forall (es :: ES). PositF es => Cl3 es
apm = Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
bar Cl3 es
forall (es :: ES). PositF es => Cl3 es
p1

-- | 'rpm' Right Hand Circular Polarizer Jones Matrix
rpm :: PositF es => Cl3 es
rpm :: forall (es :: ES). PositF es => Cl3 es
rpm = Cl3 es
forall (es :: ES). PositF es => Cl3 es
p2

-- | 'lpm' Left Hand Circular Polarizer Jones Matrix
lpm :: PositF es => Cl3 es
lpm :: forall (es :: ES). PositF es => Cl3 es
lpm = Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
bar Cl3 es
forall (es :: ES). PositF es => Cl3 es
p2


-- | 'jm' funciton that returns a Jones Matrix from an input Bloch Vector
-- currently converts the input to a unit vector
jm :: Cl3 es -> Cl3 es
jm (Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum(Cl3 es -> Cl3 es) -> (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toV3 -> Cl3 es
v) = Cl3 es -> Cl3 es
forall (es :: ES). PositF es => Cl3 es -> Cl3 es
project Cl3 es
v

-- | 'rot' will produce a versor that rotates a vector by an angle about
-- a unit vector axis.
rot :: Cl3 es -> Cl3 es -> Cl3 es
rot (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toR -> Cl3 es
theta) (Cl3 es -> Cl3 es
forall a. Num a => a -> a
signum(Cl3 es -> Cl3 es) -> (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toV3 -> Cl3 es
axis) = Cl3 es -> Cl3 es
forall a. Floating a => a -> a
exp (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ (-Cl3 es
forall (es :: ES). PositC es => Cl3 es
iCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
theta Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
axis

-- | 'rotIsh' will produce a versor that rotates by double the input angle
-- for rotating polarizers and wave plates the axis is e2.
rotIsh :: Cl3 es -> Cl3 es
rotIsh (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toR -> Cl3 es
theta) = Cl3 es -> Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es -> Cl3 es
rot (Cl3 es
2Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
*Cl3 es
theta) Cl3 es
forall (es :: ES). PositC es => Cl3 es
e2

-- | 'hpmRot' Jones matrix for a rotated ideal Linear Horizontal Polarizer.
-- Input value should be a scalar angle in Radians.
hpmRot :: Cl3 es -> Cl3 es
hpmRot (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toR -> Cl3 es
theta) = 
  let roted :: Cl3 es
roted = Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es
rotIsh Cl3 es
theta
  in Cl3 es
roted Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
hpm Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
dag Cl3 es
roted

-- | 'qwp' Quarter Wave Plate Jones Matrix
qwp :: PositF es => Cl3 es
qwp :: forall (es :: ES). PositF es => Cl3 es
qwp = Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
- Cl3 es
forall (es :: ES). PositC es => Cl3 es
i Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
bar Cl3 es
forall (es :: ES). PositF es => Cl3 es
p3

-- | 'qwpRot' Rotated Quarter Wave Plate Jones Matrix.
-- Input value should be a scalar angle in Radians.
qwpRot :: Cl3 es -> Cl3 es
qwpRot (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toR -> Cl3 es
theta) = 
  let roted :: Cl3 es
roted = Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es
rotIsh Cl3 es
theta
  in Cl3 es
roted Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
qwp Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
dag Cl3 es
roted

-- | 'hwp' Half Wave Plate Jones Matrix
hwp :: PositF es => Cl3 es
hwp :: forall (es :: ES). PositF es => Cl3 es
hwp = Cl3 es
forall (es :: ES). PositC es => Cl3 es
e3

-- | 'hwpRot' Rotated Half Wave Plate Jones Matrix.
-- Input value should be a scalar angle in Radians.
hwpRot :: Cl3 es -> Cl3 es
hwpRot (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toR -> Cl3 es
theta) = 
  let roted :: Cl3 es
roted = Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es
rotIsh Cl3 es
theta
  in Cl3 es
roted Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositF es => Cl3 es
hwp Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
dag Cl3 es
roted

-- | 'wp' a Wave Plate with phase shift of phi Jones Matrix.
-- Input value should be a scalar angle in Radians.
wp :: Cl3 es -> Cl3 es
wp (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toR -> Cl3 es
phi) = Cl3 es -> Cl3 es
forall a. Floating a => a -> a
exp (Cl3 es -> Cl3 es) -> Cl3 es -> Cl3 es
forall a b. (a -> b) -> a -> b
$ (Cl3 es
forall (es :: ES). PositC es => Cl3 es
iCl3 es -> Cl3 es -> Cl3 es
forall a. Fractional a => a -> a -> a
/Cl3 es
2) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
phi Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
forall (es :: ES). PositC es => Cl3 es
e3

-- | 'wpRot' a Rotated Wave Plate with phase shift of phi and rotation theta Jones Matrix.
-- The first input value is phi the phase shift as a scalar value in Radians. The second
-- input value is theta the rotation a scalar angle in Radians.
wpRot :: Cl3 es -> Cl3 es -> Cl3 es
wpRot (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toR -> Cl3 es
phi) (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toR -> Cl3 es
theta) = 
  let roted :: Cl3 es
roted = Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es
rotIsh Cl3 es
theta
  in Cl3 es
roted Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es
wp Cl3 es
phi Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
dag Cl3 es
roted

-- | 'refl' a Refelection Jones Matrix
refl :: PositF es => Cl3 es
refl :: forall (es :: ES). PositF es => Cl3 es
refl = Cl3 es
forall (es :: ES). PositC es => Cl3 es
e3


-- | 'factorize' is a function that takes an Jones Vector after transformation by an 
-- optical chain, and returns the amplitude (amp), phase (phi), and normalized Jones 
-- Vector (vec), by the factorization of the input such that: @__amp * exp (i*phi/2) * vec__@
factorize :: PositF es => Cl3 es -> (Cl3 es, Cl3 es, Cl3 es)
factorize :: forall (es :: ES). PositF es => Cl3 es -> (Cl3 es, Cl3 es, Cl3 es)
factorize Cl3 es
jonesVec = 
  let c :: Cl3 es
c = Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
toC Cl3 es
jonesVec
      jonesVec' :: Cl3 es
jonesVec' = Cl3 es -> Cl3 es
forall a. Fractional a => a -> a
recip Cl3 es
c Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
jonesVec
      ampC :: Cl3 es
ampC = Cl3 es -> Cl3 es
forall a. Num a => a -> a
abs Cl3 es
c
      ampJonesVec' :: Cl3 es
ampJonesVec' = Cl3 es -> Cl3 es
forall a. Num a => a -> a
abs Cl3 es
jonesVec'
      normJonesVec :: Cl3 es
normJonesVec = Cl3 es -> Cl3 es
forall a. Fractional a => a -> a
recip Cl3 es
ampJonesVec' Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
jonesVec'
      amp :: Cl3 es
amp = Cl3 es
ampC Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
ampJonesVec'
      normC :: Cl3 es
normC = Cl3 es -> Cl3 es
forall a. Fractional a => a -> a
recip Cl3 es
ampC Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es
c
      phi :: Cl3 es
phi = Cl3 es
2 Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* (-Cl3 es
forall (es :: ES). PositC es => Cl3 es
i) Cl3 es -> Cl3 es -> Cl3 es
forall a. Num a => a -> a -> a
* Cl3 es -> Cl3 es
forall a. Floating a => a -> a
log Cl3 es
normC
  in (Cl3 es
amp, Cl3 es
phi, Cl3 es
normJonesVec)

#ifndef O_NO_RANDOM
-------------------------------------------------------------------
--
--  Random Jones Vectors
--
-------------------------------------------------------------------

-- | 'randJonesVec' a Random Jones Vector.
randJonesVec :: (PositF es, RandomGen g) => g -> (Cl3 es, g)
randJonesVec :: forall (es :: ES) g. (PositF es, RandomGen g) => g -> (Cl3 es, g)
randJonesVec g
g =
  let (Cl3 es
v3, g
g') = g -> (Cl3 es, g)
forall (es :: ES) g. (PositF es, RandomGen g) => g -> (Cl3 es, g)
randUnitV3 g
g
  in (Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es
jv Cl3 es
v3,g
g')

-- | 'randOrthogonalJonesVec' a Random Orthogonal Complementary pair of Jones
-- Vectors.
randOrthogonalJonesVec :: (PositF es, RandomGen g) => g -> ((Cl3 es, Cl3 es), g)
randOrthogonalJonesVec :: forall (es :: ES) g.
(PositF es, RandomGen g) =>
g -> ((Cl3 es, Cl3 es), g)
randOrthogonalJonesVec g
g = 
  let (Cl3 es
v3, g
g') = g -> (Cl3 es, g)
forall (es :: ES) g. (PositF es, RandomGen g) => g -> (Cl3 es, g)
randUnitV3 g
g
  in ((Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es
jv Cl3 es
v3, Cl3 es -> Cl3 es
forall {es :: ES}.
(PositC es, PositC (Next es), PositC (Prev es)) =>
Cl3 es -> Cl3 es
jv (Cl3 es -> Cl3 es
forall (es :: ES). PositC es => Cl3 es -> Cl3 es
bar Cl3 es
v3)),g
g')

#endif