packages feed

aftovolio-0.5.0.0: Aftovolio/ConstraintsEncoded.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_HADDOCK show-extensions #-}

{- |
Module      :  Aftovolio.ConstraintsEncoded
Copyright   :  (c) OleksandrZhabenko 2020-2024
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.
-}
module Aftovolio.ConstraintsEncoded (
    -- * Data types
    EncodedContraints (..),
    EncodedCnstrs,

    -- * Functions to work with them

    -- ** Read functions
    readMaybeECG,

    -- ** Process-encoding functions
    decodeConstraint1,
    decodeLConstraints,
    isConstraint1,

    -- ** Modifiers and getters
    getIEl,
    setIEl,

    -- ** Predicates
    isE,
    isP,
    isF,
    isQ,
    isT,
    isSA,
    isSB,
    isV,
    isW,
    isH,
    isR,
    isM,
    isN,
    isD,
    isI,
    isU,
    isG,

    -- * Algebraic general conversion
    validOrdStr,
    generalConversion,
    filterGeneralConv,
) where

import Aftovolio.Constraints
import Data.Char (isDigit, isLetter)
import Data.InsertLeft (InsertLeft (..), splitAtEndG)
import Data.List (groupBy, nub, words)
import Data.Maybe
import Data.Tuple (fst)
import GHC.Arr
import GHC.Base
import GHC.List
import GHC.Num (abs, (+), (-))
import Text.Read (readMaybe)
import Text.Show (Show (..), show)

data EncodedContraints a b d
    = -- | Represents no additional constraint, corresponds to the whole set of theoretically possible permutations.
      E
    | -- | Represents the set of permutations with the fixed positions of some elements.
      P a b
    | -- | Represents the set of permutations with the preserved pairwise order between first and second, second and third, third and fourth elements.
      Q a a a a a
    | -- | Represents the set of permutations with the preserved pairwise order between first and second, second and third elements.
      T a a a a
    | -- | Represents the set of permutations with the preserved position of the elements AFTER the another selected one.
      SA a a b
    | -- | Represents the set of permutations with the preserved position of the elements BEFORE the another selected one.
      SB a a b
    | -- | Represents the set of permutations with the preserved order between first and second elements.
      F a a a
    | -- | Represents the set of permutations with the preserved both distance between and order of the two elements.
      V a a a
    | -- | Represents the set of permutations with the preserved distance between the two elements.
      W a a a
    | -- | Represents the set of permutations with the preserved both distances between and order of the three elements.
      H a a a a
    | -- | Represents the set of permutations with the preserved pairwise distances between the first and second, second and third elements.
      R a a a a
    | -- | Represents the set of permutations with the preserved pairwise distances between the first and second, second and third elements, and additionally the order of the first and second elements.
      M a a a a
    | -- | Represents the set of permutations with the moved fixed positions of some elements (at least one).
      N a d
    | -- | Pepresents the set of permutations with the specified order and distance between the two elements.
      D a a a a
    | -- | Pepresents the set of permutations with the specified distance between the two elements.
      I a a a a
    | -- | Represents the set of permutations with the preserved order of the 5 elements
      U a a a a a a
    | -- | Represents the set of permutations with the groupped more than two elements together
      G a a a
    deriving (Eq, Ord, Show)

validOrdStr0 ::
    String ->
    -- | Number of seen so far \'(\' parentheses
    Int ->
    -- | Number of seen so far \')\' parentheses
    Int ->
    Bool
validOrdStr0 ('E' : ys) n m = validOrdStr0 ys n m
validOrdStr0 (' ' : y : t : ys) n m
    | y `elem` "ABDFGHIMNPQRTUVW" && isDigit t =
        validOrdStr0 (dropWhile isDigit ys) n m
    | y `elem` "-(E" = validOrdStr0 (y : t : ys) n m
    | otherwise = False
validOrdStr0 ('(' : y : t : ys) n m
    | y `elem` "ABDFGHIMNPQRTUVW" && isDigit t =
        validOrdStr0 (dropWhile isDigit ys) (n + 1) m
    | y `elem` "-(E" = validOrdStr0 (y : t : ys) (n + 1) m
    | otherwise = False
validOrdStr0 (')' : y : t : ys) n m
    | y `elem` "ABDFGHIMNPQRTUVW" && isDigit t =
        validOrdStr0 (dropWhile isDigit ys) n (m + 1)
    | y `elem` "-()E" = validOrdStr0 (y : t : ys) n (m + 1)
    | otherwise = False
validOrdStr0 ('-' : y : t : ys) n m
    | y `elem` "ABDFGHIMNPQRTUVW" && isDigit t =
        validOrdStr0 (dropWhile isDigit ys) n m
    | y `elem` "-)" || isDigit y = False
    | otherwise = validOrdStr0 (y : t : ys) n m
