{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}
#if MIN_VERSION_GLASGOW_HASKELL (8,6,0,0)
{-# LANGUAGE NoStarIsType #-}
#endif
module Haskus.Binary.Unum
( Unum
, UnumNum (..)
, I
, U (..)
, Neg
, Rcp
, Infinite
, Log2
, UnumNumbers
, UnumSize
, BackingWord
, UBit (..)
, unumSize
, unumZero
, unumInfinite
, unumEncode
, unumBits
, unumNegate
, unumReciprocate
, unumLabels
, Sign (..)
, unumSign
, SORN
, SORNBackingWord
, sornBits
, sornSize
, sornEmpty
, sornFull
, sornNonInfinite
, sornNonZero
, sornSingle
, sornInsert
, sornMember
, sornRemove
, sornUnion
, sornIntersect
, sornComplement
, sornNegate
, sornElems
, sornFromElems
, sornFromTo
, SornAdd (..)
, CSORN (..)
, csornSize
, csornBits
, csornToSorn
, csornEmpty
, csornIsEmpty
, csornFromTo
, csornFull
, csornSingle
)
where
import Haskus.Number.Word
import Haskus.Binary.Bits
import Haskus.Binary.BitField
import Haskus.Utils.Types hiding (Log2)
import Haskus.Utils.HList
import Haskus.Utils.Flow
import Data.Kind (Type)
data Unum (xs :: [Type])
class UnumNum a where
unumLabel :: a -> String
data I (n :: Nat)
data Neg a
data Rcp a
data Uncertain a
instance KnownNat n => UnumNum (I n) where
unumLabel _ = show (natValue' @n)
instance UnumNum x => UnumNum (Rcp x) where
unumLabel _ = "/" ++ unumLabel (undefined :: x)
instance UnumNum x => UnumNum (Neg x) where
unumLabel _ = "-" ++ unumLabel (undefined :: x)
instance UnumNum x => UnumNum (Uncertain x) where
unumLabel _ = unumLabel (undefined :: x) ++ ".."
type Infinite = Rcp (I 0)
type family Simplify a where
Simplify a = Simplify' 'True a
type family Simplify' loop a where
Simplify' l (Rcp (Rcp x)) = Simplify x
Simplify' l (Neg (Neg x)) = Simplify x
Simplify' l (Neg (I 0)) = I 0
Simplify' l (Rcp (I 1)) = I 1
Simplify' l (Neg Infinite) = Infinite
Simplify' l (Rcp (Neg x)) = Simplify (Neg (Rcp x))
Simplify' 'True (Rcp x) = Simplify' 'False (Rcp (Simplify x))
Simplify' 'True (Neg x) = Simplify' 'False (Neg (Simplify x))
Simplify' 'False (Rcp x) = Rcp (Simplify x)
Simplify' 'False (Neg x) = Neg (Simplify x)
Simplify' l x = x
type family UnumNumbers x where
UnumNumbers (Unum xs) = Nub (AddNeg (AddRcp (Snoc xs Infinite)))
type family UnumPositives x where
UnumPositives (Unum xs) = Nub (AddRcp (Snoc xs Infinite))
type family UnumIndexables x where
UnumIndexables u =
Nub (Concat (UnumPositives u) (Reverse (MapNeg (UnumPositives u))))
type family UnumMembers x where
UnumMembers u = MakeMembers (UnumIndexables u)
type family MakeMembers xs where
MakeMembers '[] = '[]
MakeMembers (x ': xs) = x ': Uncertain x ': MakeMembers xs
data GetLabel = GetLabel
instance forall a r.
( UnumNum a
, r ~ [String]
) => Apply GetLabel (a, [String]) r where
apply _ (x,xs) = unumLabel x : xs
unumLabels :: forall u v.
( HFoldr' GetLabel [String] v [String]
, v ~ UnumMembers u
) => [String]
unumLabels = hFoldr' GetLabel ([] :: [String]) (undefined :: HList v)
type family UnumSize x where
UnumSize x = 1 + Log2 (Length (UnumNumbers x))
unumSize :: forall u.
( KnownNat (UnumSize u)
) => Word
unumSize = natValue @(UnumSize u)
unumZero :: forall u.
( Num (BackingWord u)
, Bits (BackingWord u)
, Encodable (I 0) u
) => U u
unumZero = unumEncode @u @(I 0) ExactNumber
unumInfinite :: forall u.
( Num (BackingWord u)
, Bits (BackingWord u)
, Encodable Infinite u
) => U u
unumInfinite = unumEncode @u @Infinite ExactNumber
type family Div2 n where
Div2 0 = 0
Div2 1 = 0
Div2 n = Div2 (n - 2) + 1
type family Log2 n where
Log2 0 = 0
Log2 1 = 0
Log2 n = Log2 (Div2 n) + 1
type family BackingWord x where
BackingWord x = WordAtLeast (UnumSize x)
type family MapRcp xs where
MapRcp '[] = '[]
MapRcp (x ': xs) = Simplify (Rcp x) ': MapRcp xs
type family MapNeg xs where
MapNeg '[] = '[]
MapNeg (x ': xs) = Simplify (Neg x) ': MapNeg xs
type family AddRcp xs where
AddRcp xs = Concat (Reverse (MapRcp xs)) xs
type family AddNeg xs where
AddNeg xs = Concat (Reverse (MapNeg xs)) xs
newtype U u = U (BackingWord u)
instance Eq (BackingWord u) => Eq (U u) where
U x == U y = x == y
instance forall u v.
( HFoldr' GetLabel [String] v [String]
, v ~ UnumMembers u
, Integral (BackingWord u)
) => Show (U u) where
show (U w) = unumLabels @u !! fromIntegral w
unumBits :: forall u.
( Bits (BackingWord u)
, KnownNat (UnumSize u)
) => U u -> String
unumBits (U w) = drop (fromIntegral (bitSize w - unumSize @u)) (bitsToString w)
type Encodable x u =
( KnownNat (IndexOf (Simplify x) (UnumIndexables u)))
data UBit
= ExactNumber
| OpenInterval
deriving (Show,Eq)
unumEncode :: forall u x i.
( i ~ IndexOf (Simplify x) (UnumIndexables u)
, KnownNat i
, Num (BackingWord u)
, Bits (BackingWord u)
) => UBit -> U u
{-# INLINABLE unumEncode #-}
unumEncode b = case b of
ExactNumber -> U w
OpenInterval -> U (setBit w 0)
where
w = natValue @i `shiftL` 1
unumNegate :: forall u.
( Bits (BackingWord u)
, Num (BackingWord u)
, KnownNat (UnumSize u)
) => U u -> U u
{-# INLINABLE unumNegate #-}
unumNegate (U w) = U (maskDyn s (complement w + 1))
where
s = unumSize @u
unumReciprocate :: forall u.
( Bits (BackingWord u)
, Num (BackingWord u)
, KnownNat (UnumSize u)
) => U u -> U u
{-# INLINABLE unumReciprocate #-}
unumReciprocate (U w) = U (w `xor` m + 1)
where
s = unumSize @u
m = makeMaskDyn (s-1)
data Sign
= Positive
| Negative
| NoSign
deriving (Show,Eq)
unumSign :: forall u.
( Bits (BackingWord u)
, KnownNat (UnumSize u)
) => U u -> Sign
unumSign (U w) =
if clearBit w n == zeroBits
then NoSign
else if testBit w n
then Negative
else Positive
where
n = fromIntegral (unumSize @u - 1)
type family SORNSize u where
SORNSize u = Length (UnumMembers u)
type family SORNBackingWord u where
SORNBackingWord u = WordAtLeast (SORNSize u)
newtype SORN u = SORN (SORNBackingWord u)
instance forall u v.
( KnownNat (SORNSize u)
, Bits (SORNBackingWord u)
, Num (BackingWord u)
, Integral (BackingWord u)
, HFoldr' GetLabel [String] v [String]
, v ~ UnumMembers u
) => Show (SORN u) where
show = show . sornElems
sornBits :: forall u s.
( Bits (SORNBackingWord u)
, KnownNat (UnumSize u)
, s ~ SORNSize u
, KnownNat s
) => SORN u -> String
sornBits (SORN w) = drop (bitSize w - natValue @s) (bitsToString w)
sornSize :: forall u s.
( s ~ SORNSize u
, KnownNat s
) => Word
sornSize = natValue @s
sornEmpty :: (Bits (SORNBackingWord u)) => SORN u
sornEmpty = SORN zeroBits
sornFull :: forall u.
( Bits (SORNBackingWord u)
, KnownNat (SORNSize u)
) => SORN u
sornFull = SORN (maskDyn s (complement zeroBits))
where
s = sornSize @u
sornNonInfinite :: forall u.
( Bits (SORNBackingWord u)
, Integral (BackingWord u)
, Bits (BackingWord u)
, Encodable Infinite u
) => SORN u
sornNonInfinite = sornRemove (SORN (complement zeroBits)) inf
where
inf = unumEncode @u @Infinite ExactNumber
sornNonZero ::
( Bits (SORNBackingWord u)
, Integral (BackingWord u)
, Bits (BackingWord u)
, Encodable (I 0) u
) => SORN u
sornNonZero = sornRemove (SORN (complement zeroBits)) unumZero
sornSingle ::
( Integral (BackingWord u)
, Bits (SORNBackingWord u)
) => U u -> SORN u
sornSingle = sornInsert sornEmpty
sornInsert :: forall u.
( Bits (SORNBackingWord u)
, Integral (BackingWord u)
) => SORN u -> U u -> SORN u
sornInsert (SORN w) (U v) = SORN (setBit w (fromIntegral v))
sornRemove :: forall u.
( Bits (SORNBackingWord u)
, Integral (BackingWord u)
) => SORN u -> U u -> SORN u
sornRemove (SORN w) (U v) = SORN (clearBit w (fromIntegral v))
sornMember :: forall u.
( Bits (SORNBackingWord u)
, Integral (BackingWord u)
) => SORN u -> U u -> Bool
sornMember (SORN w) (U x) = testBit w (fromIntegral x)
sornUnion :: forall u.
( Bits (SORNBackingWord u)
) => SORN u -> SORN u -> SORN u
sornUnion (SORN w) (SORN v) = SORN (w .|. v)
sornIntersect :: forall u.
( Bits (SORNBackingWord u)
) => SORN u -> SORN u -> SORN u
sornIntersect (SORN w) (SORN v) = SORN (w .&. v)
sornComplement ::
( Bits (SORNBackingWord u)
) => SORN u -> SORN u
sornComplement (SORN x) = SORN (complement x)
sornNegate :: forall u.
( Bits (SORNBackingWord u)
, Bits (BackingWord u)
, Integral (BackingWord u)
, KnownNat (SORNSize u)
, KnownNat (UnumSize u)
) => SORN u -> SORN u
sornNegate = sornFromElems . fmap unumNegate . sornElems
sornElems :: forall u s.
( s ~ SORNSize u
, KnownNat s
, Bits (SORNBackingWord u)
, Num (BackingWord u)
) => SORN u -> [U u]
sornElems (SORN x) = foldl b [] (reverse ([s `shiftR` 1 .. s-1]
++ [0 .. (s-1) `shiftR` 1]))
where
s = natValue @s
b us i = if testBit x i
then U (fromIntegral i) : us
else us
sornFromElems ::
( Integral (BackingWord u)
, Bits (SORNBackingWord u)
) => [U u] -> SORN u
sornFromElems = foldl sornInsert sornEmpty
sornFromTo :: forall u.
( Integral (BackingWord u)
, Bits (SORNBackingWord u)
, Bits (BackingWord u)
, KnownNat (UnumSize u)
) => U u -> U u -> SORN u
sornFromTo (U a) (U b) = go sornEmpty a
where
go w x
| x == b = sornInsert w (U x)
| otherwise = go (sornInsert w (U x)) (maskDyn s (x+1))
s = unumSize @u
class SornAdd u where
sornAddU :: U u -> U u -> SORN u
sornAdd ::
( KnownNat (SORNSize u)
, Bits (SORNBackingWord u)
, Num (BackingWord u)
) => SORN u -> SORN u -> SORN u
sornAdd a b =
foldl sornUnion sornEmpty [ sornAddU x y
| x <- sornElems a
, y <- sornElems b
]
sornAddDep ::
( KnownNat (SORNSize u)
, Bits (SORNBackingWord u)
, Num (BackingWord u)
) => SORN u -> SORN u
sornAddDep a =
foldl sornUnion sornEmpty [ sornAddU x x
| x <- sornElems a
]
sornSubU ::
( Bits (BackingWord u)
, Num (BackingWord u)
, KnownNat (UnumSize u)
) => U u -> U u -> SORN u
sornSubU a b = sornAddU a (unumNegate b)
sornSub ::
( KnownNat (SORNSize u)
, Bits (SORNBackingWord u)
, Bits (BackingWord u)
, Num (BackingWord u)
, KnownNat (UnumSize u)
) => SORN u -> SORN u -> SORN u
sornSub a b =
foldl sornUnion sornEmpty [ sornSubU x y
| x <- sornElems a
, y <- sornElems b
]
sornSubDep ::
( KnownNat (SORNSize u)
, Bits (SORNBackingWord u)
, Bits (BackingWord u)
, Num (BackingWord u)
, KnownNat (UnumSize u)
) => SORN u -> SORN u
sornSubDep a =
foldl sornUnion sornEmpty [ sornSubU x x
| x <- sornElems a
]
type family CSORNSize u where
CSORNSize u = 2 * UnumSize u
type family CSORNBackingWord u where
CSORNBackingWord u = WordAtLeast (CSORNSize u)
newtype CSORN u
= CSORN (BitFields (CSORNBackingWord u)
'[ BitField (UnumSize u) "start" (BackingWord u)
, BitField (UnumSize u) "count" (BackingWord u)
])
csornStart :: forall u.
( Integral (BackingWord u)
, Integral (CSORNBackingWord u)
, KnownNat (UnumSize u)
, Bits (CSORNBackingWord u)
, Field (BackingWord u)
) => CSORN u -> U u
csornStart c = U (csornStart' c)
csornStart' :: forall u.
( Integral (BackingWord u)
, Integral (CSORNBackingWord u)
, KnownNat (UnumSize u)
, Bits (CSORNBackingWord u)
, Field (BackingWord u)
) => CSORN u -> BackingWord u
csornStart' (CSORN c) = extractField' @"start" c
csornCount ::
( Integral (BackingWord u)
, Integral (CSORNBackingWord u)
, KnownNat (UnumSize u)
, Bits (CSORNBackingWord u)
, Field (BackingWord u)
) => CSORN u -> BackingWord u
csornCount (CSORN c) = extractField' @"count" c
instance forall u v.
( KnownNat (SORNSize u)
, KnownNat (UnumSize u)
, Bits (BackingWord u)
, Bits (CSORNBackingWord u)
, Integral (CSORNBackingWord u)
, Num (BackingWord u)
, Integral (BackingWord u)
, HFoldr' GetLabel [String] v [String]
, Field (BackingWord u)
, Bits (SORNBackingWord u)
, Bits (SORNBackingWord u)
, v ~ UnumMembers u
) => Show (CSORN u) where
show = show . csornToSorn
csornToSorn :: forall u.
( KnownNat (UnumSize u)
, Num (BackingWord u)
, Integral (BackingWord u)
, Integral (CSORNBackingWord u)
, Bits (CSORNBackingWord u)
, Bits (BackingWord u)
, Bits (SORNBackingWord u)
, Field (BackingWord u)
, KnownNat (SORNSize u)
, Bits (SORNBackingWord u)
) => CSORN u -> SORN u
csornToSorn c =
if csornCount c == 0
then if start == 0
then sornEmpty
else sornFull
else sornFromTo (csornStart c) (U x')
where
start = csornStart' c
x' = maskDyn s (start + csornCount c - 1)
s = unumSize @u
csornSize :: forall u s.
( s ~ CSORNSize u
, KnownNat s
) => Word
csornSize = natValue @s
csornBits :: forall u s.
( Bits (CSORNBackingWord u)
, KnownNat (UnumSize u)
, s ~ CSORNSize u
, KnownNat s
) => CSORN u -> String
csornBits (CSORN (BitFields w)) = drop (bitSize w - natValue @s) (bitsToString w)
csornEmpty :: forall u.
( Bits (CSORNBackingWord u)
) => CSORN u
csornEmpty = CSORN (BitFields zeroBits)
csornIsEmpty :: forall u.
( Bits (CSORNBackingWord u)
) => CSORN u -> Bool
{-# INLINABLE csornIsEmpty #-}
csornIsEmpty (CSORN (BitFields b)) = b == zeroBits
csornFromTo :: forall u.
( Num (BackingWord u)
, Bits (BackingWord u)
, KnownNat (UnumSize u)
, KnownNat (SORNSize u)
, Bits (BackingWord u)
, Integral (CSORNBackingWord u)
, Bits (CSORNBackingWord u)
, Field (BackingWord u)
, Integral (BackingWord u)
) => U u -> U u -> CSORN u
csornFromTo start stop =
if fromIntegral count == unumSize @u
then csornFull
else CSORN b
where
U x = start
U y = stop
s = unumSize @u
count = maskDyn s (y-x+1)
b = BitFields 0
|> updateField' @"start" x
|> updateField' @"count" count
csornFull :: forall u.
( Bits (CSORNBackingWord u)
, Integral (CSORNBackingWord u)
, Integral (BackingWord u)
, KnownNat (UnumSize u)
, Field (BackingWord u)
) => CSORN u
csornFull = CSORN (BitFields zeroBits
|> updateField' @"start" 1
|> updateField' @"count" 0)
csornSingle :: forall u.
( Bits (CSORNBackingWord u)
, Integral (CSORNBackingWord u)
, Integral (BackingWord u)
, KnownNat (UnumSize u)
, Field (BackingWord u)
) => U u -> CSORN u
csornSingle (U u) = CSORN (BitFields zeroBits
|> updateField' @"start" u
|> updateField' @"count" 1)