packages feed

ac-library-hs 1.2.5.0 → 1.2.6.0

raw patch · 15 files changed

+1307/−15 lines, 15 filesdep +semiringsdep ~randomPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: semirings

Dependency ranges changed: random

API changes (from Hackage documentation)

+ AtCoder.Extra.Math: divisors :: Int -> Vector Int
+ AtCoder.Extra.Math: divisorsUnsorted :: Int -> Vector Int
+ AtCoder.Extra.Math: isPrime :: Int -> Bool
+ AtCoder.Extra.Math: primeFactors :: HasCallStack => Int -> Vector (Int, Int)
+ AtCoder.Extra.Math: primeFactorsUnsorted :: HasCallStack => Int -> Vector (Int, Int)
+ AtCoder.Extra.Math: primes :: Int -> Vector Int
+ AtCoder.Extra.Math.Montgomery64: addMod :: Word64 -> Word64 -> Word64 -> Word64
+ AtCoder.Extra.Math.Montgomery64: data Montgomery64
+ AtCoder.Extra.Math.Montgomery64: decode :: Montgomery64 -> Word64 -> Word64
+ AtCoder.Extra.Math.Montgomery64: encode :: Montgomery64 -> Word64 -> Word64
+ AtCoder.Extra.Math.Montgomery64: eq :: Word64 -> Word64 -> Word64 -> Bool
+ AtCoder.Extra.Math.Montgomery64: fromVal :: Word64 -> Montgomery64
+ AtCoder.Extra.Math.Montgomery64: instance GHC.Classes.Eq AtCoder.Extra.Math.Montgomery64.Montgomery64
+ AtCoder.Extra.Math.Montgomery64: instance GHC.Show.Show AtCoder.Extra.Math.Montgomery64.Montgomery64
+ AtCoder.Extra.Math.Montgomery64: mulMod :: Montgomery64 -> Word64 -> Word64 -> Word64
+ AtCoder.Extra.Math.Montgomery64: new :: forall a. KnownNat a => Proxy# a -> Montgomery64
+ AtCoder.Extra.Math.Montgomery64: powMod :: HasCallStack => Montgomery64 -> Word64 -> Int -> Word64
+ AtCoder.Extra.Math.Montgomery64: reduce :: Montgomery64 -> Word128 -> Word64
+ AtCoder.Extra.Math.Montgomery64: subMod :: Word64 -> Word64 -> Word64 -> Word64
+ AtCoder.Extra.Math.Montgomery64: umod :: Montgomery64 -> Word64
+ AtCoder.Extra.ModInt64: ModInt64 :: Word64 -> ModInt64 a
+ AtCoder.Extra.ModInt64: [unModInt64] :: ModInt64 a -> Word64
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat a => GHC.Classes.Eq (AtCoder.Extra.ModInt64.ModInt64 a)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat a => GHC.Classes.Ord (AtCoder.Extra.ModInt64.ModInt64 a)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat a => GHC.Read.Read (AtCoder.Extra.ModInt64.ModInt64 a)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat a => GHC.Show.Show (AtCoder.Extra.ModInt64.ModInt64 a)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat p => GHC.Enum.Bounded (AtCoder.Extra.ModInt64.ModInt64 p)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat p => GHC.Enum.Enum (AtCoder.Extra.ModInt64.ModInt64 p)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat p => GHC.Num.Num (AtCoder.Extra.ModInt64.ModInt64 p)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat p => GHC.Real.Fractional (AtCoder.Extra.ModInt64.ModInt64 p)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat p => GHC.Real.Integral (AtCoder.Extra.ModInt64.ModInt64 p)
+ AtCoder.Extra.ModInt64: instance GHC.TypeNats.KnownNat p => GHC.Real.Real (AtCoder.Extra.ModInt64.ModInt64 p)
+ AtCoder.Extra.ModInt64: instance forall k (a :: k). Data.Primitive.Types.Prim (AtCoder.Extra.ModInt64.ModInt64 a)
+ AtCoder.Extra.ModInt64: instance forall k (a :: k). Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector (AtCoder.Extra.ModInt64.ModInt64 a)
+ AtCoder.Extra.ModInt64: instance forall k (a :: k). Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector (AtCoder.Extra.ModInt64.ModInt64 a)
+ AtCoder.Extra.ModInt64: instance forall k (a :: k). Data.Vector.Unboxed.Base.Unbox (AtCoder.Extra.ModInt64.ModInt64 a)
+ AtCoder.Extra.ModInt64: inv :: forall a. (HasCallStack, KnownNat a) => ModInt64 a -> ModInt64 a
+ AtCoder.Extra.ModInt64: modulus :: forall a. KnownNat a => ModInt64 a -> Int
+ AtCoder.Extra.ModInt64: new :: forall a. KnownNat a => Int -> ModInt64 a
+ AtCoder.Extra.ModInt64: new64 :: forall a. KnownNat a => Word64 -> ModInt64 a
+ AtCoder.Extra.ModInt64: newtype ModInt64 a
+ AtCoder.Extra.ModInt64: pow :: forall a. (HasCallStack, KnownNat a) => ModInt64 a -> Int -> ModInt64 a
+ AtCoder.Extra.ModInt64: unsafeNew :: KnownNat a => Word64 -> ModInt64 a
+ AtCoder.Extra.ModInt64: val :: forall a. KnownNat a => ModInt64 a -> Int
+ AtCoder.Extra.ModInt64: val64 :: forall a. KnownNat a => ModInt64 a -> Word64
- AtCoder.Extra.SqrtDecomposition: foldMapM :: (Monad m, Monoid a) => Int -> (Int -> m a) -> (Int -> Int -> Int -> m a) -> Int -> Int -> m a
+ AtCoder.Extra.SqrtDecomposition: foldMapM :: (Monad m, Semigroup a) => Int -> (Int -> m a) -> (Int -> Int -> Int -> m a) -> Int -> Int -> m a

Files

