{-# OPTIONS_HADDOCK show-extensions #-}
-- |
-- Module : Phladiprelio.ConstraintsEncoded
-- Copyright : (c) OleksandrZhabenko 2020-2023
-- License : MIT
-- Stability : Experimental
-- Maintainer : oleksandr.zhabenko@yahoo.com
--
-- Provides a way to encode the needed constraint with possibly less symbols.
-- Uses arrays instead of vectors.
{-# LANGUAGE FlexibleInstances, FlexibleContexts, NoImplicitPrelude #-}
module Phladiprelio.ConstraintsEncoded (
-- * Data types
EncodedContraints(..)
, EncodedCnstrs
-- * Functions to work with them
-- ** Read functions
, readMaybeECG
-- ** Process-encoding functions
, decodeConstraint1
, decodeLConstraints
-- ** Modifiers and getters
, getIEl
, setIEl
-- ** Predicates
, isE
, isP
, isF
, isQ
, isT
, isSA
, isSB
, isV
, isW
, isH
, isR
, isM
) where
import GHC.Base
import GHC.List
import GHC.Num ((-),abs)
import Text.Show (show)
import Text.Read (readMaybe)
import Data.Maybe
import Data.List (nub)
import GHC.Arr
import Phladiprelio.Constraints
import Data.SubG (InsertLeft(..))
data EncodedContraints a b = E
| P a b
| Q a a a a a
| T a a a a
| SA a a b
| SB a a b
| F a a a
| V a a a
| W a a a
| H a a a a
| R a a a a
| M a a a a
deriving (Eq, Ord)
-- | Inspired by the: https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Maybe.html
-- Is provided here as a more general way to read the 'String' into a 'EncodedCnstrs'.
-- It is up to user to check whether the parameters are in the correct form, the function does
-- not do the full checking.
readMaybeECG :: Int -> String -> Maybe EncodedCnstrs
readMaybeECG n xs
| null xs = Nothing
| n >=0 && n <= 9 =
let h = head xs
ts = filter (\x -> x >= '0' && [x] <= show n) . tail $ xs in
case h of
'E' -> Just E
_ -> f n h ts
| otherwise = Nothing
where f n c ts
| c `elem` "HFMRQTVW" = let ys = nub . catMaybes . map (\t -> readMaybe [t]::Maybe Int) $ ts
res
| length ys /= g c = Nothing
| c == 'Q' = let [y,z,u,w] = map (\rr -> if rr == 0 then 9 else rr - 1) ys in Just (Q n y z u w)
| c `elem` "FVW" = let [y,z] = map (\rr -> if rr == 0 then 9 else rr - 1) ys in Just ((case c of {'F' -> F; 'V'-> V; ~ww -> W}) n y z)
| otherwise = let [y,z,u] = map (\rr -> if rr == 0 then 9 else rr - 1) ys in Just ((case c of {'T' -> T; 'H' -> H; 'M' -> M; ~rr -> R}) n y z u) in res
| c `elem` "AB" = let y = readMaybe (take 1 ts)::Maybe Int in
if isJust y then
let y0 = fromJust y
zs = map (\rr -> if rr == 0 then 9 else rr - 1) . filter (/= y0) . nub . catMaybes . map (\t -> readMaybe [t]::Maybe Int) . drop 1 $ ts in
case zs of
[] -> Nothing
~x2 -> Just ((if c == 'A' then SA else SB) n (if y0 == 0 then 9 else y0 - 1) (listArray (0,length x2 - 1) x2))
else Nothing
| c == 'P' = if null ts then Just E else Just . P n . listArray (0,length ts - 1) . map (\r -> case (fromJust (readMaybe [r]::Maybe Int)) of {0 -> 9; n -> n-1}) $ ts
| otherwise = Nothing
g c
| c `elem` "FVW" = 2
| c == 'Q' = 4
| otherwise = 3
type EncodedCnstrs = EncodedContraints Int (Array Int Int)
-- | Must be applied to the correct array of permutation indeces. Otherwise, it gives runtime error (exception). All the integers inside the
-- 'EncodedCnstrs' must be in the range [0..n] where @n@ corresponds to the maximum element in the permutation 'Array' 'Int' 'Int'. Besides,
-- @n@ is (probably must be) not greater than 6.
decodeConstraint1 :: (InsertLeft t (Array Int Int), Monoid (t (Array Int Int))) => EncodedCnstrs -> t (Array Int Int) -> t (Array Int Int)
decodeConstraint1 E = id
decodeConstraint1 (P _ v) = fixedPointsS v
decodeConstraint1 (Q _ i j k l) = unsafeQuadruples i j k l
decodeConstraint1 (T _ i j k) = unsafeTriples i j k
decodeConstraint1 (SA _ i v) = unsafeSeveralA i v
decodeConstraint1 (SB _ i v) = unsafeSeveralB i v
decodeConstraint1 (F _ i j) = filterOrderIJ i j
decodeConstraint1 (V _ i j) = filterSignDistanceIJ i j (j - i)
decodeConstraint1 (W _ i j) = filterUnsignDistanceIJ i j (abs $ j - i)
decodeConstraint1 (H _ i j k) = filterSignDistanceIJK3 i j k (j - i) (k - j)
decodeConstraint1 (R _ i j k) = filterUnsignDistanceIJK3 i j k (abs (j - i)) (abs (k - j))
decodeConstraint1 (M _ i j k) = filterMixedDistanceIJK3 i j k (j - i) (abs (k - j))
-- | Must be applied to the correct array of permutation indeces. Otherwise, it gives runtime error (exception). All the integers inside the
-- 'EncodedCnstrs' must be in the range [0..n] where @n@ corresponds to the maximum element in the permutation 'Array' 'Int' 'Int'. Besides,
-- @n@ is (probably must be) not greater than 6.
decodeLConstraints :: (InsertLeft t (Array Int Int), Monoid (t (Array Int Int))) => [EncodedCnstrs] -> t (Array Int Int) -> t (Array Int Int)
decodeLConstraints (x:xs) = decodeLConstraints' ys . decodeConstraint1 y
where y = minimum (x:xs)
ys = filter (/= y) . g $ (x:xs)
g (E:zs) = g zs
g (z:zs) = z : g zs
g _ = []
decodeLConstraints' (z:zs) = decodeLConstraints' zs . decodeConstraint1 z
decodeLConstraints' _ = id
decodeLConstraints _ = id
isE :: EncodedCnstrs -> Bool
isE E = True
isE _ = False
isP :: EncodedCnstrs -> Bool
isP (P _ _) = True
isP _ = False
isF :: EncodedCnstrs -> Bool
isF (F _ _ _) = True
isF _ = False
isT :: EncodedCnstrs -> Bool
isT (T _ _ _ _) = True
isT _ = False
isQ :: EncodedCnstrs -> Bool
isQ (Q _ _ _ _ _) = True
isQ _ = False
isSA :: EncodedCnstrs -> Bool
isSA (SA _ _ _) = True
isSA _ = False
isSB :: EncodedCnstrs -> Bool
isSB (SB _ _ _) = True
isSB _ = False
isV :: EncodedCnstrs -> Bool
isV (V _ _ _) = True
isV _ = False
isW :: EncodedCnstrs -> Bool
isW (W _ _ _) = True
isW _ = False
isH :: EncodedCnstrs -> Bool
isH (H _ _ _ _) = True
isH _ = False
isR :: EncodedCnstrs -> Bool
isR (R _ _ _ _) = True
isR _ = False
isM :: EncodedCnstrs -> Bool
isM (M _ _ _ _) = True
isM _ = False
{-| Works only with the correctly defined argument though it is not checked. Use with this caution.
-}
getIEl :: EncodedCnstrs -> Int
getIEl E = -1
getIEl (P _ arr) = unsafeAt arr 0
getIEl (Q _ i _ _ _) = i
getIEl (T _ i _ _) = i
getIEl (SA _ i _) = i
getIEl (SB _ i _) = i
getIEl (F _ i _) = i
getIEl (V _ i _) = i
getIEl (W _ i _) = i
getIEl (H _ i _ _) = i
getIEl (R _ i _ _) = i
getIEl (M _ i _ _) = i
{-| Works only with the correctly defined arguments though it is not checked. Use with this caution.
-}
setIEl :: Int -> EncodedCnstrs -> EncodedCnstrs
setIEl _ E = E
setIEl i (P n arr) = P n (arr // [(0,i)])
setIEl i (Q n _ j k l) = Q n i j k l
setIEl i (T n _ j k) = T n i j k
setIEl i (SA n _ v) = SA n i v
setIEl i (SB n _ v) = SB n i v
setIEl i (F n _ j) = F n i j
setIEl i (V n _ j) = V n i j
setIEl i (W n _ j) = W n i j
setIEl i (H n _ j k) = H n i j k
setIEl i (R n _ j k) = R n i j k
setIEl i (M n _ j k) = M n i j k