{-# LANGUAGE NamedFieldPuns #-}
module Freckle.App.Random
( smallRandomSubsetOfLargeIntegerRange
, Range (..)
, NonEmptyRange (..)
, inclusiveRange
) where
import Freckle.App.Prelude
import Control.Monad.Random (MonadRandom (..), Random)
import Control.Monad.ST (runST)
import Control.Monad.State.Strict (execStateT, get, put)
import Data.Functor ((<&>))
import Data.STRef (newSTRef, readSTRef, writeSTRef)
import Numeric.Natural (Natural)
import Data.Set qualified as Set
data Range i
= RangeEmpty
| RangeNonEmpty (NonEmptyRange i)
data NonEmptyRange i = NonEmptyRange
{ forall i. NonEmptyRange i -> i
inclusiveMinBound :: i
, forall i. NonEmptyRange i -> Natural
offset :: Natural
}
inclusiveRange
:: Integral i
=> i
-> i
-> Range i
inclusiveRange :: forall i. Integral i => i -> i -> Range i
inclusiveRange i
a i
b =
if i
a i -> i -> Bool
forall a. Ord a => a -> a -> Bool
<= i
b
then NonEmptyRange i -> Range i
forall i. NonEmptyRange i -> Range i
RangeNonEmpty (i -> Natural -> NonEmptyRange i
forall i. i -> Natural -> NonEmptyRange i
NonEmptyRange i
a (i -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (i
b i -> i -> i
forall a. Num a => a -> a -> a
- i
a)))
else Range i
forall i. Range i
RangeEmpty
smallRandomSubsetOfLargeIntegerRange
:: (MonadRandom m, Random i, Integral i)
=> Natural
-> Range i
-> m (Set i)
smallRandomSubsetOfLargeIntegerRange :: forall (m :: * -> *) i.
(MonadRandom m, Random i, Integral i) =>
Natural -> Range i -> m (Set i)
smallRandomSubsetOfLargeIntegerRange Natural
n = \case
Range i
RangeEmpty -> Set i -> m (Set i)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Set i
forall a. Set a
Set.empty
RangeNonEmpty NonEmptyRange i
r ->
(RangeWithGaps i -> Set i) -> m (RangeWithGaps i) -> m (Set i)
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap RangeWithGaps i -> Set i
forall i. RangeWithGaps i -> Set i
gaps (m (RangeWithGaps i) -> m (Set i))
-> m (RangeWithGaps i) -> m (Set i)
forall a b. (a -> b) -> a -> b
$
(StateT (RangeWithGaps i) m ()
-> RangeWithGaps i -> m (RangeWithGaps i))
-> RangeWithGaps i
-> StateT (RangeWithGaps i) m ()
-> m (RangeWithGaps i)
forall a b c. (a -> b -> c) -> b -> a -> c
flip StateT (RangeWithGaps i) m ()
-> RangeWithGaps i -> m (RangeWithGaps i)
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m s
execStateT (NonEmptyRange i -> Set i -> RangeWithGaps i
forall i. NonEmptyRange i -> Set i -> RangeWithGaps i
RangeWithGaps NonEmptyRange i
r Set i
forall a. Set a
Set.empty) (StateT (RangeWithGaps i) m () -> m (RangeWithGaps i))
-> StateT (RangeWithGaps i) m () -> m (RangeWithGaps i)
forall a b. (a -> b) -> a -> b
$
[Natural]
-> (Natural -> StateT (RangeWithGaps i) m ())
-> StateT (RangeWithGaps i) m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Natural
1 .. Natural
n] ((Natural -> StateT (RangeWithGaps i) m ())
-> StateT (RangeWithGaps i) m ())
-> (Natural -> StateT (RangeWithGaps i) m ())
-> StateT (RangeWithGaps i) m ()
forall a b. (a -> b) -> a -> b
$ \Natural
_ -> do
StateT (RangeWithGaps i) m (RangeWithGaps i)
forall s (m :: * -> *). MonadState s m => m s
get StateT (RangeWithGaps i) m (RangeWithGaps i)
-> (RangeWithGaps i
-> StateT (RangeWithGaps i) m (RangeWithGaps i))
-> StateT (RangeWithGaps i) m (RangeWithGaps i)
forall a b.
StateT (RangeWithGaps i) m a
-> (a -> StateT (RangeWithGaps i) m b)
-> StateT (RangeWithGaps i) m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (m (RangeWithGaps i) -> StateT (RangeWithGaps i) m (RangeWithGaps i)
forall (m :: * -> *) a.
Monad m =>
m a -> StateT (RangeWithGaps i) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (RangeWithGaps i)
-> StateT (RangeWithGaps i) m (RangeWithGaps i))
-> (RangeWithGaps i -> m (RangeWithGaps i))
-> RangeWithGaps i
-> StateT (RangeWithGaps i) m (RangeWithGaps i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RangeWithGaps i -> m (RangeWithGaps i)
forall (m :: * -> *) i.
(MonadRandom m, Random i, Integral i) =>
RangeWithGaps i -> m (RangeWithGaps i)
randomlyRemove) StateT (RangeWithGaps i) m (RangeWithGaps i)
-> (RangeWithGaps i -> StateT (RangeWithGaps i) m ())
-> StateT (RangeWithGaps i) m ()
forall a b.
StateT (RangeWithGaps i) m a
-> (a -> StateT (RangeWithGaps i) m b)
-> StateT (RangeWithGaps i) m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= RangeWithGaps i -> StateT (RangeWithGaps i) m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put
data RangeWithGaps i = RangeWithGaps
{ forall i. RangeWithGaps i -> NonEmptyRange i
rangeWithoutGaps :: NonEmptyRange i
, forall i. RangeWithGaps i -> Set i
gaps :: Set i
}
randomlyRemove
:: (MonadRandom m, Random i, Integral i) => RangeWithGaps i -> m (RangeWithGaps i)
randomlyRemove :: forall (m :: * -> *) i.
(MonadRandom m, Random i, Integral i) =>
RangeWithGaps i -> m (RangeWithGaps i)
randomlyRemove RangeWithGaps i
rg =
RangeWithGaps i -> m (Maybe i)
forall (m :: * -> *) i.
(MonadRandom m, Random i, Integral i) =>
RangeWithGaps i -> m (Maybe i)
randomFromRangeWithGaps RangeWithGaps i
rg m (Maybe i) -> (Maybe i -> RangeWithGaps i) -> m (RangeWithGaps i)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
Maybe i
Nothing -> RangeWithGaps i
rg
Just i
i -> RangeWithGaps i
rg {gaps = Set.insert i (gaps rg)}
randomFromRangeWithGaps
:: (MonadRandom m, Random i, Integral i)
=> RangeWithGaps i
-> m (Maybe i)
randomFromRangeWithGaps :: forall (m :: * -> *) i.
(MonadRandom m, Random i, Integral i) =>
RangeWithGaps i -> m (Maybe i)
randomFromRangeWithGaps RangeWithGaps i
rg =
let
RangeWithGaps {NonEmptyRange i
rangeWithoutGaps :: forall i. RangeWithGaps i -> NonEmptyRange i
rangeWithoutGaps :: NonEmptyRange i
rangeWithoutGaps, Set i
gaps :: forall i. RangeWithGaps i -> Set i
gaps :: Set i
gaps} = RangeWithGaps i
rg
NonEmptyRange {i
inclusiveMinBound :: forall i. NonEmptyRange i -> i
inclusiveMinBound :: i
inclusiveMinBound, Natural
offset :: forall i. NonEmptyRange i -> Natural
offset :: Natural
offset} = NonEmptyRange i
rangeWithoutGaps
in
if Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Set i -> Int
forall a. Set a -> Int
Set.size Set i
gaps) Natural -> Natural -> Bool
forall a. Eq a => a -> a -> Bool
== Natural
offset Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Natural
1
then Maybe i -> m (Maybe i)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe i
forall a. Maybe a
Nothing
else
i -> Maybe i
forall a. a -> Maybe a
Just
(i -> Maybe i) -> m i -> m (Maybe i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
i
r <-
(i
inclusiveMinBound +)
(i -> i) -> m i -> m i
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (i, i) -> m i
forall a. Random a => (a, a) -> m a
forall (m :: * -> *) a. (MonadRandom m, Random a) => (a, a) -> m a
getRandomR (i
0, Natural -> i
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
offset i -> i -> i
forall a. Num a => a -> a -> a
- Int -> i
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Set i -> Int
forall a. Set a -> Int
Set.size Set i
gaps))
i -> m i
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (i -> m i) -> i -> m i
forall a b. (a -> b) -> a -> b
$ (forall s. ST s i) -> i
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s i) -> i) -> (forall s. ST s i) -> i
forall a b. (a -> b) -> a -> b
$ do
STRef s i
xRef <- i -> ST s (STRef s i)
forall a s. a -> ST s (STRef s a)
newSTRef i
r
STRef s [i]
gapQueue <- [i] -> ST s (STRef s [i])
forall a s. a -> ST s (STRef s a)
newSTRef ([i] -> ST s (STRef s [i])) -> [i] -> ST s (STRef s [i])
forall a b. (a -> b) -> a -> b
$ Set i -> [i]
forall a. Set a -> [a]
Set.toAscList Set i
gaps
let go :: ST s i
go = do
i
x <- STRef s i -> ST s i
forall s a. STRef s a -> ST s a
readSTRef STRef s i
xRef
STRef s [i] -> ST s [i]
forall s a. STRef s a -> ST s a
readSTRef STRef s [i]
gapQueue ST s [i] -> ([i] -> ST s i) -> ST s i
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
i
g : [i]
gs | i
g i -> i -> Bool
forall a. Ord a => a -> a -> Bool
<= i
x -> do
STRef s i -> i -> ST s ()
forall s a. STRef s a -> a -> ST s ()
writeSTRef STRef s i
xRef (i
x i -> i -> i
forall a. Num a => a -> a -> a
+ i
1)
STRef s [i] -> [i] -> ST s ()
forall s a. STRef s a -> a -> ST s ()
writeSTRef STRef s [i]
gapQueue [i]
gs
ST s i
go
[i]
_ -> i -> ST s i
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure i
x
ST s i
go