ac-library-hs-1.5.0.0: src/AtCoder/ModInt.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE TypeFamilies #-}
-- | It is the structure that treats the modular arithmetic. All the remaining parts of AC Library
-- works without modint, so you don't necessarily read this to use the remaining parts.
--
-- ==== __Example__
-- It is often convenient to define a type alias of `ModInt` for a specific modulus value:
--
-- >>> import AtCoder.ModInt qualified as M
-- >>> type Mint = M.ModInt998244353
-- >>> let modInt :: Int -> Mint; modInt = M.new
-- >>> modInt 1000000000
-- 1755647
--
-- >>> modInt 1000000000 / modInt 3
-- 666081451
--
-- ==== Major changes from the original @ac-library@
-- - @StaticModInt@ is renamed to `ModInt`.
-- - @DynamicModInt@ is removed.
--
-- @since 1.0.0.0
module AtCoder.ModInt
( -- * Modulus
Modulus (..),
ModInt998244353,
ModInt1000000007,
-- ** Helpers
modVal,
modVal#,
-- * ModInt
ModInt (..),
-- * Constructors
-- ** Safe constructors
new,
new32,
new64,
-- ** Unsafe constructor
unsafeNew,
-- * Accessors
-- ** Modulus value
modulus,
-- ** Internal value
val,
val32,
val64,
-- * Operators
pow,
inv,
)
where
import AtCoder.Internal.Assert qualified as ACIA
import AtCoder.Internal.Barrett qualified as ACIBT
import AtCoder.Internal.Math qualified as ACIM
import Data.Bits ((!>>.))
import Data.Coerce (coerce)
import Data.Proxy (Proxy)
import Data.Ratio (denominator, numerator)
import Data.Vector.Generic qualified as VG
import Data.Vector.Generic.Mutable qualified as VGM
import Data.Vector.Primitive qualified as P
import Data.Vector.Unboxed qualified as U
import Data.Vector.Unboxed qualified as VU
import Data.Word (Word32, Word64)
import GHC.Exts (Proxy#, proxy#)
import GHC.Stack (HasCallStack)
import GHC.TypeNats (KnownNat, natVal, natVal')
-- | `KnownNat` with meta information as a modulus value for convolution.
--
-- @since 1.0.0.0
class (KnownNat a) => Modulus a where
-- | Returns if the modulus is a prime value.
--
-- @since 1.0.0.0
isPrimeModulus :: Proxy# a -> Bool
-- | Returns the primitive root of the modulus value. Note that the default implementation is slow
-- and the value should be hard-coded.
--
-- @since 1.0.0.0
{-# INLINE primitiveRootModulus #-}
primitiveRootModulus :: Proxy# a -> Int
-- we could use `AllowAmbigousTypes` or `Tagged` newtype, but `Proxy#` wasn't so slow.
-- not sure about the case of `x^n` though..
primitiveRootModulus _ = ACIM.primitiveRoot $ fromIntegral (natVal' (proxy# @a))
-- | \(2^{24} - 1\).
--
-- @since 1.0.0.0
instance Modulus 167772161 where
{-# INLINE isPrimeModulus #-}
isPrimeModulus _ = True
{-# INLINE primitiveRootModulus #-}
primitiveRootModulus _ = 3
-- | \(2^{25} - 1\).
--
-- @since 1.0.0.0
instance Modulus 469762049 where
{-# INLINE isPrimeModulus #-}
isPrimeModulus _ = True
{-# INLINE primitiveRootModulus #-}
primitiveRootModulus _ = 3
-- | \(2^{26} - 1\).
--
-- @since 1.0.0.0
instance Modulus 754974721 where
{-# INLINE isPrimeModulus #-}
isPrimeModulus _ = True
{-# INLINE primitiveRootModulus #-}
primitiveRootModulus _ = 11
-- | \(119 \times 2^{23} + 1\). It is often used in contest problems.
--
-- @since 1.0.0.0
instance Modulus 998244353 where
{-# INLINE isPrimeModulus #-}
isPrimeModulus _ = True
{-# INLINE primitiveRootModulus #-}
primitiveRootModulus _ = 3
-- | It used to be used in contest problems.
--
-- @since 1.0.0.0
instance Modulus 1000000007 where
{-# INLINE isPrimeModulus #-}
isPrimeModulus _ = True
{-# INLINE primitiveRootModulus #-}
primitiveRootModulus _ = 5
-- | \(2^{31} - 1\), suitable for boundary testing.
--
-- @since 1.0.0.0
instance Modulus 2147483647 where
{-# INLINE isPrimeModulus #-}
isPrimeModulus _ = True
{-# INLINE primitiveRootModulus #-}
primitiveRootModulus _ = 7
-- | @since 1.0.0.0
type ModInt998244353 = ModInt 998244353
-- | @since 1.0.0.0
type ModInt1000000007 = ModInt 1000000007
-- | Retrieves the `Int` value from a `KnownNat`.
--
-- >>> :set -XDataKinds
-- >>> import Data.Proxy (Proxy(..))
-- >>> modVal (Proxy @42)
-- 42
--
-- @since 1.0.0.0
{-# INLINE modVal #-}
modVal :: forall a. (KnownNat a) => Proxy a -> Int
modVal p = fromIntegral $ natVal p
-- | Retrieves the `Int` value from a `KnownNat`.
--
-- >>> :set -XDataKinds
-- >>> :set -XMagicHash
-- >>> import GHC.Exts (proxy#)
-- >>> modVal# (proxy# @42)
-- 42
--
-- @since 1.0.0.0
{-# INLINE modVal# #-}
modVal# :: forall a. (KnownNat a) => Proxy# a -> Int
modVal# p = fromIntegral $ natVal' p
-- | Creates a `ModInt` from an `Int` value taking the mod.
--
-- @since 1.0.0.0
{-# INLINE new #-}
new :: forall a. (KnownNat a) => Int -> ModInt a
new v = ModInt . fromIntegral $ v `mod` fromIntegral (natVal' (proxy# @a))
-- | Creates a `ModInt` from a `Word32` value taking the mod.
--
-- @since 1.0.0.0
{-# INLINE new32 #-}
new32 :: forall a. (KnownNat a) => Word32 -> ModInt a
new32 v = ModInt $ v `mod` fromIntegral (natVal' (proxy# @a))
-- | Creates a `ModInt` from a `Word64` value taking the mod.
--
-- @since 1.0.0.0
{-# INLINE new64 #-}
new64 :: forall a. (KnownNat a) => Word64 -> ModInt a
new64 v = ModInt . fromIntegral $ v `mod` fromIntegral (natVal' (proxy# @a))
-- | Creates `ModInt` without taking the mod. It is the function for constant-factor speedup.
--
-- ==== Constraints
-- - \(0 \leq x \lt \mathrm{mod}\) (not asserted at runtime)
--
-- @since 1.0.0.0
{-# INLINE unsafeNew #-}
unsafeNew :: (KnownNat a) => Word32 -> ModInt a
unsafeNew = ModInt
-- | `Word32` value that treats the modular arithmetic.
newtype ModInt a = ModInt
{ -- | @since 1.0.0.0
unModInt :: Word32
}
deriving
( -- | @since 1.0.0.0
P.Prim
)
deriving newtype
( -- | @since 1.0.0.0
Eq,
-- | @since 1.0.0.0
Ord,
-- | @since 1.0.0.0
Read,
-- | @since 1.0.0.0
Show
)
-- | Retrieve the mod from a `ModInt` object.
--
-- ==== Complexity
-- - \(O(1)\)
--
-- @since 1.0.0.0
{-# INLINE modulus #-}
modulus :: forall a. (KnownNat a) => ModInt a -> Int
modulus _ = fromIntegral (natVal' (proxy# @a))
-- | Returns the internal value in `Int`.
--
-- ==== Complexity
-- - \(O(1)\)
--
-- @since 1.0.0.0
{-# INLINE val #-}
val :: (KnownNat a) => ModInt a -> Int
val = fromIntegral . unModInt
-- | Returns the internal value as `Word32` without type conversion. It is the function for
-- constant-factor speedup.
--
-- ==== Complexity
-- - \(O(1)\)
--
-- @since 1.0.0.0
{-# INLINE val32 #-}
val32 :: (KnownNat a) => ModInt a -> Word32
val32 = unModInt
-- | Returns the internal value in `Word32`.
--
-- ==== Complexity
-- - \(O(1)\)
--
-- @since 1.0.0.0
{-# INLINE val64 #-}
val64 :: (KnownNat a) => ModInt a -> Word64
val64 = fromIntegral . unModInt
-- | Returns \(x^n\). The implementation is a bit more efficient than `^`.
--
-- ==== Constraints
-- - \(0 \le n\)
--
-- ==== Complexity
-- - \(O(\log n)\)
--
-- @since 1.0.0.0
{-# INLINE pow #-}
pow :: forall a. (HasCallStack, KnownNat a) => ModInt a -> Int -> ModInt a
pow (ModInt x0) n0 = ModInt . fromIntegral $ inner n0 1 (fromIntegral x0)
where
!_ = ACIA.runtimeAssert (0 <= n0) $ "AtCoder.ModInt.pow: given negative exponential `n`: " ++ show n0 ++ show "`"
bt = ACIBT.new64 $ fromIntegral (natVal' (proxy# @a))
inner :: Int -> Word64 -> Word64 -> Word64
inner !n !r !y
| n == 0 = r
| otherwise =
let r' = if odd n then ACIBT.mulMod bt r y else r
y' = ACIBT.mulMod bt y y
in inner (n !>>. 1) r' y'
-- Original ACL version seems like slower as in the benchmark
-- pow :: (HasCallStack, KnownNat a) => ModInt a -> Int -> ModInt a
-- pow x0 n0 = inner x0 n0 1
-- where
-- !_ = ACIA.runtimeAssert (0 <= n0) $ "AtCoder.ModInt.pow: given negative exponential `n`: " ++ show n0 ++ show "`"
-- inner !x !n !r
-- | n == 0 = r
-- | otherwise =
-- let !r' = if odd n then r * x else r
-- in inner (x * x) (n !>>. 1) r'
-- | Returns \(y\) with \(xy \equiv 1\).
--
-- ==== Constraints
-- - @\gcd(val x, modulus x) == 1@.
--
-- ==== Complexity
-- - \(O(\log \mathrm{mod})\)
--
-- @since 1.0.0.0
{-# INLINE inv #-}
inv :: forall a. (HasCallStack, Modulus a) => ModInt a -> ModInt a
inv self@(ModInt x)
| isPrimeModulus (proxy# @a) =
let !_ = ACIA.runtimeAssert (x /= 0) "AtCoder.ModInt.inv: tried to perform zero division"
in pow self (fromIntegral (natVal' (proxy# @a)) - 2)
| otherwise =
let (!eg1, !eg2) = ACIM.invGcd (fromIntegral x) $ fromIntegral (natVal' (proxy# @a))
!_ = ACIA.runtimeAssert (eg1 == 1) "AtCoder.ModInt.inv: `x^(-1) mod m` cannot be calculated when `gcd x modulus /= 1`"
in fromIntegral eg2
-- | @since 1.0.0.0
deriving newtype instance (KnownNat p) => Real (ModInt p)
-- | @since 1.0.0.0
instance (KnownNat p) => Num (ModInt p) where
{-# INLINE (+) #-}
(ModInt !x1) + (ModInt !x2)
| x' >= m = ModInt $! x' - m
| otherwise = ModInt x'
where
!x' = x1 + x2
!m = fromIntegral (natVal' (proxy# @p))
{-# INLINE (-) #-}
(ModInt !x1) - (ModInt !x2)
| x' >= m = ModInt $! x' + m -- loops
| otherwise = ModInt x'
where
!x' = x1 - x2
!m = fromIntegral (natVal' (proxy# @p))
{-# INLINE (*) #-}
(ModInt !x1) * (ModInt !x2) = ModInt $! fromIntegral (x' `rem` m)
where
!x' :: Word64 = fromIntegral x1 * fromIntegral x2
!m :: Word64 = fromIntegral (natVal' (proxy# @p))
{-# INLINE negate #-}
negate x = 0 - x
{-# INLINE abs #-}
abs = id
{-# INLINE signum #-}
signum _ = ModInt 1
{-# INLINE fromInteger #-}
fromInteger = ModInt . fromInteger . (`mod` fromIntegral (natVal' (proxy# @p)))
-- | @since 1.0.0.0
instance (KnownNat p) => Bounded (ModInt p) where
{-# INLINE minBound #-}
minBound = ModInt 0
{-# INLINE maxBound #-}
maxBound = ModInt $! fromIntegral (natVal' (proxy# @p)) - 1
-- | @since 1.0.0.0
instance (KnownNat p) => Enum (ModInt p) where
{-# INLINE toEnum #-}
toEnum = new
{-# INLINE fromEnum #-}
fromEnum = fromIntegral . unModInt
-- | @since 1.0.0.0
instance (Modulus p) => Integral (ModInt p) where
{-# INLINE quotRem #-}
quotRem x y = (x / y, x - x / y * y)
{-# INLINE toInteger #-}
toInteger = coerce (toInteger @Word32)
-- | @since 1.0.0.0
instance (Modulus p) => Fractional (ModInt p) where
{-# INLINE recip #-}
recip = inv
{-# INLINE fromRational #-}
fromRational q = fromInteger (numerator q) / fromInteger (denominator q)
-- | @since 1.0.0.0
newtype instance VU.MVector s (ModInt a) = MV_ModInt (VU.MVector s Word32)
-- | @since 1.0.0.0
newtype instance VU.Vector (ModInt a) = V_ModInt (VU.Vector Word32)
-- | @since 1.0.0.0
deriving newtype instance VGM.MVector VU.MVector (ModInt a)
-- | @since 1.0.0.0
deriving newtype instance VG.Vector VU.Vector (ModInt a)
-- | @since 1.0.0.0
instance VU.Unbox (ModInt a)