module Data.Sized.Sampled where
import Data.Sized.Signed as S
import Data.Sized.Matrix as M
import Data.Sized.Fin
data Sampled (m :: Nat) (n :: Nat) = Sampled (Signed n) Rational
toVector :: (SingI m, SingI n) => Sampled m n -> Vector n Bool
toVector (Sampled sig _) = S.toVector sig
fromVector :: forall n m . (SingI n, SingI m) => Vector n Bool -> Sampled m n
fromVector v = mkSampled (fromIntegral scale * fromIntegral val / fromIntegral precision)
  where val :: Signed n
        val = S.fromVector v
        scale     :: Integer
        scale     = fromIntegral (fromNat (sing :: Sing m))
        precision :: Integer
        precision = 2 ^ (fromIntegral (fromNat (sing :: Sing n)  1) :: Integer)
mkSampled :: forall n m . (SingI n, SingI m) => Rational -> Sampled m n
mkSampled v = Sampled val (fromIntegral scale * fromIntegral val / fromIntegral precision)
  where scale     :: Integer
        scale     = fromIntegral (fromNat (sing :: Sing m))
        precision :: Integer
        precision = 2 ^ (fromIntegral (fromNat (sing :: Sing n)  1) :: Integer)
        val0      :: Rational
        val0      = v / fromIntegral scale
        val1      :: Integer
                    
        val1      = round (val0 * fromIntegral precision)
        val       = if val1 >= precision then maxBound
                    else if val1 <= precision then minBound
                    else fromInteger val1
instance (SingI ix) => Eq (Sampled m ix) where
    (Sampled a _) == (Sampled b _) = a == b
instance (SingI ix) => Ord (Sampled m ix) where
    (Sampled a _) `compare` (Sampled b _) = a `compare` b
instance (SingI ix) => Show (Sampled m ix) where
    show (Sampled _ s) = show (fromRational s :: Double)
instance (SingI ix, SingI m) => Read (Sampled m ix) where
    readsPrec i str = [ (mkSampled a,r) | (a,r) <- readsPrec i str ]
instance (SingI ix, SingI m) => Num (Sampled m ix) where
    (Sampled _ a) + (Sampled _ b) = mkSampled $ a + b
    (Sampled _ a)  (Sampled _ b) = mkSampled $ a  b
    (Sampled _ a) * (Sampled _ b) = mkSampled $ a * b
    abs (Sampled _ n) = mkSampled $ abs n
    signum (Sampled _ n) = mkSampled $ signum n
    fromInteger n = mkSampled (fromInteger n)
instance (SingI ix, SingI m) => Real (Sampled m ix) where
    toRational (Sampled _ n) = toRational n
instance (SingI ix, SingI m) => Fractional (Sampled m ix) where
    fromRational n      = mkSampled n
    recip (Sampled _ n) = mkSampled $ recip n
instance (SingI ix, SingI m) => Enum (Sampled m ix) where
    fromEnum (Sampled n _) = fromEnum n
    toEnum n = mkSampled (fromIntegral scale * fromIntegral val / fromIntegral precision)
      where val :: Signed ix
            val = fromIntegral n
            scale     :: Integer
            scale     = fromIntegral (fromNat (sing :: Sing m))
            precision :: Integer
            precision = 2 ^ (fromIntegral (fromNat (sing :: Sing ix)  1) :: Integer)