CHANGELOG.md view
@@ -1,9 +1,18 @@ # Revision history for acl-hs +## 1.2.6.0 -- April 2025++- Added `AtCoder.Extra.Math` functions+  - `isPrime`+  - `primes`+  - `primeFactors`+- Added `AtCoderExtra.Math.Montgomery64`+- Added `AtCoderExtra.ModInt64`+ ## 1.2.5.0 -- April 2025 -- Added AtCoder.`Extra.Mo`-- Added AtCoder.`Extra.SqrtDecomposition`+- Added `AtCoder.Extra.Mo`+- Added `AtCoder.Extra.SqrtDecomposition`  ## 1.2.4.0 -- April 2025 @@ -29,9 +38,9 @@  ## 1.2.2.0 -- Feb 2025 -- Added `AtCoder.Extra.KdTree` and `Extra.LazyKdTree`.+- Added `AtCoder.Extra.KdTree` and `AtCoder.Extra.LazyKdTree`. - Added `clear` function to the dynamic segment tree family.-- Fixed AtCoder.`Extra.Hld.new` for a tree with a single vertex.+- Fixed `AtCoder.Extra.Hld.new` for a tree with a single vertex.  ## 1.2.1.0 -- Feb 2025 
ac-library-hs.cabal view
@@ -4,7 +4,7 @@ -- PVP summary:  +-+------- breaking API changes --               | | +----- non-breaking API additions --               | | | +--- code changes with no API change-version:         1.2.5.0+version:         1.2.6.0 synopsis:        Data structures and algorithms description:   Haskell port of [ac-library](https://github.com/atcoder/ac-library), a library for competitive@@ -39,6 +39,7 @@     , bitvec             <1.2     , bytestring         <0.14     , primitive          >=0.6.4.0 && <0.10+    , random             >=1.2.0     , vector             >=0.13.0  && <0.14     , vector-algorithms  <0.10     , wide-word          <0.2@@ -70,7 +71,9 @@     AtCoder.Extra.KdTree     AtCoder.Extra.LazyKdTree     AtCoder.Extra.Math+    AtCoder.Extra.Math.Montgomery64     AtCoder.Extra.Mo+    AtCoder.Extra.ModInt64     AtCoder.Extra.Monoid     AtCoder.Extra.Monoid.Affine1     AtCoder.Extra.Monoid.Mat2x2@@ -155,6 +158,8 @@     Tests.Extra.KdTree     Tests.Extra.LazyKdTree     Tests.Extra.Math+    Tests.Extra.Math.Montgomery64+    Tests.Extra.ModInt64     Tests.Extra.Monoid     Tests.Extra.MultiSet     Tests.Extra.SegTree2d@@ -199,6 +204,7 @@     , QuickCheck     , quickcheck-classes     , random+    , semirings     , tasty     , tasty-hspec     , tasty-hunit@@ -219,6 +225,8 @@     Bench.Matrix     Bench.ModInt     Bench.PowMod+    Bench.RepeatWithIndex+    Bench.RepeatWithoutIndex     Bench.SwapDupe     BenchLib.AddMod     BenchLib.Matrix
+ benchmarks/Bench/RepeatWithIndex.hs view
@@ -0,0 +1,67 @@+-- | Benchmark for monadic streams.+module Bench.RepeatWithIndex (benches) where++import Criterion+import Control.Monad (when, replicateM_)+import Control.Monad.ST (runST)+import Data.Foldable (for_)+import Data.Vector.Fusion.Stream.Monadic qualified as MS+import Data.Vector.Generic.Mutable as VGM+import Data.Vector.Unboxed as VU+import Data.Vector.Unboxed.Mutable as VUM++len :: Int+len = 10 ^ 7++list :: Int -> Int+list x = runST $ do+  res <- VUM.replicate 1 x+  for_ [0 .. len - 1] $ \dx -> do+    VGM.modify res (+ dx) 0+  VGM.read res 0++-- | @cojna/iota+(..<) :: (Monad m) => Int -> Int -> MS.Stream m Int+(..<) !l !r = MS.Stream step l+  where+    step x+      | x < r = return $ MS.Yield x (x + 1)+      | otherwise = return MS.Done+    {-# INLINE [0] step #-}+{-# INLINE [1] (..<) #-}++stream :: Int -> Int+stream x = runST $ do+  res <- VUM.replicate 1 x+  flip MS.mapM_ (0 ..< len) $ \dx -> do+    VGM.modify res (+ dx) 0+  VGM.read res 0++vector :: Int -> Int+vector x = runST $ do+  res <- VUM.replicate 1 x+  VU.forM_ (VU.generate len id) $ \dx -> do+    VGM.modify res (+ dx) 0+  VGM.read res 0++recursion :: Int -> Int+recursion x = runST $ do+  res <- VUM.replicate 1 x+  let run i = do+        when (i < len) $ do+          VGM.modify res (+ i) 0+          run $ i + 1+  run 0+  VGM.read res 0++-- The result is suspicious.. the stream version is slower than vector, recursive or replicateM_ is+-- faster by 10 times?+benches :: Benchmark+benches =+  bgroup+    "repeat-with-index"+    [ bench "list" $ nf list 0,+      bench "stream" $ nf stream 0,+      bench "vector" $ nf vector 0,+      bench "recursion" $ nf recursion 0+    ]
+ benchmarks/Bench/RepeatWithoutIndex.hs view
@@ -0,0 +1,75 @@+-- | Benchmark for monadic streams.+module Bench.RepeatWithoutIndex (benches) where++import Criterion+import Control.Monad (when, replicateM_)+import Control.Monad.ST (runST)+import Data.Foldable (for_)+import Data.Vector.Fusion.Stream.Monadic qualified as MS+import Data.Vector.Generic.Mutable as VGM+import Data.Vector.Unboxed as VU+import Data.Vector.Unboxed.Mutable as VUM++len :: Int+len = 10 ^ 7++list :: Int -> Int+list x = runST $ do+  res <- VUM.replicate 1 x+  for_ [0 .. len - 1] $ \_ -> do+    VGM.modify res (+ 1) 0+  VGM.read res 0++-- | @cojna/iota+(..<) :: (Monad m) => Int -> Int -> MS.Stream m Int+(..<) !l !r = MS.Stream step l+  where+    step x+      | x < r = return $ MS.Yield x (x + 1)+      | otherwise = return MS.Done+    {-# INLINE [0] step #-}+{-# INLINE [1] (..<) #-}++stream :: Int -> Int+stream x = runST $ do+  res <- VUM.replicate 1 x+  flip MS.mapM_ (0 ..< len) $ \_ -> do+    VGM.modify res (+ 1) 0+  VGM.read res 0++vector :: Int -> Int+vector x = runST $ do+  res <- VUM.replicate 1 x+  VU.forM_ (VU.generate len id) $ \_ -> do+    VGM.modify res (+ 1) 0+  VGM.read res 0++recursion :: Int -> Int+recursion x = runST $ do+  res <- VUM.replicate 1 x+  let run i = do+        when (i < len) $ do+          VGM.modify res (+ 1) 0+          run $ i + 1+  run 0+  VGM.read res 0++rep :: Int -> Int+rep x = runST $ do+  res <- VUM.replicate 1 x+  replicateM_ len $ do+    VGM.modify res (+ 1) 0+  VGM.read res 0++-- The result is suspicious.. the stream version is slower than vector, recursive or replicateM_ is+-- faster by 10 times?+benches :: Benchmark+benches =+  bgroup+    "repeat-without-index"+    [ bench "list" $ nf list 0,+      bench "stream" $ nf stream 0,+      bench "vector" $ nf vector 0,+      bench "recursion" $ nf recursion 0,+      bench "rep" $ nf rep 0+    ]
benchmarks/Main.hs view
@@ -7,6 +7,8 @@ import Bench.ModInt qualified import Bench.MulMod qualified import Bench.PowMod qualified+import Bench.RepeatWithIndex qualified+import Bench.RepeatWithoutIndex qualified import Bench.SwapDupe qualified import Criterion.Main @@ -22,5 +24,7 @@       Bench.AddMod.benches,       Bench.PowMod.benches,       Bench.Matrix.benches,+      Bench.RepeatWithIndex.benches,+      Bench.RepeatWithoutIndex.benches,       Bench.SwapDupe.benches     ]
src/AtCoder/Extra/Graph.hs view
@@ -99,7 +99,7 @@ import AtCoder.Internal.MinHeap qualified as MH import AtCoder.Internal.Queue qualified as Q import AtCoder.Internal.Scc qualified as ACISCC-import Control.Monad (when)+import Control.Monad (replicateM_, when) import Control.Monad.Fix (fix) import Control.Monad.Primitive (PrimMonad, PrimState, stToPrim) import Control.Monad.ST (ST, runST)@@ -443,7 +443,7 @@                           VGM.unsafeWrite next 0 (nxt + 1)                           B.pushBack edges (nxt, v)                           len <- B.length st-                          for_ [1 .. len - s] $ \_ -> do+                          replicateM_ (len - s) $ do                             back <- fromJust <$> B.popBack st                             B.pushBack edges (nxt, back)                         pure (child', k')@@ -477,7 +477,7 @@   n' <- VGM.unsafeRead next 0   Csr.build' n' <$> B.unsafeFreeze edges --- | \(O(n + m)\) Returns a [blocks (biconnected comopnents)](https://en.wikipedia.org/wiki/Biconnected_component)+-- | \(O(n + m)\) Returns [blocks (biconnected comopnents)](https://en.wikipedia.org/wiki/Biconnected_component) -- of the graph. -- -- ==== __Example__
src/AtCoder/Extra/Math.hs view
@@ -7,6 +7,14 @@     ACIM.invGcd,     primitiveRoot32, +    -- * Prime numbers and divisors+    primes,+    isPrime,+    primeFactors,+    primeFactorsUnsorted,+    divisors,+    divisorsUnsorted,+     -- * Binary exponentiation      -- | ==== __Examples__@@ -26,10 +34,22 @@   ) where +import AtCoder.Extra.Math.Montgomery64 qualified as M64 import AtCoder.Internal.Assert qualified as ACIA import AtCoder.Internal.Math qualified as ACIM-import Data.Bits ((.>>.))+import Control.Monad (unless, when)+import Data.Bit (Bit (..))+import Data.Bits (bit, countTrailingZeros, (.<<.), (.>>.))+import Data.Foldable (for_)+import Data.Maybe (fromJust)+import Data.Vector.Algorithms.Intro qualified as VAI+import Data.Vector.Algorithms.Radix qualified as VAR+import Data.Vector.Generic.Mutable qualified as VGM+import Data.Vector.Unboxed qualified as VU+import Data.Vector.Unboxed.Mutable qualified as VUM+import Data.Word (Word64) import GHC.Stack (HasCallStack)+import System.Random  -- | \(O(k \log^3 n) (k = 3)\). Returns whether the given `Int` value is a prime number. --@@ -57,6 +77,307 @@ primitiveRoot32 x = ACIM.primitiveRoot x   where     !_ = ACIA.runtimeAssert (x < (1 .>>. 32)) $ "AtCoder.Extra.Math.primitiveRoot32: given too large number `" ++ show x ++ "`"++-- | \(O(n \log \log n)\) Creates an array of prime numbers up to the given limit, using Sieve of+-- Eratosthenes.+--+-- The minimum computational complexity is \(\Omega(B \log \log B)\), where \(B = 2^{15}\) is the+-- length of segment. This constraint comes from the use of segmented sieve.+--+-- ==== Constraints+-- - The upper limit must be less than or equal to \(2^{30} (\gt 10^9)\), otherwise the returned+-- prime table is incorrect.+--+-- @since 1.2.6.0+{-# INLINEABLE primes #-}+primes :: Int -> VU.Vector Int+primes upperLimit+  | upperLimit <= 1 = VU.empty+  | otherwise = VU.create $ do+      -- segment length (TODO: isn't it 32767?)+      let !s = 32768 :: Int -- 2 ^ 15++      -- sieve length (TODO: use \sqrt limit? do benchmark)+      let !sieveMax = s++      -- Is it like LT bound??+      let !limit = upperLimit + 1++      -- base primes with index+      (!ps, !is) <- do+        sieve <- VUM.replicate (sieveMax + 1) $ Bit False+        ps <- VUM.unsafeNew (sieveMax `div` 2)+        is <- VUM.unsafeNew (sieveMax `div` 2)+        -- FIXME: carry index?+        iNext <- VUM.replicate 1 (0 :: Int)+        for_ [3, 5 .. s] $ \p1 -> do+          Bit b <- VGM.read sieve p1+          unless b $ do+            at <- VGM.read iNext 0+            VGM.write iNext 0 $ at + 1+            -- (base prime, next index (odd numbers only, so `div` 2)+            VGM.write ps at p1+            VGM.write is at $ p1 * p1 `div` 2+            -- NOTE: if `j` is a composite number, it's already enumerated by a smaller prime+            -- number than `p0`, so skip to `p1 * p1` and iterate through odd numbers only:+            for_ [p1 * p1, p1 * p1 + 2 * p1 .. sieveMax] $ \np1 -> do+              VGM.write sieve np1 $ Bit True+        len <- VGM.read iNext 0+        (,VGM.take len is) <$> VU.unsafeFreeze (VGM.take len ps)++      -- https://en.wikipedia.org/wiki/Prime-counting_function+      let !maxPrimeCount :: Int+            -- NOTE: 1,700 is a point where the next function estimates better as far as I tested:+            | limit < 1700 = round (1.25506 * fromIntegral limit / log (fromIntegral limit) :: Double)+            -- Rosser and Schoenfeld Boundsh (1962): holds for x > e^{3/2}:+            | limit < 60184 = round (fromIntegral limit / (log (fromIntegral limit) - 1.5) :: Double)+            -- Pierre Dusart (2010): holds for x >= 60184:+            | otherwise = ceiling (fromIntegral limit / (log (fromIntegral limit) - 1.1) :: Double)++      -- let f x = round (1.25506 * fromIntegral x / log (fromIntegral x) :: Double)+      -- let g x = round (fromIntegral x / (log (fromIntegral x) - 1.5) :: Double)+      -- let h x = ceiling (fromIntegral x / (log (fromIntegral x) - 1.1) :: Double)+      -- let p x = (f x, g x, h x)++      result <- VUM.replicate maxPrimeCount (-1)+      VGM.write result 0 2+      -- FIXME: carry index?+      nPrimes <- VUM.replicate 1 (1 :: Int)++      -- Sieve of Eratosthenes by block of size `s`, ignoring even numers+      -- FIXME: block length of size `s/2` should make more sense?+      block <- VUM.unsafeNew s+      let !r = limit `div` 2+      for_ [1, 1 + s .. r] $ \l -> do+        VGM.set block $ Bit False++        VU.iforM_ ps $ \idx p -> do+          -- FIXME: cut out the ps beforehand+          when (p <= limit) $ do+            i0 <- VGM.read is idx+            let run i = do+                  if i < l + s+                    then do+                      -- within the block+                      VGM.write block (i - l) $ Bit True+                      run $ i + p+                    else do+                      -- went out of the block+                      VGM.write is idx i+            run i0++        block' <- VU.take (min s (r - l)) <$> VU.unsafeFreeze block+        VU.iforM_ block' $ \i (Bit b) -> do+          unless b $ do+            at <- VGM.read nPrimes 0+            when (at < maxPrimeCount) $ do+              VGM.write nPrimes 0 $ at + 1+              VGM.write result at $ (l + i) * 2 + 1++      len <- VGM.read nPrimes 0+      pure $ VGM.take len result++-- | \(O(w \log^3 n)\) Miller–Rabin primality test, where \(w = 3\) for \(x \lt 2^{32}\) and+-- \(w = 7\) for \(x \ge 3^{32}\).+--+-- @since 1.2.6.0+{-# INLINEABLE isPrime #-}+isPrime :: Int -> Bool+isPrime x+  | x <= 1 = False+  -- Up to 11^2:+  | x == 2 || x == 3 || x == 5 || x == 7 = True+  | even x || x `rem` 3 == 0 || x `rem` 5 == 0 || x `rem` 7 == 0 = False+  | x < 121 = True+isPrime x+  -- http://miller-rabin.appspot.com/+  -- \| x < bit 32 = all test [2, 7, 61]+  | x < bit 32 = test 2 && test 7 && test 61+  -- \| otherwise = all test [2, 325, 9375, 28178, 450775, 9780504, 1795265022]+  | otherwise = test 2 && test 325 && test 9375 && test 28178 && test 450775 && test 9780504 && test 1795265022+  where+    !x64 :: Word64 = fromIntegral x+    !d :: Word64 = (x64 - 1) .>>. countTrailingZeros (x64 - 1)+    !mont = M64.fromVal x64+    !one = M64.encode mont 1+    !minusOne = M64.encode mont (x64 - 1)+    test a = inner (M64.powMod mont (M64.encode mont a) (fromIntegral d)) d+      where+        inner :: Word64 -> Word64 -> Bool+        inner y t+          | not (M64.eq x64 y one) && not (M64.eq x64 y minusOne) && t /= x64 - 1 = inner (M64.mulMod mont y y) (t .<<. 1)+          | not (M64.eq x64 y minusOne) && even t = False+          | otherwise = True++-- | Pollard's Rho algorithm.+{-# INLINEABLE rho #-}+rho :: (HasCallStack) => Word64 -> Int -> Int -> Int+rho modVal n c+  | n < 1 = error $ "AtCoder.Extra.Math.rho: given value less than or equal to `1`: `" ++ show n ++ show "`"+  | otherwise = fromIntegral $! inner 1 (M64.encode mont 1) (M64.encode mont 2) (M64.encode mont 1) (M64.encode mont 1) 1+  where+    -- what a mess!!+    !mont = M64.fromVal modVal+    !n64 :: Word64 = fromIntegral n+    !cc = M64.encode mont $ fromIntegral c+    f !x = M64.addMod modVal (M64.mulMod mont x x) cc+    fn 0 !x = x+    fn n_ !x = fn (n_ - 1) $! f x+    !m2 :: Int = bit $ floor (logBase (2.0 :: Double) (fromIntegral n)) `div` 5+    inner r _lastY0 y0 z0 q0 g0+      | g0 == 1 =+          let !y = fn r y0+              (!y', !z', !q', !g') = inner2 0 y z0 q0 g0+           in inner (r .<<. 1) y0 y' z' q' g'+      -- FIXME: It can sometimes slow, depending on the seed value+      -- \| g0 == n64 = inner3 z0+      | otherwise = g0+      where+        inner2 !k !y !z !q !g+          | k >= r || g /= 1 = (y, z, q, g)+          | otherwise =+              let (!y', !q') = fn2 (min m2 (r - k)) y q+                  !g' = gcd (M64.decode mont q) n64+               in inner2 (k + m2) y' y q' g'+          where+            fn2 0 !y_ !q_ = (y_, q_)+            fn2 n_ !y_ !q_ =+              let !y' = f y_+                  !q' = M64.mulMod mont q_ (M64.subMod modVal y0 y')+               in fn2 (n_ - 1) y' q'++-- FIXME: it can sometimes slow, depending on the seed value+-- inner3 !z+--   | g == 1 = inner3 z'+--   | otherwise = g+--   where+--     !z' = f z+--     !g = gcd (M64.decode mont (M64.subMod modVal lastY0 z')) n64++-- | Tries to find a prime factor for the given value, running Pollard's Rho algorithm.+--+-- ==== Constrants+-- - \(x \gt 1\)+{-# INLINEABLE findPrimeFactor #-}+findPrimeFactor :: (HasCallStack) => StdGen -> Int -> (Maybe Int, StdGen)+findPrimeFactor gen0 n+  | n <= 1 = error $ "AtCoder.Extra.Math.findPrimeFactor: given value less than or equal to `1`: " ++ show n ++ show "`"+  | isPrime n = (Just n, gen0)+  | otherwise = tryN 200 gen0+  where+    tryN :: Int -> StdGen -> (Maybe Int, StdGen)+    tryN 0 gen = (Nothing, gen)+    tryN i gen+      | isPrime m = (Just m, gen')+      | otherwise = tryN (i - 1) gen'+      where+        (!rnd, !gen') = uniformR (0, n - 1) gen+        !m = rho (fromIntegral n) n rnd++-- | Returns prime factors in run-length encoding \((p_i, n_i)\), sorted by \(p_i\).+--+-- ==== Constraints+-- - \(x \ge 1\)+--+-- @since 1.2.6.0+{-# INLINE primeFactors #-}+primeFactors :: (HasCallStack) => Int -> VU.Vector (Int, Int)+primeFactors = VU.modify VAI.sort . primeFactorsUnsorted++-- | Returns prime factors in run-length encoding \((p_i, n_i)\) in arbitrary order.+--+-- It internally uses probabilistic method (Pollard's rho algorithm) and it can actually result in+-- runtime error, however, the probability is very low and the API does not return `Maybe`.+--+-- @since 1.2.6.0+{-# INLINEABLE primeFactorsUnsorted #-}+primeFactorsUnsorted :: (HasCallStack) => Int -> VU.Vector (Int, Int)+primeFactorsUnsorted n+  | n < 1 = error $ "AtCoder.Extra.Math.primeFactorsUnsorted: given non-positive value `" ++ show n ++ "`"+  | otherwise = VU.create $ do+      buf <- VUM.unsafeNew (ceiling (logBase (2 :: Double) (fromIntegral n)))++      -- for small prime factors, try them all:+      let runDiv cur iWrite [] = pure (cur, iWrite)+          runDiv cur iWrite (d : rest)+            | d * d > cur = pure (cur, iWrite)+            | otherwise = case tryDiv 0 cur d of+                Just (!cur', !nd) -> do+                  VGM.write buf iWrite (d, nd)+                  runDiv cur' (iWrite + 1) rest+                Nothing -> runDiv cur iWrite rest++      (!n', !iWrite0) <- runDiv n 0 (2 : [3, 5 .. 97])++      -- for bigger prime numbers, use Polland's rho algorithm:+      let runRho !gen !cur !iWrite+            | cur > 1 = case findPrimeFactor gen cur of+                (Just p, !gen') -> do+                  let (!cur', !np) = fromJust $ tryDiv 0 cur p+                  VGM.write buf iWrite (p, np)+                  runRho gen' cur' (iWrite + 1)+                (Nothing, !_gen') -> do+                  -- we could return `Nothing` instead+                  error $ "unable to find prime factor for " ++ show cur+            | otherwise = pure iWrite++      -- NOTE: The seed value ifs fixed here. We could decide it at runtime for possibly faster+      -- submissions on TLE redjuge, however, 're rather preferring deterministic result:+      len <- runRho (mkStdGen 123456789) n' iWrite0+      pure $ VUM.take len buf+  where+    tryDiv :: Int -> Int -> Int -> Maybe (Int, Int)+    tryDiv !nDiv x d+      | r == 0 = tryDiv (nDiv + 1) q d+      | nDiv > 0 = Just (x, nDiv)+      | otherwise = Nothing+      where+        (!q, !r) = x `quotRem` d++-- | Enumerates divisors of the input value.+--+-- ==== Constraints+-- - \(x \ge 1\)+--+-- @since 1.2.6.0+{-# INLINE divisors #-}+divisors :: Int -> VU.Vector Int+-- TODO: use intro sort?+divisors = VU.modify VAR.sort . divisorsUnsorted++-- | Enumerates divisors of the input value.+--+-- ==== Constraints+-- - \(x \ge 1\)+--+-- @since 1.2.6.0+{-# INLINEABLE divisorsUnsorted #-}+divisorsUnsorted :: Int -> VU.Vector Int+divisorsUnsorted x = VU.create $ do+  vec <- VUM.unsafeNew nDivisors+  VGM.write vec 0 1+  VU.foldM'_+    ( \lenSofar (!p, !np) -> do+        (fst <$>)+          $ VU.foldM'+            ( \(!offset, !pp) _ -> do+                let !pp' = pp * p+                -- multiply to all the values sofar:+                VGM.iforM_ (VGM.take lenSofar vec) $ \i vx -> do+                  VGM.write vec (offset + i) $! vx * pp'+                  pure pp'+                pure (offset + lenSofar, pp')+            )+            (lenSofar, 1 :: Int)+          $ VU.generate np (+ 1)+    )+    (1 :: Int)+    pns+  pure vec+  where+    pns = primeFactors x+    (!_, !ns) = VU.unzip pns+    nDivisors = VU.foldl' (\ !acc n -> acc * (n + 1)) (1 :: Int) ns  -- | Calculates \(x^n\) with custom multiplication operator using the binary exponentiation -- technique.
+ src/AtCoder/Extra/Math/Montgomery64.hs view
@@ -0,0 +1,176 @@+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE NamedFieldPuns #-}++-- | Fast modular multiplication for `Word64` using Montgomery multiplication. If the modulus value+-- is known to fit in 32 bits, use the @AtCoder.Internal.Barrett@ module instead.+--+-- @since 1.2.6.0+module AtCoder.Extra.Math.Montgomery64+  ( -- * Montgomery64+    Montgomery64,++    -- * Constructor+    new,+    fromVal,++    -- * Accessor+    umod,++    -- * Montgomery form encoding+    encode,+    decode,+    reduce,++    -- * Calculations+    addMod,+    subMod,+    mulMod,+    powMod,+    eq,+  )+where++import AtCoder.Internal.Assert qualified as ACIA+import Data.Bits (bit, (!>>.))+import Data.WideWord.Word128 (Word128 (..))+import Data.Word (Word64)+import GHC.Exts (Proxy#)+import GHC.Stack (HasCallStack)+import GHC.TypeNats (KnownNat, natVal')++-- TODO: provide with newtype for Montgomery form?++-- | Fast modular multiplication for `Word64` using Montgomery64 multiplication.+--+-- @since 1.2.6.0+data Montgomery64 = Montgomery64+  { mM64 :: {-# UNPACK #-} !Word64,+    rM64 :: {-# UNPACK #-} !Word64,+    n2M64 :: {-# UNPACK #-} !Word64+  }+  deriving+    ( -- | @since 1.2.6.0+      Eq,+      -- | @since 1.2.6.0+      Show+    )++-- TODO: add unasfePerformIO?+-- TODO: remove NOINLINE?++-- | \(O(1)\) Static, shared storage of `Montgomery64`.+--+-- ==== Constraints+-- - \(m \le 2^{62})+-- - \(m\) is odd+--+-- @since 1.2.6.0+{-# NOINLINE new #-}+new :: forall a. (KnownNat a) => Proxy# a -> Montgomery64+-- FIXME: test allocated once+new p = fromVal . fromIntegral $! natVal' p++-- | \(O(1)\) Creates a `Montgomery64` for a modulus value \(m\) of type `Word64` value.+--+-- ==== Constraints+-- - \(m \le 2^{62})+-- - \(m\) is odd+--+-- @since 1.2.6.0+{-# INLINE fromVal #-}+fromVal :: Word64 -> Montgomery64+fromVal m =+  let !m128 :: Word128 = fromIntegral m+      !n2 = word128Lo64 $ (-m128) `mod` m128+      !r = getR m 0+      !_ = ACIA.runtimeAssert (r * m == -1) "AtCoder.Extra.Montgomery64.fromVal: internal implementation error"+   in Montgomery64 m r n2+  where+    !_ = ACIA.runtimeAssert (odd m && m <= bit 62) $ "AtCoder.Extra.Montgomery64.fromVal: not given odd modulus value that is less than or equal to 2^62: " ++ show m+    getR :: Word64 -> Int -> Word64+    getR !acc i+      | i >= 5 = -acc+      | otherwise = getR (acc * (2 - m * acc)) (i + 1)++-- | \(O(1)\) Retrieves the modulus \(m\).+--+-- @since 1.2.6.0+{-# INLINE umod #-}+umod :: Montgomery64 -> Word64+umod Montgomery64 {mM64} = mM64++-- | \(O(1)\) Converts the given `Word64` to Montgomery form.+--+-- @since 1.2.6.0+{-# INLINE encode #-}+encode :: Montgomery64 -> Word64 -> Word64+encode mont@Montgomery64 {n2M64} x = reduce mont $! fromIntegral x * fromIntegral n2M64++-- | \(O(1)\) Retrieves the value from a Montgomery form of value.+--+-- @since 1.2.6.0+{-# INLINE decode #-}+decode :: Montgomery64 -> Word64 -> Word64+decode mont@Montgomery64 {mM64} x =+  let !res = reduce mont $! fromIntegral x+   in if res >= mM64 then res - mM64 else res++-- | \(O(1)\) Takes the mod in Montgomery form.+--+-- @since 1.2.6.0+{-# INLINE reduce #-}+reduce :: Montgomery64 -> Word128 -> Word64+reduce Montgomery64 {mM64, rM64} x =+  word128Hi64 $!+    (x + fromIntegral (word128Lo64 x * rM64) * fromIntegral mM64)++-- | \(O(1)\) Calculates \(a + b \bmod m\) in the Montgomery form.+{-# INLINE addMod #-}+addMod :: Word64 -> Word64 -> Word64 -> Word64+addMod m a b+    | x' >= m = x' - m+    | otherwise = x'+  where+    !x' = a + b++-- | \(O(1)\) Calculates \(a - b \bmod m\) in the Montgomery form.+{-# INLINE subMod #-}+subMod :: Word64 -> Word64 -> Word64 -> Word64+subMod m a b+    | a >= b = a - b+    | otherwise = a - b + m++-- | \(O(1)\) Calculates \(a^n \bmod m\) in the Montgomery form.+--+-- @since 1.2.6.0+{-# INLINE mulMod #-}+mulMod :: Montgomery64 -> Word64 -> Word64 -> Word64+mulMod mont a b = reduce mont $! fromIntegral a * fromIntegral b++-- | \(O(w)\) Calculates \(a^n \bmod m\) in the Montgomery form.+--+-- @since 1.2.6.0+{-# INLINE powMod #-}+powMod :: (HasCallStack) => Montgomery64 -> Word64 -> Int -> Word64+powMod mont x0 n0 = inner n0 (encode mont 1) x0+  where+    !_ = ACIA.runtimeAssert (0 <= n0) $ "AtCoder.Extra.Math.Montgomery64.powMod: given negative exponential `n`: " ++ show n0 ++ show "`"+    inner :: Int -> Word64 -> Word64 -> Word64+    inner !n !r !y+      | n == 0 = r+      | otherwise =+          let !r' = if odd n then mulMod mont r y else r+              !y' = mulMod mont y y+           in inner (n !>>. 1) r' y'++-- | \(O(1)\) Compares two values of Montgomery form and returns whether they represent the same+-- value.+--+-- @since 1.2.6.0+{-# INLINE eq #-}+eq :: Word64 -> Word64 -> Word64 -> Bool+eq mM64 a b = a' == b'+  where+    !a' = if a < mM64 then a else a - mM64+    !b' = if b < mM64 then b else b - mM64+
+ src/AtCoder/Extra/ModInt64.hs view
@@ -0,0 +1,259 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE TypeFamilies #-}++-- | @ModInt@ for 64 bit modulus values.+--+-- @since 1.2.6.0+module AtCoder.Extra.ModInt64+  ( -- * ModInt64+    ModInt64 (..),++    -- * Constructors++    -- ** Safe constructors+    new,+    new64,++    -- ** Unsafe constructor+    unsafeNew,++    -- * Accessors++    -- ** Modulus value+    modulus,++    -- ** Internal value+    val,+    val64,++    -- * Operators+    pow,+    inv,+  )+where++import AtCoder.Internal.Assert qualified as ACIA+import AtCoder.Extra.Math.Montgomery64 qualified as M64+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 (Word64)+import GHC.Exts (proxy#)+import GHC.Stack (HasCallStack)+import GHC.TypeNats (KnownNat, natVal')++-- | `Word64` value that treats the modular arithmetic.+--+-- @since 1.2.6.0+newtype ModInt64 a = ModInt64+  { -- | Montgomery form of the value. Use `val` to retrieve the value.+    --+    -- @since 1.2.6.0+    unModInt64 :: Word64+  }+  deriving+    ( -- | @since 1.2.6.0+      P.Prim+    )++-- | @since 1.2.6.0+instance (KnownNat a) => Eq (ModInt64 a) where+  {-# INLINE (==) #-}+  ModInt64 x == ModInt64 y = M64.eq (fromIntegral (natVal' (proxy# @a))) x y++-- | @since 1.2.6.0+instance (KnownNat a) => Ord (ModInt64 a) where+  {-# INLINE compare #-}+  compare (ModInt64 a) (ModInt64 b) = compare a b++-- | @since 1.2.6.0+instance (KnownNat a) => Read (ModInt64 a) where+  {-# INLINE readsPrec #-}+  readsPrec p s = [(fromInteger x, r) | (!x, !r) <- readsPrec p s]++-- | @since 1.2.6.0+instance (KnownNat a) => Show (ModInt64 a) where+  {-# INLINE show #-}+  show = show . val++-- | \(O(1)\) Creates a `ModInt64` from an `Int` value taking the mod.+--+-- @since 1.2.6.0+{-# INLINE new #-}+new :: forall a. (KnownNat a) => Int -> ModInt64 a+new = ModInt64 . M64.encode (M64.new (proxy# @a)) . fromIntegral . (`mod` m)+  where+    !m = fromIntegral $ natVal' (proxy# @a)++-- | \(O(1)\) Creates a `ModInt64` from a `Word64` value taking the mod.+--+-- @since 1.2.6.0+{-# INLINE new64 #-}+new64 :: forall a. (KnownNat a) => Word64 -> ModInt64 a+new64 = ModInt64 . M64.encode (M64.new (proxy# @a))++-- | \(O(1)\) Creates `ModInt64` from a Montgomery form with no validation.+--+-- @since 1.2.6.0+{-# INLINE unsafeNew #-}+unsafeNew :: (KnownNat a) => Word64 -> ModInt64 a+unsafeNew = ModInt64++-- | \(O(1)\) Retrieve the mod from a `ModInt64` object.+--+-- ==== Complecity+-- - \(O(1)\)+--+-- @since 1.2.6.0+{-# INLINE modulus #-}+modulus :: forall a. (KnownNat a) => ModInt64 a -> Int+modulus _ = fromIntegral (natVal' (proxy# @a))++-- | \(O(1)\) Returns the internal value in `Int`.+--+-- ==== Complecity+-- - \(O(1)\)+--+-- @since 1.2.6.0+{-# INLINE val #-}+val :: forall a. (KnownNat a) => ModInt64 a -> Int+val = fromIntegral . val64++-- | \(O(1)\) Returns the internal value in `Word64`.+--+-- ==== Complecity+-- - \(O(1)\)+--+-- @since 1.2.6.0+{-# INLINE val64 #-}+val64 :: forall a. (KnownNat a) => ModInt64 a -> Word64+val64 (ModInt64 x) = M64.decode (M64.new (proxy# @a)) x++-- | \(O(\log n\) Returns \(x^n\). The implementation is a bit more efficient than `^`.+--+-- ==== Constraints+-- - \(0 \le n\)+--+-- @since 1.2.6.0+{-# INLINE pow #-}+pow :: forall a. (HasCallStack, KnownNat a) => ModInt64 a -> Int -> ModInt64 a+pow (ModInt64 x) n = ModInt64 $! M64.powMod (M64.new (proxy# @a)) x n++-- TODO: move invMod to Montgomery64+-- TODO: time complexity of `inv`?++-- | Returns \(y\) such that \(xy \equiv 1\) holds.+--+-- ==== Constraints+-- - The value must not be zero.+--+-- @since 1.2.6.0+{-# INLINE inv #-}+inv :: forall a. (HasCallStack, KnownNat a) => ModInt64 a -> ModInt64 a+-- TODO: assert zero division?+inv self = inner (val self) m 1 0+  where+    !_ = ACIA.runtimeAssert (val self /= 0) "AtCoder.Extra.ModInt64.inv: given zero"+    !m = fromIntegral (natVal' (proxy# @a))+    inner x y u v+      | y <= 0 = new u+      | otherwise = inner x' y' u' v'+      where+        x' = y+        y' = x - t * y+        u' = v+        v' = u - t * v+        t = x `div` y++-- https://github.com/NyaanNyaan/library/blob/master/modint/montgomery-modint.hpp+-- constexpr mint inverse() const {+--   int x = get(), y = mod, u = 1, v = 0, t = 0, tmp = 0;+--   while (y > 0) {+--     t = x / y;+--     x -= t * y, u -= t * v;+--     tmp = x, x = y, y = tmp;+--     tmp = u, u = v, v = tmp;+--   }+--   return mint{u};+-- }++-- | @since 1.2.6.0+deriving newtype instance (KnownNat p) => Real (ModInt64 p)++-- | @since 1.2.6.0+instance forall p. (KnownNat p) => Num (ModInt64 p) where+  {-# INLINE (+) #-}+  (ModInt64 !x1) + (ModInt64 !x2) = ModInt64 $! M64.addMod m x1 x2+    where+      !m = fromIntegral (natVal' (proxy# @p))+  {-# INLINE (-) #-}+  (ModInt64 !x1) - (ModInt64 !x2) = ModInt64 $! M64.subMod m x1 x2+    where+      !m = fromIntegral (natVal' (proxy# @p))+  {-# INLINE (*) #-}+  (ModInt64 !x1) * (ModInt64 !x2) = ModInt64 $! M64.mulMod (M64.new (proxy# @p)) x1 x2+  {-# INLINE negate #-}+  negate x = 0 - x+  {-# INLINE abs #-}+  abs = id+  {-# INLINE signum #-}+  signum _ = ModInt64 $ M64.encode (M64.new (proxy# @p)) 1+  -- because the input value can be negative, be sure to take the mod:+  {-# INLINE fromInteger #-}+  fromInteger = ModInt64 . M64.encode (M64.new (proxy# @p)) . fromInteger . (`mod` m)+    where+      !m = toInteger $ natVal' (proxy# @p)++-- | @since 1.2.6.0+instance (KnownNat p) => Bounded (ModInt64 p) where+  {-# INLINE minBound #-}+  minBound = ModInt64 0+  {-# INLINE maxBound #-}+  maxBound = ModInt64 . M64.encode (M64.new (proxy# @p)) $! fromIntegral (natVal' (proxy# @p)) - 1++-- | @since 1.2.6.0+instance (KnownNat p) => Enum (ModInt64 p) where+  {-# INLINE toEnum #-}+  toEnum = new+  {-# INLINE fromEnum #-}+  fromEnum = fromIntegral . val++-- | @since 1.2.6.0+instance (KnownNat p) => Integral (ModInt64 p) where+  -- FIXME: THIS IS COMPLETELY WRONG. Compare with `ModInt`.+  {-# INLINE quotRem #-}+  -- quotRem x y =+  --   let !x' = val x+  --       !y' = val y+  --       (!q, !r) = x' `quotRem` y'+  --    in (new q, new r)+  quotRem x y = (x / y, x - x / y * y)+  {-# INLINE toInteger #-}+  toInteger = toInteger . val++-- | @since 1.2.6.0+instance (KnownNat p) => Fractional (ModInt64 p) where+  {-# INLINE recip #-}+  recip = inv+  {-# INLINE fromRational #-}+  fromRational q = fromInteger (numerator q) / fromInteger (denominator q)++-- | @since 1.2.6.0+newtype instance VU.MVector s (ModInt64 a) = MV_ModInt64 (VU.MVector s Word64)++-- | @since 1.2.6.0+newtype instance VU.Vector (ModInt64 a) = V_ModInt64 (VU.Vector Word64)++-- | @since 1.2.6.0+deriving newtype instance VGM.MVector VU.MVector (ModInt64 a)++-- | @since 1.2.6.0+deriving newtype instance VG.Vector VU.Vector (ModInt64 a)++-- | @since 1.2.6.0+instance VU.Unbox (ModInt64 a)
src/AtCoder/Extra/SqrtDecomposition.hs view
@@ -30,7 +30,7 @@ import Data.Foldable (for_) import Data.Vector.Unboxed qualified as VU --- INLINE all the functions, even if the performance gain is just a little bit.+-- INLINE all the functions, even if the performance gain is just a little bit, in case it matters.  -- | \(O(\sqrt n)\) Runs user function for each block. {-# INLINE forM_ #-}@@ -67,10 +67,14 @@  -- | \(O(\sqrt n)\) Runs user function for each block and concatanate their monoid output. --+-- ==== Constraints+-- - \(l \le r\)+-- - If an empty interval is queried, the @readPart@ function must return a valid value.+-- -- @since 1.2.5.0 {-# INLINE foldMapM #-} foldMapM ::-  (Monad m, Monoid a) =>+  (Monad m, Semigroup a) =>   -- | Context: block length.   Int ->   -- | Function: @readFull@ function that takes target block index and returns monoid value of it.@@ -89,6 +93,10 @@ -- | \(O(\sqrt n)\) Runs user function for each block and concatanates their output with user -- function. --+-- ==== Constraints+-- - \(l \le r\)+-- - If an empty interval is queried, the @readPart@ function must return a valid value.+-- -- @since 1.2.5.0 {-# INLINE foldMapWithM #-} foldMapWithM ::@@ -133,6 +141,9 @@  -- | \(O(\sqrt n)\) Runs user function for each block, performing left folding. --+-- ==== Constraints+-- - \(l \le r\)+-- -- @since 1.2.5.0 {-# INLINE foldM #-} foldM ::@@ -158,7 +169,9 @@   let (!ir, !remR) = r `divMod` blockLen   if il == ir     then do-      foldPart s0 il l r+      if remL == remR+        then pure s0+        else foldPart s0 il l r     else do       !sx <-         if remL == 0@@ -174,6 +187,9 @@         else foldPart sm ir (r - remR) r  -- | \(O(\sqrt n)\) `foldM` with return value discarded.+--+-- ==== Constraints+-- - \(l \le r\) -- -- @since 1.2.5.0 {-# INLINE foldM_ #-}
src/AtCoder/ModInt.hs view
@@ -79,7 +79,7 @@ import GHC.Stack (HasCallStack) import GHC.TypeNats (KnownNat, natVal, natVal') --- | `KnownNat` with meta information used for modulus.+-- | `KnownNat` with meta information as a modulus value for convolution. -- -- @since 1.0.0.0 class (KnownNat a) => Modulus a where@@ -244,7 +244,7 @@ modulus :: forall a. (KnownNat a) => ModInt a -> Int modulus _ = fromIntegral (natVal' (proxy# @a)) --- | Returns the internal value converted to `Int`.+-- | Returns the internal value in `Int`. -- -- ==== Complecity -- - \(O(1)\)@@ -265,7 +265,7 @@ val32 :: (KnownNat a) => ModInt a -> Word32 val32 = unModInt --- | Returns the internal value converted to `Word32`.+-- | Returns the internal value in `Word32`. -- -- ==== Complecity -- - \(O(1)\)
test/Main.hs view
@@ -20,6 +20,8 @@ import Tests.Extra.KdTree qualified import Tests.Extra.LazyKdTree qualified import Tests.Extra.Math qualified+import Tests.Extra.Math.Montgomery64 qualified+import Tests.Extra.ModInt64 qualified import Tests.Extra.Monoid qualified import Tests.Extra.MultiSet qualified import Tests.Extra.SegTree2d qualified@@ -75,6 +77,8 @@             testGroup "KdTree" Tests.Extra.KdTree.tests,             testGroup "LazyKdTree" Tests.Extra.LazyKdTree.tests,             testGroup "Math" Tests.Extra.Math.tests,+            testGroup "Math.Montgomery64" Tests.Extra.Math.Montgomery64.tests,+            testGroup "ModInt64" Tests.Extra.ModInt64.tests,             testGroup "Monoid" Tests.Extra.Monoid.tests,             testGroup "MultiSet" Tests.Extra.MultiSet.tests,             testGroup "SegTree2d" Tests.Extra.SegTree2d.tests,
test/Tests/Extra/Math.hs view
@@ -1,10 +1,14 @@ module Tests.Extra.Math (tests) where  import AtCoder.Extra.Math qualified as ACEM+import Data.Foldable (for_)+import Data.List qualified as L import Data.Proxy (Proxy (..)) import Data.Semigroup (Max (..), Min (..), Sum (..), mtimesDefault, stimes)+import Data.Vector.Unboxed qualified as VU import Test.QuickCheck.Property qualified as QC import Test.Tasty+import Test.Tasty.HUnit import Test.Tasty.QuickCheck qualified as QC import Tests.Util (myForAllShrink) @@ -36,6 +40,84 @@     rhsS = "mtimes n s"     rhs (QC.NonNegative !n, !m) = mtimesDefault n m +-- | This is a solid, fast implementation of prime number enumeration for lists.+truePrimes :: [Int]+truePrimes = 2 : 3 : minus [5, 7 ..] (unionAll [[p * p, p * p + 2 * p ..] | p <- tail truePrimes])+  where+    minus (x : xs) (y : ys) = case compare x y of+      LT -> x : minus xs (y : ys)+      EQ -> minus xs ys+      GT -> minus (x : xs) ys+    minus xs _ = xs++    union (x : xs) (y : ys) = case compare x y of+      LT -> x : union xs (y : ys)+      EQ -> x : union xs ys+      GT -> y : union (x : xs) ys+    union xs [] = xs+    union [] ys = ys++    unionAll :: (Ord a) => [[a]] -> [a]+    unionAll ((x : xs) : t) = x : union xs (unionAll $ pairs t)+      where+        pairs ((x : xs) : ys : t) = (x : union xs ys) : pairs t+        pairs _ = error "unionAll _ pairs: unreachable"+    unionAll _ = error "unionAll: unreachable"++-- | This is a solid, fast implementation of prime number enumeration for lists.+truePrimeFactors :: Int -> [(Int, Int)]+truePrimeFactors !n_ = map (\ !xs -> (head xs, length xs)) . L.group $ inner n_ input+  where+    -- TODO: reuse `primes`?+    input = 2 : 3 : [y | x <- [5, 11 ..], y <- [x, x + 2]]+    inner n pps@(p : ps)+      | n == 1 = []+      | n < p * p = [n]+      | r == 0 = p : inner q pps+      | otherwise = inner n ps+      where+        (q, r) = divMod n p+    inner _ _ = error "unreachable"++trueDivisors :: Int -> [Int]+trueDivisors n = L.sort $ inner 1+  where+    inner k+      -- no dependency to `Int` square root function+      | k * k > n = []+      -- no divisor duplication+      | k * k == n = [k]+      -- not sorted yet+      | r == 0 = k : d : inner (succ k)+      -- ignore non divisors+      | otherwise = inner (succ k)+      where+        -- This strict evaluation and unboxing takes some effect, even though they're not always+        -- used.+        (!d, !r) = n `divMod` k++-- unit_primes :: TestTree+-- unit_primes = testCase "primes" $ do+--   for_ [0 .. 10 ^ 9] $ \upper -> do+--     when (upper `mod` 10000 == 0) $ do+--       let !_ = traceShow upper ()+--       pure ()+--     let expected = VU.fromList $ takeWhile (<= upper) truePrimes+--     let result = ACEM.primes upper+--     result @?= expected++prop_primeFactors :: QC.Positive Int -> QC.Property+prop_primeFactors (QC.Positive x) =+  let expected = VU.fromList $ truePrimeFactors x+      result = ACEM.primeFactors x+   in result QC.=== expected++prop_divisors :: QC.Positive Int -> QC.Property+prop_divisors (QC.Positive x) =+  let expected = VU.fromList $ trueDivisors x+      result = ACEM.divisors x+   in result QC.=== expected+ tests :: [TestTree] tests =   [ testGroup@@ -51,5 +133,13 @@         QC.testProperty "Product" (prop_mtimes' (Proxy @(Sum Int))),         QC.testProperty "Max" (prop_mtimes' (Proxy @(Max Int))),         QC.testProperty "Min" (prop_mtimes' (Proxy @(Min Int)))+      ],+    testGroup+      "primes"+      [ -- unit_primes+        QC.testProperty "primeFactors" prop_primeFactors,+        QC.testProperty "divisors" prop_divisors       ]   ]++-- unit_primes
+ test/Tests/Extra/Math/Montgomery64.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE TypeFamilies #-}++module Tests.Extra.Math.Montgomery64 (tests) where++import AtCoder.Extra.Math qualified as ACEM+import AtCoder.Extra.Math.Montgomery64 qualified as M+import Data.Bits+import Data.WideWord.Word128 (Word128 (..))+import Data.Word (Word64)+import Test.Tasty+import Test.Tasty.QuickCheck qualified as QC++to128 :: (Integral a) => a -> Word128+to128 = fromIntegral++mulMod :: Word64 -> Word64 -> Word64 -> Word64+mulMod m x y = word128Lo64 $! (to128 (x `mod` m) * to128 (y `mod` m)) `mod` to128 m++p :: Word64 -> Bool+p m = odd m && m <= bit 62++prop_mulMod :: QC.Positive Word64 -> Word64 -> Word64 -> QC.Property+prop_mulMod (QC.Positive m) x y =+  p m QC.==>+    let !mont = M.fromVal m+        !res = M.decode mont $ M.mulMod mont (M.encode mont x) (M.encode mont y)+        !expected = mulMod m x y+     in res QC.=== expected++prop_powMod :: QC.Positive Word64 -> Word64 -> QC.Positive Int -> QC.Property+prop_powMod (QC.Positive m) x (QC.Positive n) =+  p m QC.==>+    let !mont = M.fromVal m+        !res = M.decode mont $ M.powMod mont (M.encode mont x) n+        !expected = ACEM.power (mulMod m) n (x `mod` m)+     in res QC.=== expected++tests :: [TestTree]+tests =+  [ QC.testProperty "mulMod" prop_mulMod,+    QC.testProperty "powMod" prop_powMod+  ]
+ test/Tests/Extra/ModInt64.hs view
@@ -0,0 +1,219 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE TypeFamilies #-}++module Tests.Extra.ModInt64 (tests) where++import AtCoder.Extra.Math qualified as ACEM+import AtCoder.Extra.ModInt64 qualified as M+import AtCoder.ModInt qualified as M32+import Data.Semiring (Ring (..), Semiring (..), WrappedNum (..))+import Data.WideWord.Word128 (Word128 (..))+import Data.Word (Word64 (..))+import GHC.Exts (Proxy#, proxy#)+import GHC.TypeNats (KnownNat, natVal')+import Test.QuickCheck.Classes qualified as QCC+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck qualified as QC+import Tests.Util (laws)++deriving via (WrappedNum Word64) instance Semiring (M.ModInt64 a)++deriving via (WrappedNum Word64) instance Ring (M.ModInt64 a)++type M1 = 3++type M2 = 5++type M3 = 998244353++type M4 = 1000000007++type M5 = 4611686018427387847++instance M32.Modulus M1 where+  {-# INLINE isPrimeModulus #-}+  isPrimeModulus _ = True++  -- FIXME: wrong+  primitiveRootModulus _ = (-1)++instance M32.Modulus M2 where+  {-# INLINE isPrimeModulus #-}+  isPrimeModulus _ = True++  -- FIXME: wrong+  primitiveRootModulus _ = (-1)++instance (KnownNat a) => QC.Arbitrary (M.ModInt64 a) where+  arbitrary = M.new <$> QC.arbitrary++to128 :: (Integral a) => a -> Word128+to128 = fromIntegral++mulMod :: Int -> Int -> Int -> Int+mulMod m x y = fromIntegral . word128Lo64 $! (to128 (x `mod` m) * to128 (y `mod` m)) `mod` to128 m++unit_literal :: forall a. (KnownNat a) => Proxy# a -> TestTree+unit_literal proxy = testCase "literal" $ do+  let !m :: Int = fromIntegral $ natVal' proxy+  (@?= (0 `mod` m)) $ fromIntegral (0 :: M.ModInt64 a)+  (@?= ((-1) `mod` m)) $ fromIntegral (-1 :: M.ModInt64 a)+  (@?= (1 `mod` m)) $ fromIntegral (1 :: M.ModInt64 a)+  (@?= (m `mod` m)) $ fromIntegral (M.new @a m)+  (@?= ((m - 1) `mod` m)) $ fromIntegral (M.new @a (m - 1))+  (@?= ((m + 1) `mod` m)) $ fromIntegral (M.new @a (m + 1))++prop_addMod :: forall a. (KnownNat a) => Proxy# a -> Int -> Int -> QC.Property+prop_addMod proxy x y =+  let !m = fromIntegral $ natVal' proxy+      !res = M.val $ M.new @a x + M.new @a y+      !expected = (x + y) `mod` m+   in res QC.=== expected++prop_subMod :: forall a. (KnownNat a) => Proxy# a -> Int -> Int -> QC.Property+prop_subMod proxy x y =+  let !m = fromIntegral $ natVal' proxy+      !res = M.val $ M.new @a x - M.new @a y+      !expected = (x - y) `mod` m+   in res QC.=== expected++prop_mulMod :: forall a. (KnownNat a) => Proxy# a -> Int -> Int -> QC.Property+prop_mulMod proxy x y =+  let !m = fromIntegral $ natVal' proxy+      !res = M.val $ M.new @a x * M.new @a y+      !expected = mulMod m x y+   in res QC.=== expected++prop_powMod :: forall a. (KnownNat a) => Proxy# a -> Int -> QC.Positive Int -> QC.Property+prop_powMod proxy x (QC.Positive n) =+  let !m = fromIntegral $ natVal' proxy+      !res = M.val $ M.pow (M.new @a x) n+      !expected = ACEM.power (mulMod m) n (x `mod` m)+   in res QC.=== expected++prop_inv :: forall a. (KnownNat a) => M.ModInt64 a -> QC.Property+prop_inv x =+  M.val x+    /= 0+    QC.==> QC.counterexample (show x)+    $ QC.conjoin+      [ M.inv x * x QC.=== M.new 1,+        M.new 1 QC.=== M.inv x * x+      ]++prop_quotRem :: forall a. (M32.Modulus a) => Proxy# a -> Int -> QC.NonZero Int -> QC.Property+prop_quotRem _ x (QC.NonZero y) =+  (y `mod` m /= 0) QC.==>+    let (!resQ, !resR) = M.new @a x `quotRem` M.new @a y+        (!expQ, !expR) = M32.new @a x `quotRem` M32.new @a y+     in QC.conjoin+          [ M.val resQ QC.=== M32.val expQ,+            M.val resR QC.=== M32.val expR+          ]+  where+    !m = fromIntegral $ natVal' (proxy# @a)++prop_eq :: forall a. (KnownNat a) => Proxy# a -> Word64 -> Word64 -> QC.Property+prop_eq _ x y = lhs QC.=== rhs+  where+    !lhs = M.new64 @a x == M.new64 @a y+    !m = fromIntegral $ natVal' (proxy# @a)+    !rhs = x `mod` m == y `mod` m++-- Cannot create list for unlifted types+--+-- {-# LANGUAGE ImpredicativeTypes #-}+-- modProps :: String -> [forall a. (KnownNat a) => Proxy# a -> QC.Property] -> TestTree+-- modProps title prop =+--   testGroup title $+--     map+--       (\proxy -> QC.testProperty (show (natVal' proxy)) (prop proxy))+--       [proxy# @M1, proxy# @M2, proxy# @M3, proxy# @M4, proxy# @M5]++tests :: [TestTree]+tests =+  [ testGroup+      "literal"+      [ unit_literal (proxy# @M1),+        unit_literal (proxy# @M2),+        unit_literal (proxy# @M3),+        unit_literal (proxy# @M4),+        unit_literal (proxy# @M5)+      ],+    testGroup+      "inv"+      [ QC.testProperty "1" (prop_inv @M1),+        QC.testProperty "2" (prop_inv @M2),+        QC.testProperty "3" (prop_inv @M3),+        QC.testProperty "4" (prop_inv @M4),+        QC.testProperty "5" (prop_inv @M5)+      ],+    testGroup+      "quotRem"+      [ QC.testProperty "1" (prop_quotRem (proxy# @M1)),+        QC.testProperty "2" (prop_quotRem (proxy# @M2)),+        QC.testProperty "3" (prop_quotRem (proxy# @M3)),+        QC.testProperty "4" (prop_quotRem (proxy# @M4))+        -- 64 bit+        -- QC.testProperty "5" (prop_quotRem (proxy# @M5))+      ],+    testGroup+      "eq"+      [ QC.testProperty "1" (prop_eq (proxy# @M1)),+        QC.testProperty "2" (prop_eq (proxy# @M2)),+        QC.testProperty "3" (prop_eq (proxy# @M3)),+        QC.testProperty "4" (prop_eq (proxy# @M4)),+        QC.testProperty "5" (prop_eq (proxy# @M5))+      ],+    testGroup+      "addMod"+      [ QC.testProperty "1" (prop_addMod (proxy# @M1)),+        QC.testProperty "2" (prop_addMod (proxy# @M2)),+        QC.testProperty "3" (prop_addMod (proxy# @M3)),+        QC.testProperty "4" (prop_addMod (proxy# @M4)),+        QC.testProperty "5" (prop_addMod (proxy# @M5))+      ],+    testGroup+      "subMod"+      [ QC.testProperty "1" (prop_subMod (proxy# @M1)),+        QC.testProperty "2" (prop_subMod (proxy# @M2)),+        QC.testProperty "3" (prop_subMod (proxy# @M3)),+        QC.testProperty "4" (prop_subMod (proxy# @M4)),+        QC.testProperty "5" (prop_subMod (proxy# @M5))+      ],+    testGroup+      "mulMod"+      [ QC.testProperty "1" (prop_mulMod (proxy# @M1)),+        QC.testProperty "2" (prop_mulMod (proxy# @M2)),+        QC.testProperty "3" (prop_mulMod (proxy# @M3)),+        QC.testProperty "4" (prop_mulMod (proxy# @M4)),+        QC.testProperty "5" (prop_mulMod (proxy# @M5))+      ],+    testGroup+      "powMod"+      [ QC.testProperty "1" (prop_powMod (proxy# @M1)),+        QC.testProperty "2" (prop_powMod (proxy# @M2)),+        QC.testProperty "3" (prop_powMod (proxy# @M3)),+        QC.testProperty "4" (prop_powMod (proxy# @M4)),+        QC.testProperty "5" (prop_powMod (proxy# @M5))+      ],+    testGroup+      "laws"+      [ laws @(M.ModInt64 M5)+          [ QCC.eqLaws,+            QCC.numLaws,+            QCC.integralLaws,+            QCC.ordLaws,+            QCC.enumLaws,+            QCC.boundedEnumLaws,+            QCC.primLaws,+            QCC.semiringLaws,+            QCC.ringLaws,+            QCC.showReadLaws+          ]+      ]+  ]