{-# LANGUAGE OverloadedLists  #-}
{-# LANGUAGE TypeApplications #-}

module ZkFold.Base.Algebra.Basic.Permutations (
    IndexSet,
    IndexPartition,
    Permutation,
    fromPermutation,
    applyPermutation,
    mkIndexPartition,
    fromCycles
) where

import           Data.Map                         (Map, elems, empty, singleton, union)
import           Data.Maybe                       (fromJust)
import qualified Data.Vector                      as V
import           Numeric.Natural                  (Natural)
import           Prelude                          hiding (Num (..), drop, length, mod, (!!))
import qualified Prelude                          as P
import           Test.QuickCheck                  (Arbitrary (..))

import           ZkFold.Base.Algebra.Basic.Class
import           ZkFold.Base.Algebra.Basic.Number
import           ZkFold.Base.Data.Vector          (Vector (..), fromVector, toVector)
import           ZkFold.Prelude                   (chooseNatural, drop, length, (!!))

-- TODO (Issue #18): make the code safer

------------------------------ Index sets and partitions -------------------------------------

type IndexSet = V.Vector Natural
type IndexPartition a = Map a IndexSet

mkIndexPartition :: Ord a => V.Vector a -> IndexPartition a
mkIndexPartition :: forall a. Ord a => Vector a -> IndexPartition a
mkIndexPartition Vector a
vs =
    let f :: a -> Map a (Vector Natural)
f a
i = a -> Vector Natural -> Map a (Vector Natural)
forall k a. k -> a -> Map k a
singleton a
i (Vector Natural -> Map a (Vector Natural))
-> Vector Natural -> Map a (Vector Natural)
forall a b. (a -> b) -> a -> b
$ ((a, Natural) -> Natural) -> Vector (a, Natural) -> Vector Natural
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, Natural) -> Natural
forall a b. (a, b) -> b
snd (Vector (a, Natural) -> Vector Natural)
-> Vector (a, Natural) -> Vector Natural
forall a b. (a -> b) -> a -> b
$ ((a, Natural) -> Bool)
-> Vector (a, Natural) -> Vector (a, Natural)
forall a. (a -> Bool) -> Vector a -> Vector a
V.filter (\(a
v, Natural
_) -> a
v a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
i) (Vector (a, Natural) -> Vector (a, Natural))
-> Vector (a, Natural) -> Vector (a, Natural)
forall a b. (a -> b) -> a -> b
$ Vector a -> Vector Natural -> Vector (a, Natural)
forall a b. Vector a -> Vector b -> Vector (a, b)
V.zip Vector a
vs [Natural
Item (Vector Natural)
1 .. Vector a -> Natural
forall (t :: Type -> Type) a. Foldable t => t a -> Natural
length Vector a
vs]
    in (Map a (Vector Natural)
 -> Map a (Vector Natural) -> Map a (Vector Natural))
-> Map a (Vector Natural)
-> Vector (Map a (Vector Natural))
-> Map a (Vector Natural)
forall a b. (a -> b -> a) -> a -> Vector b -> a
V.foldl Map a (Vector Natural)
-> Map a (Vector Natural) -> Map a (Vector Natural)
forall k a. Ord k => Map k a -> Map k a -> Map k a
union Map a (Vector Natural)
forall k a. Map k a
empty (Vector (Map a (Vector Natural)) -> Map a (Vector Natural))
-> Vector (Map a (Vector Natural)) -> Map a (Vector Natural)
forall a b. (a -> b) -> a -> b
$ (a -> Map a (Vector Natural))
-> Vector a -> Vector (Map a (Vector Natural))
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Map a (Vector Natural)
f Vector a
vs

------------------------------------- Permutations -------------------------------------------

newtype Permutation n = Permutation (Vector n Natural)
    deriving (Int -> Permutation n -> ShowS
[Permutation n] -> ShowS
Permutation n -> String
(Int -> Permutation n -> ShowS)
-> (Permutation n -> String)
-> ([Permutation n] -> ShowS)
-> Show (Permutation n)
forall (n :: Natural). Int -> Permutation n -> ShowS
forall (n :: Natural). [Permutation n] -> ShowS
forall (n :: Natural). Permutation n -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall (n :: Natural). Int -> Permutation n -> ShowS
showsPrec :: Int -> Permutation n -> ShowS
$cshow :: forall (n :: Natural). Permutation n -> String
show :: Permutation n -> String
$cshowList :: forall (n :: Natural). [Permutation n] -> ShowS
showList :: [Permutation n] -> ShowS
Show, Permutation n -> Permutation n -> Bool
(Permutation n -> Permutation n -> Bool)
-> (Permutation n -> Permutation n -> Bool) -> Eq (Permutation n)
forall (n :: Natural). Permutation n -> Permutation n -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall (n :: Natural). Permutation n -> Permutation n -> Bool
== :: Permutation n -> Permutation n -> Bool
$c/= :: forall (n :: Natural). Permutation n -> Permutation n -> Bool
/= :: Permutation n -> Permutation n -> Bool
Eq)

instance KnownNat n => Arbitrary (Permutation n) where
    arbitrary :: Gen (Permutation n)
arbitrary =
        let f :: [a] -> [a] -> Gen [a]
f [a]
as [] = [a] -> Gen [a]
forall a. a -> Gen a
forall (m :: Type -> Type) a. Monad m => a -> m a
return [a]
as
            f [a]
as [a]
bs = do
                Natural
i <- (Natural, Natural) -> Gen Natural
chooseNatural (Natural
0, [a] -> Natural
forall (t :: Type -> Type) a. Foldable t => t a -> Natural
length [a]
bs Natural -> Natural -> Natural
-! Natural
1)
                let as' :: [a]
as' = ([a]
bs [a] -> Natural -> a
forall a. [a] -> Natural -> a
!! Natural
i) a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
as
                    bs' :: [a]
bs' = Natural -> [a] -> [a]
forall a. Natural -> [a] -> [a]
drop Natural
i [a]
bs
                [a] -> [a] -> Gen [a]
f [a]
as' [a]
bs'
        in Vector n Natural -> Permutation n
forall (n :: Natural). Vector n Natural -> Permutation n
Permutation (Vector n Natural -> Permutation n)
-> ([Natural] -> Vector n Natural) -> [Natural] -> Permutation n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Natural] -> Vector n Natural
forall (size :: Natural) a. [a] -> Vector size a
Vector ([Natural] -> Permutation n)
-> Gen [Natural] -> Gen (Permutation n)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> [Natural] -> [Natural] -> Gen [Natural]
forall {a}. [a] -> [a] -> Gen [a]
f [] [Natural
Item [Natural]
1..forall (n :: Natural). KnownNat n => Natural
value @n]

