packages feed

tensort-1.1.0.0: src/Data/Tensort/Subalgorithms/Rotationsort.hs

-- | This module provides Rotationsort variants for sorting lists.
--
-- | I was having some issues with the swaps for larger input lists, so for now
--   these functions are only implemented for lists of length 3 or less.
module Data.Tensort.Subalgorithms.Rotationsort
  ( rotationsort,
    rotationsortAmbi,
    rotationsortReverse,
    rotationsortReverseAmbi,
  )
where

-- | Takes a list and returns a sorted list using a Rotationsort
--  algorithm.
--
--  I was having some issues with the swaps for larger input lists, so for now
--  this function is only implemented for lists of length 3 or less.

-- | ==== __Examples__
-- >>> rotationsort ([1,3,2] :: [Int])
-- [1,2,3]
--
-- >>> rotationsort ([(3, 1), (1, 3), (2, 2)] :: [(Int, Int)])
-- [(1,3),(2,2),(3,1)]
rotationsort :: (Ord a) => [a] -> [a]
rotationsort bits = rotationsort' bits 0 False False

-- | Takes a list and returns a sorted list using an Ambidextrous
--   Rotationsort algorithm.
--
--  I was having some issues with the swaps for larger input lists, so for now
--  this function is only implemented for lists of length 3 or less.

-- | ==== __Examples__
-- >>> rotationsortAmbi ([1,3,2] :: [Int])
-- [1,2,3]
--
-- >>> rotationsortAmbi ([(3, 1), (1, 3), (2, 2)] :: [(Int, Int)])
-- [(1,3),(2,2),(3,1)]
rotationsortAmbi :: (Ord a) => [a] -> [a]
rotationsortAmbi bits = rotationsort' bits 0 True False

-- | Takes a list and returns a sorted list using a Reverse
--   Rotationsort algorithm.
--
--   I was having some issues with the swaps for larger input lists, so for now
--   this function is only implemented for lists of length 3 or less.

-- | ==== __Examples__
-- >>> rotationsortReverse ([1,3,2] :: [Int])
-- [1,2,3]
--
-- >>> rotationsortReverse ([(3, 1), (1, 3), (2, 2)] :: [(Int, Int)])
-- [(1,3),(2,2),(3,1)]
rotationsortReverse :: (Ord a) => [a] -> [a]
rotationsortReverse bits = rotationsort' bits (length bits - 1) False True

-- | Takes a list and returns a sorted list using an Ambidextrous
--   Reverse Rotationsort algorithm.
--
--   I was having some issues with the swaps for larger input lists, so for now
--   this function is only implemented for lists of length 3 or less.

-- | ==== __Examples__
-- >>> rotationsortReverseAmbi ([1,3,2] :: [Int])
-- [1,2,3]
--
-- >>> rotationsortReverseAmbi ([(3, 1), (1, 3), (2, 2)] :: [(Int, Int)])
-- [(1,3),(2,2),(3,1)]
rotationsortReverseAmbi :: (Ord a) => [a] -> [a]
rotationsortReverseAmbi bits = rotationsort' bits (length bits - 1) True True

rotationsort' :: (Ord a) => [a] -> Int -> Bool -> Bool -> [a]
rotationsort' xs currentIndex isAmbi isReverse
  | length xs > 3 =
      error
        "From rotationsort': algorithm not yet implemented for lists of length greater than 3"
  | currentIndex < 0 || currentIndex >= length xs =
      xs
  | length xs < 2 = xs
  | length xs == 2 =
      rotatationsortPair xs currentIndex isAmbi isReverse
  | currentIndex == firstIndex (length xs) isReverse =
      rotationsortHead xs currentIndex isAmbi isReverse
  | currentIndex == lastIndex (length xs) isReverse =
      rotationsortLast xs currentIndex isAmbi isReverse
  | otherwise =
      rotationsortMiddle xs currentIndex isAmbi isReverse

rotatationsortPair :: (Ord a) => [a] -> Int -> Bool -> Bool -> [a]
rotatationsortPair xs currentIndex isAmbi isReverse
  | not secondElemGreater =
      rotationsort'
        swappedXs
        (firstIndex (length xs) isReverse)
        isAmbi
        isReverse
  | otherwise =
      rotationsort'
        xs
        (nextIndex currentIndex isReverse)
        isAmbi
        isReverse
  where
    x = head xs
    y = xs !! 1
    secondElemGreater = y >= x
    swappedXs = y : [x]