validOrdStr0 (x : y : t : ys) n m
    | x `elem` "ABDFGHIMNPQRTUVW" && isDigit y =
        validOrdStr0 (dropWhile isDigit (t : ys)) n m
    | x `elem` "ABDFGHIMNPQRTUVW" = False
    | otherwise = validOrdStr0 (y : t : ys) n (m + 1)
validOrdStr0 (x : ')' : ys) n m
    | isDigit x = validOrdStr0 ys n (m + 1)
    | x == ')' = validOrdStr0 ys n (m + 2)
    | otherwise = False
validOrdStr0 (x : y : _) n m
    | x `elem` "(ABDFGHIMNQRTUVW" = False
    | y `elem` " -(ABDFGHIMNPQRTUVW" = False
    | x == 'P' && not (isDigit y) = False
    | x == ')' && y /= 'E' = False
    | x == 'P' && n == m = True
    | x == ')' && y == 'E' = n == (m + 1)
    | (x `elem` "E -") && y == 'E' = n == m
    | otherwise = False
validOrdStr0 (x : _) n m
    | isDigit x || (x `elem` ")E") = if x == ')' then n == (m + 1) else n == m
    | otherwise = False
validOrdStr0 _ n m = n == m

{- | An extended predicate to check whether the 'String' is a probably correct representation of the
constraints algebraic expression for 'generalConversion' evaluation.
-}
validOrdStr :: String -> Bool
validOrdStr xs = validOrdStr0 xs 0 0
{-# INLINE validOrdStr #-}

stage1Parsing :: String -> [String]
stage1Parsing =
    groupBy
        ( \x y -> x == '(' && y == '(' || isLetter x && isDigit y || x == ')' && y == ')'
        )
{-# INLINE stage1Parsing #-}

-- | At the moment is used only for the list of 'String' without any parentheses in each of them.
convertToBools ::
    Int ->
    Array Int Int ->
    [String] ->
    -- | The result is a 'String' that Haskell can evaluate to 'Bool' (some logical expression).
    String
convertToBools n arr ("-" : yss) = "not " `mappend` (convertToBools n arr yss)
convertToBools n arr (" " : yss) = " || " `mappend` (convertToBools n arr yss)
convertToBools n arr (xs : yss@(ys : _))
    | xs `elem` ["True", "False"] =
        xs
            `mappend` ( case ys of
                            " " -> " "
                            _ -> " && "
                      )
            `mappend` convertToBools n arr yss
    | otherwise =
        let cnstrs = fromMaybe E . readMaybeECG n $ xs
         in show (isConstraint1 True arr cnstrs)
                `mappend` ( case ys of
                                " " -> " "
                                _ -> " && "
                          )
                `mappend` convertToBools n arr yss
convertToBools n arr (xs : _)
    | xs `elem` ["True", "False"] = xs
    | otherwise =
        (show . isConstraint1 True arr . fromMaybe E . readMaybeECG n $ xs)
convertToBools _ _ _ = []

splitNoParenAtDisjunction :: [String] -> [[String]]
splitNoParenAtDisjunction xss@(_ : _)
    | null tss = []
    | otherwise = tss : splitNoParenAtDisjunction wss
  where
    (tss, uss) = break (== "||") xss
    wss = drop 1 uss
splitNoParenAtDisjunction _ = []

noParenString0 :: [String] -> Bool
noParenString0 (xs : ys : ts : yss)
    | xs == "not" =
        case ys of
            "True" -> False
            _ -> noParenString0 yss
    | otherwise =
        case xs of
            "True" -> noParenString0 (ts : yss)
            _ -> False
noParenString0 ("not" : ys : _) = if ys == "True" then False else True
noParenString0 (xs : _)
    | xs == "True" = True
    | otherwise = False
noParenString0 _ = True

noParenString :: [String] -> Bool
noParenString = or . map noParenString0 . splitNoParenAtDisjunction
{-# INLINE noParenString #-}

oneStep :: Int -> Array Int Int -> [String] -> Bool
oneStep m arr = noParenString . words . convertToBools m arr
{-# INLINE oneStep #-}

oneChange :: Int -> Array Int Int -> [String] -> [String]
oneChange m arr xss
    | null wss = [show . oneStep m arr $ xss]
    | otherwise =
        ( (\(jss, _, qss) -> jss `mappend` [show . oneStep m arr $ qss])
            . foldr
                ( \xs (tss, n, rss) ->
                    if xs == "(" && n == 0
                        then (tss, 1, rss)
                        else
                            if any (== '(') xs && n == 0
                                then (drop 1 xs : tss, 1, rss)
                                else case n of
                                    0 -> (tss, 0, xs : rss)
                                    _ -> (xs : tss, 1, rss)
                )
                ([], 0, [])
            $ yss
        )
            `mappend` kss
  where
    (yss, wss) = break (any (== ')')) xss
    kss = case wss of
        ")" : vss -> vss
        ws : vss -> drop 1 ws : vss
        _ -> []

generalConversion :: Int -> String -> Array Int Int -> Bool
generalConversion m xs arr
    | validOrdStr xs =
        (\ks -> if ks == "True" || ks == "E" then True else False)
            . head
            . head
            . dropWhile ((/= 1) . length)
            . drop 1
            . iterate (oneChange m arr)
            . stage1Parsing
            $ xs
    | otherwise = False
{-# INLINE generalConversion #-}

-- | Can be thought of as 'filter' ('generalConversion' ... ) @<arrays>@ but is somewhat more efficient.
filterGeneralConv :: Int -> String -> [Array Int Int] -> [Array Int Int]
filterGeneralConv m cnstrns xs
    | validOrdStr cnstrns =
        let !xss = stage1Parsing cnstrns
         in filter
                ( \arr ->
                    (\ks -> if ks == "True" || ks == "E" then True else False)
                        . head
                        . head
                        . dropWhile ((/= 1) . length)
                        . drop 1
                        . iterate (oneChange m arr) $
                        xss
                )
                xs
    | otherwise = []
{-# INLINE filterGeneralConv #-}

{- | 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` "DFGHIMQRQTUVW" =
            let ys0 = catMaybes . map (\t -> readMaybe [t] :: Maybe Int) $ ts
                ys = nub ys0
                (jjs, ps) = splitAtEndG 1 ys0
                res
                    | length ys0 >= 3 && (c `elem` "DI") =
                        let qs = take 2 . nub $ jjs
                            [y, z] = map (\rr -> if rr == 0 then 9 else rr - 1) qs
                         in if length qs /= 2 || ps == [0] || ps > [n]
                                then Nothing
                                else Just ((if c == 'D' then D else I) n y z (head ps))
                    | length ys /= g c = Nothing
                   | 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; _ -> W) n y z)
                    | c `elem` "HMT" =
                        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; _ -> R) n y z u)
                    | c == 'G' =
                        let [y0, z0] = map (\rr -> if rr == 0 then 9 else rr - 1) ys
                            (y, z) 
                                 | y0 < z0 = (y0, z0)
                                 | otherwise = (z0, y0) 
                         in Just (G n y z)
                    | 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 == 'U' =
                        let [y, z, t, u, w] = map (\rr -> if rr == 0 then 9 else rr - 1) ys
                         in Just (U n y z t u w)
                    | otherwise = Nothing
             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; q -> q - 1) $
                        ts
        | c == 'N' =
            if tl == 0
                then Just E
                else
                    Just
                        . N n
                        . listArray (0, tl - 1)
                        . map
                            ( (\[s, w] -> (w, s))
                                . map (\r -> case (fromJust (readMaybe [r] :: Maybe Int)) of 0 -> 9; q -> q - 1)
                            ) $
                        h3
        | otherwise = Nothing
      where
        h1 (b : d : ds) = [b, d] : h1 ds
        h1 _ = []
        h2 = h1 ts
        qqs = map head h2
        pps = map last h2
        h3
            | length (nub qqs) == length qqs && length (nub pps) == length pps = h2
            | otherwise = []
        tl = length h3
    g c
        | c `elem` "FGVW" = 2
        | c == 'Q' = 4
        | c == 'U' = 5
        | otherwise = 3

type EncodedCnstrs =
    EncodedContraints Int (Array Int Int) (Array Int (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-1] where @n@ corresponds to the maximum element in the permutation 'Array' 'Int' 'Int'.
-}
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 (abs $ j - i)
decodeConstraint1 (W _ i j) = filterUnsignDistanceIJ i j (abs $ j - i)
decodeConstraint1 (H _ i j k) = filterSignDistanceIJK3 i j k (abs $ j - i) (abs $ 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 (abs $ j - i) (abs $ k - j)
decodeConstraint1 (N _ v) = fixedPointsG v
decodeConstraint1 (D _ i j d) = filterSignDistanceIJ i j (abs d)
decodeConstraint1 (I _ i j d) = filterUnsignDistanceIJ i j (abs d)
decodeConstraint1 (U _ i j k l m) = unsafeQuintuples i j k l m
decodeConstraint1 (G _ i j) = filterGrouppedTogether i j
{-# SPECIALIZE decodeConstraint1 ::
    EncodedCnstrs -> [Array Int 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-1] where @n@ corresponds to the maximum element in the permutation 'Array' 'Int' 'Int'.
-}
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
{-# SPECIALIZE decodeLConstraints ::
    [EncodedCnstrs] -> [Array Int Int] -> [Array Int Int]
    #-}

isConstraint1 :: Bool -> Array Int Int -> EncodedCnstrs -> Bool
isConstraint1 bool _ E = bool
isConstraint1 True arr (F _ i j) = unsafeOrderIJ i j arr
isConstraint1 True arr (T _ i j k) = isTripleOrdered i j k arr
isConstraint1 True arr (Q _ i j k l) = isQuadrupleOrdered i j k l arr
isConstraint1 True arr (SA _ i arr2) = isSeveralAOrdered i arr2 arr
isConstraint1 True arr (SB _ i arr2) = isSeveralBOrdered i arr2 arr
isConstraint1 True arr (P _ arr2) = isFixedPoint arr2 arr
isConstraint1 True arr (H _ i j k) = isSignDistIJK3 i j k (abs $ j - i) (abs $ k - j) arr
isConstraint1 True arr (M _ i j k) = isMixedDistIJK3 i j k (abs $ j - i) (abs $ k - j) arr
isConstraint1 True arr (R _ i j k) = isUnsignDistIJK3 i j k (abs $ j - i) (abs $ k - j) arr
isConstraint1 True arr (V _ i j) = unsafeSignDistanceIJ i j (abs $ j - i) arr
isConstraint1 True arr (W _ i j) = unsafeUnsignDistanceIJ i j (abs $ j - i) arr
isConstraint1 True arr (N _ arr2) = isFixedPointTup arr2 arr
isConstraint1 True arr (D _ i j d) = unsafeSignDistanceIJ i j (abs d) arr
isConstraint1 True arr (I _ i j d) = unsafeUnsignDistanceIJ i j (abs d) arr
isConstraint1 True arr (U _ i j k l m) = isQuintupleOrdered i j k l m arr
isConstraint1 True arr (G _ i j) = isGrouppedTogether i j arr
isConstraint1 False arr (F _ i j) = unsafeOrderIJ j i arr
isConstraint1 False arr (T _ i j k) = notTripleOrdered i j k arr
isConstraint1 False arr (Q _ i j k l) = notQuadrupleOrdered i j k l arr
isConstraint1 False arr (SA _ i arr2) = notSeveralAOrdered i arr2 arr
isConstraint1 False arr (SB _ i arr2) = notSeveralBOrdered i arr2 arr
isConstraint1 False arr (P _ arr2) = notFixedPoint arr2 arr
isConstraint1 False arr (H _ i j k) = notSignDistIJK3 i j k (abs $ j - i) (abs $ k - j) arr
isConstraint1 False arr (M _ i j k) = notMixedDistIJK3 i j k (abs $ j - i) (abs $ k - j) arr
isConstraint1 False arr (R _ i j k) = notUnsignDistIJK3 i j k (abs $ j - i) (abs $ k - j) arr
isConstraint1 False arr (V _ i j) = unsafeSignDistanceIJ j i (abs $ j - i) arr
isConstraint1 False arr (W _ i j) = not . unsafeUnsignDistanceIJ i j (abs $ j - i) $ arr
isConstraint1 False arr (N _ arr2) = notFixedPointTup arr2 arr
isConstraint1 False arr (D _ i j d) = unsafeSignDistanceIJ j i (abs d) arr
isConstraint1 False arr (I _ i j d) = not . unsafeUnsignDistanceIJ i j (abs d) $ arr
isConstraint1 False arr (U _ i j k l m) = notQuintupleOrdered i j k l m arr
isConstraint1 False arr (G _ i j) = notGrouppedTogether i j arr

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

isN :: EncodedCnstrs -> Bool
isN (N _ _) = True
isN _ = False

isD :: EncodedCnstrs -> Bool
isD (D _ _ _ _) = True
isD _ = False

isI :: EncodedCnstrs -> Bool
isI (I _ _ _ _) = True
isI _ = False

isU :: EncodedCnstrs -> Bool
isU (U _ _ _ _ _ _) = True
isU _ = False

isG :: EncodedCnstrs -> Bool
isG (G _ _ _) = True
isG _ = 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
getIEl (N _ arr) = fst . unsafeAt arr $ 0
getIEl (D _ i _ _) = i
getIEl (I _ i _ _) = i
getIEl (U _ i _ _ _ _) = i
getIEl (G _ 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
setIEl _ (N n arr) = N n arr
setIEl i (D n _ j k) = D n i j k
setIEl i (I n _ j k) = I n i j k
setIEl i (U n _ j k l m) = U n i j k l m
setIEl i (G n _ j) = G n i j