{-# language Safe #-}
{-# language FlexibleInstances #-}
{-# language PatternSynonyms #-}
{-# language ViewPatterns #-}
module Data.Group.Order
(
GroupOrder(..)
, Order(..)
, pattern Infinitary
, pattern Finitary
, orderForBits
, lcmOrder
, FiniteGroup
, finiteOrder
) where
import Data.Bits
import Data.Functor.Const (Const(..))
import Data.Functor.Identity (Identity(..))
import Data.Group
import Data.Group.Finite (FiniteGroup, finiteOrder)
import Data.Int
import Data.Monoid
import Data.Ord (Down(..))
import Data.Proxy (Proxy)
import Data.Word
import Numeric.Natural (Natural)
data Order = Infinite | Finite !Natural
deriving (Eq, Show)
pattern Infinitary :: (GroupOrder g) => g
pattern Infinitary <- (order -> Infinite)
pattern Finitary :: (GroupOrder g) => Natural -> g
pattern Finitary n <- (order -> Finite n)
lcmOrder :: Order -> Order -> Order
lcmOrder (Finite m) (Finite n) = Finite (lcm m n)
lcmOrder _ _ = Infinite
class (Eq g, Group g) => GroupOrder g where
order :: g -> Order
instance GroupOrder () where
order _ = Finite 1
instance GroupOrder (Proxy a) where
order _ = Finite 1
instance GroupOrder (Sum Integer) where
order 0 = Finite 1
order _ = Infinite
instance GroupOrder (Sum Rational) where
order 0 = Finite 1
order _ = Infinite
instance GroupOrder (Sum Int) where order = orderForBits
instance GroupOrder (Sum Int8) where order = orderForBits
instance GroupOrder (Sum Int16) where order = orderForBits
instance GroupOrder (Sum Int32) where order = orderForBits
instance GroupOrder (Sum Int64) where order = orderForBits
instance GroupOrder (Sum Word) where order = orderForBits
instance GroupOrder (Sum Word8) where order = orderForBits
instance GroupOrder (Sum Word16) where order = orderForBits
instance GroupOrder (Sum Word32) where order = orderForBits
instance GroupOrder (Sum Word64) where order = orderForBits
zeroFactor :: FiniteBits a => a -> Natural
zeroFactor a = bit (finiteBitSize a - countTrailingZeros a)
orderForBits :: (Integral a, FiniteBits a) => Sum a -> Order
orderForBits (Sum a) = Finite (zeroFactor a)
instance GroupOrder (Product Rational) where
order 1 = Finite 1
order _ = Infinite
instance (GroupOrder a, GroupOrder b) => GroupOrder (a,b) where
order (a,b) = order a `lcmOrder` order b
instance (GroupOrder a, GroupOrder b, GroupOrder c) => GroupOrder (a,b,c) where
order (a,b,c) = order ((a,b),c)
instance (GroupOrder a, GroupOrder b, GroupOrder c, GroupOrder d)
=> GroupOrder (a,b,c,d) where
order (a,b,c,d) = order ((a,b),(c,d))
instance (GroupOrder a, GroupOrder b, GroupOrder c, GroupOrder d, GroupOrder e)
=> GroupOrder (a,b,c,d,e) where
order (a,b,c,d,e) = order ((a,b,c),(d,e))
instance GroupOrder a => GroupOrder (Down a) where
order (Down a) = order a
instance GroupOrder a => GroupOrder (Dual a) where
order = order . getDual
instance GroupOrder a => GroupOrder (Const a b) where
order = order . getConst
instance GroupOrder a => GroupOrder (Identity a) where
order = order . runIdentity