rotationsortHead :: (Ord a) => [a] -> Int -> Bool -> Bool -> [a]
rotationsortHead xs currentIndex isAmbi isReverse
  | not $ lastElemOrdered xs currentIndex isReverse =
      rotationsort'
        rotateToFirst
        (firstIndex (length xs) isReverse)
        isAmbi
        isReverse
  | not $ nextElemOrdered xs currentIndex isReverse =
      rotationsort'
        rotateBackward
        (firstIndex (length xs) isReverse)
        isAmbi
        isReverse
  | otherwise =
      rotationsort'
        xs
        (nextIndex currentIndex isReverse)
        isAmbi
        isReverse
  where
    w = xs !! lastIndex (length xs) isReverse
    x = xs !! currentIndex
    y = xs !! nextIndex currentIndex isReverse
    rotateToFirst =
      if isReverse then [y] ++ [x] ++ [w] else [w] ++ [x] ++ [y]
    rotateBackward =
      if isReverse then [w] ++ [x] ++ [y] else [y] ++ [x] ++ [w]

rotationsortMiddle :: (Ord a) => [a] -> Int -> Bool -> Bool -> [a]
rotationsortMiddle xs currentIndex isAmbi isReverse
  | not $ nextElemOrdered xs currentIndex isReverse =
      rotationsort'
        rotateBackward
        (firstIndex (length xs) isReverse)
        isAmbi
        isReverse
  | not isAmbi =
      rotationsort'
        xs
        (nextIndex currentIndex isReverse)
        isAmbi
        isReverse
  | not $ prevElemOrdered xs currentIndex isReverse =
      rotationsort'
        rotateForward
        (prevIndex currentIndex isReverse)
        isAmbi
        isReverse
  | otherwise =
      rotationsort'
        xs
        (nextIndex currentIndex isReverse)
        isAmbi
        isReverse
  where
    w = xs !! prevIndex currentIndex isReverse
    x = xs !! currentIndex
    y = xs !! nextIndex currentIndex isReverse
    rotateBackward =
      if isReverse then [x] ++ [y] ++ [w] else [y] ++ [w] ++ [x]
    rotateForward =
      if isReverse then [y] ++ [w] ++ [x] else [x] ++ [y] ++ [w]

rotationsortLast ::
  (Ord a) => [a] -> Int -> Bool -> Bool -> [a]
rotationsortLast xs currentIndex isAmbi isReverse
  | not isAmbi =
      rotationsort'
        xs
        (nextIndex currentIndex isReverse)
        isAmbi
        isReverse
  | not $ firstElemOrdered xs currentIndex isReverse =
      rotationsort'
        rotateToLast
        (prevIndex currentIndex isReverse)
        isAmbi
        isReverse
  | not $ prevElemOrdered xs currentIndex isReverse =
      rotationsort'
        rotateForward
        (prevIndex currentIndex isReverse)
        isAmbi
        isReverse
  | otherwise =
      rotationsort'
        xs
        (nextIndex currentIndex isReverse)
        isAmbi
        isReverse
  where
    w = xs !! prevIndex currentIndex isReverse
    x = xs !! currentIndex
    y = xs !! firstIndex (length xs) isReverse
    rotateForward =
      if isReverse then [w] ++ [x] ++ [y] else [y] ++ [x] ++ [w]
    rotateToLast =
      if isReverse then [y] ++ [x] ++ [w] else [w] ++ [x] ++ [y]

nextIndex :: Int -> Bool -> Int
nextIndex currentIndex isReverse
  | isReverse = currentIndex - 1
  | otherwise = currentIndex + 1

prevIndex :: Int -> Bool -> Int
prevIndex currentIndex isReverse
  | isReverse = currentIndex + 1
  | otherwise = currentIndex - 1

lastIndex :: Int -> Bool -> Int
lastIndex listLength isReverse
  | isReverse = 0
  | otherwise = listLength - 1

firstIndex :: Int -> Bool -> Int
firstIndex listLength isReverse
  | isReverse = listLength - 1
  | otherwise = 0

nextElemOrdered :: (Ord a) => [a] -> Int -> Bool -> Bool
nextElemOrdered xs currentIndex isReverse = if isReverse then x >= y else y >= x
  where
    x = xs !! currentIndex
    y = xs !! nextIndex currentIndex isReverse

prevElemOrdered :: (Ord a) => [a] -> Int -> Bool -> Bool
prevElemOrdered xs currentIndex isReverse = if isReverse then w >= x else x >= w
  where
    x = xs !! currentIndex
    w = xs !! prevIndex currentIndex isReverse

firstElemOrdered :: (Ord a) => [a] -> Int -> Bool -> Bool
firstElemOrdered xs currentIndex isReverse = if isReverse then w >= x else x >= w
  where
    x = xs !! currentIndex
    w = xs !! firstIndex (length xs) isReverse

lastElemOrdered :: (Ord a) => [a] -> Int -> Bool -> Bool
lastElemOrdered xs currentIndex isReverse = if isReverse then x >= y else y >= x
  where
    x = xs !! currentIndex
    y = xs !! lastIndex (length xs) isReverse