fromPermutation :: Permutation n -> [Natural]
fromPermutation :: forall (n :: Natural). Permutation n -> [Natural]
fromPermutation (Permutation Vector n Natural
perm) = Vector n Natural -> [Natural]
forall (size :: Natural) a. Vector size a -> [a]
fromVector Vector n Natural
perm

applyPermutation :: Permutation n -> Vector n a -> Vector n a
applyPermutation :: forall (n :: Natural) a. Permutation n -> Vector n a -> Vector n a
applyPermutation (Permutation (Vector [Natural]
ps)) (Vector [a]
as) = [a] -> Vector n a
forall (size :: Natural) a. [a] -> Vector size a
Vector ([a] -> Vector n a) -> [a] -> Vector n a
forall a b. (a -> b) -> a -> b
$ (Natural -> a) -> [Natural] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map ([a]
as [a] -> Natural -> a
forall a. [a] -> Natural -> a
!!) [Natural]
ps

applyCycle :: IndexSet -> Permutation n -> Permutation n
applyCycle :: forall (n :: Natural).
Vector Natural -> Permutation n -> Permutation n
applyCycle Vector Natural
c (Permutation Vector n Natural
perm) = Vector n Natural -> Permutation n
forall (n :: Natural). Vector n Natural -> Permutation n
Permutation (Vector n Natural -> Permutation n)
-> Vector n Natural -> Permutation n
forall a b. (a -> b) -> a -> b
$ (Natural -> Natural) -> Vector n Natural -> Vector n Natural
forall a b. (a -> b) -> Vector n a -> Vector n b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap Natural -> Natural
f Vector n Natural
perm
    where
        f :: Natural -> Natural
        f :: Natural -> Natural
f Natural
i = case Natural
i Natural -> Vector Natural -> Maybe Int
forall a. Eq a => a -> Vector a -> Maybe Int
`V.elemIndex` Vector Natural
c of
            Just Int
j  -> Vector Natural
c Vector Natural -> Int -> Natural
forall a. Vector a -> Int -> a
V.! ((Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
P.+ Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`P.mod` Vector Natural -> Int
forall a. Vector a -> Int
V.length Vector Natural
c)
            Maybe Int
Nothing -> Natural
i

fromCycles :: KnownNat n => IndexPartition a -> Permutation n
fromCycles :: forall (n :: Natural) a.
KnownNat n =>
IndexPartition a -> Permutation n
fromCycles IndexPartition a
p =
    let n :: Natural
n = Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Natural) -> Int -> Natural
forall a b. (a -> b) -> a -> b
$ Vector Natural -> Int
forall a. Vector a -> Int
V.length (Vector Natural -> Int) -> Vector Natural -> Int
forall a b. (a -> b) -> a -> b
$ [Vector Natural] -> Vector Natural
forall a. [Vector a] -> Vector a
V.concat ([Vector Natural] -> Vector Natural)
-> [Vector Natural] -> Vector Natural
forall a b. (a -> b) -> a -> b
$ IndexPartition a -> [Vector Natural]
forall k a. Map k a -> [a]
elems IndexPartition a
p
    in (Vector Natural -> Permutation n -> Permutation n)
-> Permutation n -> [Vector Natural] -> Permutation n
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: Type -> Type) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Vector Natural -> Permutation n -> Permutation n
forall (n :: Natural).
Vector Natural -> Permutation n -> Permutation n
applyCycle (Vector n Natural -> Permutation n
forall (n :: Natural). Vector n Natural -> Permutation n
Permutation (Vector n Natural -> Permutation n)
-> Vector n Natural -> Permutation n
forall a b. (a -> b) -> a -> b
$ Maybe (Vector n Natural) -> Vector n Natural
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe (Vector n Natural) -> Vector n Natural)
-> Maybe (Vector n Natural) -> Vector n Natural
forall a b. (a -> b) -> a -> b
$ [Natural] -> Maybe (Vector n Natural)
forall (size :: Natural) a.
KnownNat size =>
[a] -> Maybe (Vector size a)
toVector [Natural
Item [Natural]
1 .. Natural
Item [Natural]
n]) ([Vector Natural] -> Permutation n)
-> [Vector Natural] -> Permutation n
forall a b. (a -> b) -> a -> b
$ IndexPartition a -> [Vector Natural]
forall k a. Map k a -> [a]
elems IndexPartition a
p