move moveable utility functions to utility file
This commit is contained in:
parent
7d6d8bf23d
commit
1155905be3
@ -52,6 +52,7 @@ library
|
|||||||
, HushGP.Instructions.VectorStringInstructions
|
, HushGP.Instructions.VectorStringInstructions
|
||||||
, HushGP.Instructions.VectorBoolInstructions
|
, HushGP.Instructions.VectorBoolInstructions
|
||||||
, HushGP.Instructions.VectorCharInstructions
|
, HushGP.Instructions.VectorCharInstructions
|
||||||
|
, HushGP.Instructions.Utility
|
||||||
, HushGP.PushTests
|
, HushGP.PushTests
|
||||||
, HushGP.PushTests.IntTests
|
, HushGP.PushTests.IntTests
|
||||||
, HushGP.PushTests.GenericTests
|
, HushGP.PushTests.GenericTests
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@ module HushGP.Instructions.BoolInstructions where
|
|||||||
|
|
||||||
import HushGP.State
|
import HushGP.State
|
||||||
import HushGP.Instructions.GenericInstructions
|
import HushGP.Instructions.GenericInstructions
|
||||||
|
import HushGP.Instructions.Utility
|
||||||
|
|
||||||
-- |If top of int stack /= 0 pushes True to bool stack, else false.
|
-- |If top of int stack /= 0 pushes True to bool stack, else false.
|
||||||
instructionBoolFromInt :: State -> State
|
instructionBoolFromInt :: State -> State
|
||||||
@ -12,12 +13,6 @@ instructionBoolFromInt state = state
|
|||||||
instructionBoolFromFloat :: State -> State
|
instructionBoolFromFloat :: State -> State
|
||||||
instructionBoolFromFloat state@(State {_float = f1 : fs, _bool = bs}) = state {_float = fs, _bool = (f1 /= 0) : bs}
|
instructionBoolFromFloat state@(State {_float = f1 : fs, _bool = bs}) = state {_float = fs, _bool = (f1 /= 0) : bs}
|
||||||
instructionBoolFromFloat state = state
|
instructionBoolFromFloat state = state
|
||||||
|
|
||||||
-- |A template function to make bool comparisons concise.
|
|
||||||
boolTemplate :: (Bool -> Bool -> Bool) -> State -> State
|
|
||||||
boolTemplate func state@(State {_bool = b1 : b2 : bs}) = state {_bool = func b1 b2 : bs}
|
|
||||||
boolTemplate _ state = state
|
|
||||||
|
|
||||||
-- |Takes the top two bools and Ands them.
|
-- |Takes the top two bools and Ands them.
|
||||||
instructionBoolAnd :: State -> State
|
instructionBoolAnd :: State -> State
|
||||||
instructionBoolAnd = boolTemplate (&&)
|
instructionBoolAnd = boolTemplate (&&)
|
||||||
@ -36,13 +31,6 @@ instructionBoolInvertSecondThenAnd state = state
|
|||||||
instructionBoolOr :: State -> State
|
instructionBoolOr :: State -> State
|
||||||
instructionBoolOr = boolTemplate (||)
|
instructionBoolOr = boolTemplate (||)
|
||||||
|
|
||||||
-- |Utility function. Haskell doesn't have its own xor operation.
|
|
||||||
xor :: Bool -> Bool -> Bool
|
|
||||||
xor b1 b2
|
|
||||||
| b1 && not b2 = True
|
|
||||||
| not b1 && b2 = True
|
|
||||||
| otherwise = False
|
|
||||||
|
|
||||||
-- |Takes the xor of the top two bools.
|
-- |Takes the xor of the top two bools.
|
||||||
instructionBoolXor :: State -> State
|
instructionBoolXor :: State -> State
|
||||||
instructionBoolXor = boolTemplate xor
|
instructionBoolXor = boolTemplate xor
|
||||||
|
@ -2,12 +2,8 @@ module HushGP.Instructions.CharInstructions where
|
|||||||
|
|
||||||
import Data.Char
|
import Data.Char
|
||||||
import HushGP.State
|
import HushGP.State
|
||||||
import HushGP.Instructions.StringInstructions (wschars)
|
|
||||||
import HushGP.Instructions.GenericInstructions
|
import HushGP.Instructions.GenericInstructions
|
||||||
|
import HushGP.Instructions.Utility
|
||||||
-- |Converts a whole number `mod` 128 to a char.
|
|
||||||
intToAscii :: Integral a => a -> Char
|
|
||||||
intToAscii val = chr (abs (fromIntegral val) `mod` 128)
|
|
||||||
|
|
||||||
-- |Combines the top two chars into a string and pushes the result to the string stack.
|
-- |Combines the top two chars into a string and pushes the result to the string stack.
|
||||||
instructionCharConcat :: State -> State
|
instructionCharConcat :: State -> State
|
||||||
|
@ -4,105 +4,9 @@ import Data.List (elemIndex)
|
|||||||
import HushGP.State
|
import HushGP.State
|
||||||
import HushGP.Instructions.GenericInstructions
|
import HushGP.Instructions.GenericInstructions
|
||||||
import HushGP.Instructions.IntInstructions
|
import HushGP.Instructions.IntInstructions
|
||||||
|
import HushGP.Instructions.Utility
|
||||||
-- import Debug.Trace
|
-- import Debug.Trace
|
||||||
|
|
||||||
-- |Utility function: Checks to see if a gene is a code block.
|
|
||||||
-- If it is a block, returns true, else returns false
|
|
||||||
isBlock :: Gene -> Bool
|
|
||||||
isBlock (Block _) = True
|
|
||||||
isBlock _ = False
|
|
||||||
|
|
||||||
-- |Utility function: Returns the length of the passed block.
|
|
||||||
-- If the gene isn't a block, returns 1
|
|
||||||
blockLength :: Gene -> Int
|
|
||||||
blockLength (Block bxs) = length bxs
|
|
||||||
blockLength _ = 1
|
|
||||||
|
|
||||||
-- |Utility function: Returns true if the passed block is empty, false is not.
|
|
||||||
-- If the passed gene is not a block, returns false
|
|
||||||
blockIsNull :: Gene -> Bool
|
|
||||||
blockIsNull (Block bxs) = null bxs
|
|
||||||
blockIsNull _ = False
|
|
||||||
|
|
||||||
-- |Utility Function: A helper function for instructionCodeContainer. The full description is there.
|
|
||||||
-- https://faculty.hampshire.edu/lspector/push3-description.html#Type
|
|
||||||
-- CODE.CONTAINER
|
|
||||||
findContainer :: Gene -> Gene -> Gene
|
|
||||||
findContainer (Block fullA) gene
|
|
||||||
| length fullA <= blockLength gene = Block []
|
|
||||||
| gene `elem` fullA = Block [] -- Not allowed to be top level
|
|
||||||
| any isBlock fullA = findContainer' (filter isBlock fullA) gene
|
|
||||||
| otherwise = Block []
|
|
||||||
where
|
|
||||||
findContainer' :: [Gene] -> Gene -> Gene
|
|
||||||
findContainer' [] _ = Block []
|
|
||||||
findContainer' ((Block bx1) : bxs) g = if g `elem` bx1 then Block bx1 else findContainer' bxs g
|
|
||||||
findContainer' _ _ = Block [] -- This should never happen
|
|
||||||
findContainer _ _ = Block []
|
|
||||||
|
|
||||||
-- |Utility Function: A helper function for instructionCodeDiscrepancy. The full description is there.
|
|
||||||
countDiscrepancy :: Gene -> Gene -> Int
|
|
||||||
countDiscrepancy (Block xs) (Block ys) = sum [if uncurry (==) tup then 0 else 1 | tup <- zip xs ys] + abs (length xs - length ys)
|
|
||||||
countDiscrepancy xgene ygene = if xgene == ygene then 1 else 0
|
|
||||||
|
|
||||||
-- |Utility Function: Extracts the first gene from a block. Returns itself if not a block
|
|
||||||
extractFirstFromBlock :: Gene -> Gene
|
|
||||||
extractFirstFromBlock (Block (bx1 : _)) = bx1
|
|
||||||
extractFirstFromBlock gene = gene
|
|
||||||
|
|
||||||
-- |Utility Function: Returns the last gene from a block, [] if the block is empty, and itself if not a block
|
|
||||||
extractLastFromBlock :: Gene -> Gene
|
|
||||||
extractLastFromBlock (Block []) = Block []
|
|
||||||
extractLastFromBlock (Block bxs) = last bxs
|
|
||||||
extractLastFromBlock gene = gene
|
|
||||||
|
|
||||||
-- |Utility Function: Calls init on a block. If the block is empty, returns []. If gene isn't a block, returns itself
|
|
||||||
extractInitFromBlock :: Gene -> Gene
|
|
||||||
extractInitFromBlock (Block bxs) = Block (safeInit bxs)
|
|
||||||
extractInitFromBlock gene = gene
|
|
||||||
|
|
||||||
-- |Utility Function: Calls `drop 1` on a block. If gene isn't a block, returns itself
|
|
||||||
extractTailFromBlock :: Gene -> Gene
|
|
||||||
extractTailFromBlock (Block bxs) = Block (drop 1 bxs)
|
|
||||||
extractTailFromBlock _ = Block []
|
|
||||||
|
|
||||||
-- |Utility Function: Extracts the code at a point in the genome. Recurses into a nested Block if found. The
|
|
||||||
-- point is based on an int.
|
|
||||||
codeAtPoint :: [Gene] -> Int -> Gene
|
|
||||||
codeAtPoint (gene : _) 0 = gene
|
|
||||||
codeAtPoint [] _ = Block [] -- Should only happen if an empty block is last Gene in the list of Genes
|
|
||||||
codeAtPoint ((Block nestedGenes) : genes) index = codeAtPoint (nestedGenes <> genes) (index - 1)
|
|
||||||
codeAtPoint (_ : genes) index = codeAtPoint genes (index - 1)
|
|
||||||
|
|
||||||
-- |Utility Function: Inserts code at a point in the genome. Recurses into a block if found. The point is based
|
|
||||||
-- on an integer
|
|
||||||
codeInsertAtPoint :: [Gene] -> Gene -> Int -> [Gene]
|
|
||||||
codeInsertAtPoint oldGenes gene 0 = gene : oldGenes
|
|
||||||
codeInsertAtPoint [] gene _ = [gene] -- This shouldn't happen (lol)
|
|
||||||
codeInsertAtPoint ((Block genes) : oldGenes) gene index = Block (codeInsertAtPoint genes gene (index - 1)) : oldGenes
|
|
||||||
codeInsertAtPoint (oldGene : oldGenes) gene index = oldGene : codeInsertAtPoint oldGenes gene (index - 1)
|
|
||||||
|
|
||||||
-- |Utility Function: Combines two genes together into a block.
|
|
||||||
codeCombine :: Gene -> Gene -> Gene
|
|
||||||
codeCombine (Block bxs) (Block bys) = Block (bxs <> bys)
|
|
||||||
codeCombine (Block bxs) ygene = Block (ygene : bxs)
|
|
||||||
codeCombine xgene (Block bys) = Block (xgene : bys)
|
|
||||||
codeCombine xgene ygene = Block [xgene, ygene]
|
|
||||||
|
|
||||||
-- |Utility Function: Determines if the second gene is a member of the first gene.
|
|
||||||
-- If the first gene is a Block and the second gene is also a Block, does a sublist search for the second block in the first block.
|
|
||||||
-- if the first gene is a Block and the second gene is not, the block is searched for the second gene.
|
|
||||||
-- If neither of the genes are blocks, returns False.
|
|
||||||
codeMember :: Gene -> Gene -> Bool
|
|
||||||
codeMember (Block bxs) (Block bys) = findSubA bxs bys /= (-1)
|
|
||||||
codeMember (Block bxs) ygene = ygene `elem` bxs
|
|
||||||
codeMember _ _ = False
|
|
||||||
|
|
||||||
-- |Utility Function: Calculates the size of a Block including counting the nested Blocks recursively
|
|
||||||
codeRecursiveSize :: Gene -> Int
|
|
||||||
codeRecursiveSize (Block bxs) = sum [codeRecursiveSize x + if isBlock x then 1 else 0 | x <- bxs]
|
|
||||||
codeRecursiveSize _ = 1
|
|
||||||
|
|
||||||
-- |Pops the top of the code stack
|
-- |Pops the top of the code stack
|
||||||
instructionCodePop :: State -> State
|
instructionCodePop :: State -> State
|
||||||
instructionCodePop = instructionPop code
|
instructionCodePop = instructionPop code
|
||||||
|
@ -2,6 +2,7 @@ module HushGP.Instructions.FloatInstructions where
|
|||||||
|
|
||||||
import Data.Fixed (mod')
|
import Data.Fixed (mod')
|
||||||
import HushGP.Instructions.GenericInstructions
|
import HushGP.Instructions.GenericInstructions
|
||||||
|
import HushGP.Instructions.Utility
|
||||||
import HushGP.State
|
import HushGP.State
|
||||||
import Data.Char
|
import Data.Char
|
||||||
|
|
||||||
|
@ -2,111 +2,13 @@ module HushGP.Instructions.GenericInstructions where
|
|||||||
|
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import HushGP.State
|
import HushGP.State
|
||||||
|
import HushGP.Instructions.Utility
|
||||||
import Data.List (sort, sortBy)
|
import Data.List (sort, sortBy)
|
||||||
import Data.Ord
|
import Data.Ord
|
||||||
import Data.List.Split
|
import Data.List.Split
|
||||||
|
|
||||||
-- import Debug.Trace
|
-- import Debug.Trace
|
||||||
|
|
||||||
-- |Utility Function: Deletes an item from a list at a specified index.
|
|
||||||
deleteAt :: Int -> [a] -> [a]
|
|
||||||
deleteAt idx xs = take idx xs <> drop 1 (drop idx xs)
|
|
||||||
|
|
||||||
-- |Utility Function: Combines two tuples containing lists with a value placed between them.
|
|
||||||
combineTuple :: a -> ([a], [a]) -> [a]
|
|
||||||
combineTuple val = combineTupleList [val]
|
|
||||||
|
|
||||||
-- |Utility Function: Combines two tuples containing lists with a list placed between them.
|
|
||||||
combineTupleList :: [a] -> ([a], [a]) -> [a]
|
|
||||||
combineTupleList val tup = fst tup <> val <> snd tup
|
|
||||||
|
|
||||||
-- |Utility Function: Inserts a value based on an int at a specified index.
|
|
||||||
insertAt :: Int -> a -> [a] -> [a]
|
|
||||||
insertAt idx val xs = combineTuple val (splitAt idx xs)
|
|
||||||
|
|
||||||
-- |Utility Function: Replaces a value based on an int at a specified index.
|
|
||||||
replaceAt :: Int -> a -> [a] -> [a]
|
|
||||||
replaceAt idx val xs = deleteAt (idx + 1) (insertAt idx val xs)
|
|
||||||
|
|
||||||
-- |Utility Function: Takes two ints as indicies. Sorts them low to high, sets the start to
|
|
||||||
-- 0 if the lowest start is less than 0 and the end to the length of the list - 1 if the end
|
|
||||||
-- if larger than the list. Grabs the sub list of adjusted indicies.
|
|
||||||
subList :: Int -> Int -> [a] -> [a]
|
|
||||||
subList idx0 idx1 xs =
|
|
||||||
let
|
|
||||||
(start, end) = if idx0 <= idx1 then (idx0, idx1) else (idx1, idx0)
|
|
||||||
adjStart = max 0 start
|
|
||||||
adjEnd = min end (length xs)
|
|
||||||
in
|
|
||||||
take adjEnd (drop adjStart xs)
|
|
||||||
|
|
||||||
-- |Utility Function: Finds the index of the second list inside of the first index.
|
|
||||||
-- If the sublist passed is larger than the full list, returns -1
|
|
||||||
-- If the lists are of equal length, and then contents are equal, returns 0. If not equal, returns -1
|
|
||||||
-- Recursively shortens the full list until the sub list is found.
|
|
||||||
findSubA :: forall a. Eq a => [a] -> [a] -> Int
|
|
||||||
findSubA fullA subA
|
|
||||||
| length fullA < length subA = -1
|
|
||||||
| length fullA == length subA = if fullA == subA then 0 else -1
|
|
||||||
| otherwise = findSubA' fullA subA 0
|
|
||||||
where
|
|
||||||
findSubA' :: [a] -> [a] -> Int -> Int
|
|
||||||
findSubA' fA sA subIndex
|
|
||||||
| null fA = -1
|
|
||||||
| length sA > length fA = -1
|
|
||||||
| sA == take (length sA) fA = subIndex
|
|
||||||
| otherwise = findSubA' (drop 1 fA) sA (subIndex + 1)
|
|
||||||
|
|
||||||
-- |Utility Function: Replaces a number of instances of old with new in a list.
|
|
||||||
-- The Maybe Int is the amount of olds to replace with new. Nothing means replace all.
|
|
||||||
-- Just chain findSubA calls.
|
|
||||||
-- May not be the most efficient method with the findSubA calls.
|
|
||||||
replace :: Eq a => [a] -> [a] -> [a] -> Maybe Int -> [a]
|
|
||||||
replace fullA old new (Just amt) =
|
|
||||||
if findSubA fullA old /= -1 && amt > 0
|
|
||||||
then replace (take (findSubA fullA old) fullA <> new <> drop (findSubA fullA old + length old) fullA) old new (Just $ amt - 1)
|
|
||||||
else fullA
|
|
||||||
replace fullA old new Nothing =
|
|
||||||
if findSubA fullA old /= -1
|
|
||||||
then replace (take (findSubA fullA old) fullA <> new <> drop (findSubA fullA old + length old) fullA) old new Nothing
|
|
||||||
else fullA
|
|
||||||
|
|
||||||
-- |Utility Function: Counts the amount of occurrences of a sub list inside
|
|
||||||
-- of a larger list.
|
|
||||||
amtOccurences :: forall a. Eq a => [a] -> [a] -> Int
|
|
||||||
amtOccurences fullA subA = amtOccurences' fullA subA 0
|
|
||||||
where
|
|
||||||
amtOccurences' :: [a] -> [a] -> Int -> Int
|
|
||||||
amtOccurences' fA sA count =
|
|
||||||
if findSubA fA sA /= -1
|
|
||||||
then amtOccurences' (replace fA sA mempty (Just 1)) sA (count + 1)
|
|
||||||
else count
|
|
||||||
|
|
||||||
-- |Utility Function: Takes the last N elements of a list.
|
|
||||||
takeR :: Int -> [a] -> [a]
|
|
||||||
takeR amt fullA = drop (length fullA - amt) fullA
|
|
||||||
|
|
||||||
-- |Utility Function: Drops the last N elements of a list.
|
|
||||||
dropR :: Int -> [a] -> [a]
|
|
||||||
dropR amt fullA = take (length fullA - amt) fullA
|
|
||||||
|
|
||||||
-- |Utility Function: A safe version of init. If the list is empty, returns the empty list.
|
|
||||||
-- If the list has items, takes the init of the list.
|
|
||||||
safeInit :: [a] -> [a]
|
|
||||||
safeInit [] = []
|
|
||||||
safeInit xs = init xs
|
|
||||||
|
|
||||||
-- |Utility Function: An indexing strategy used in parts of Hush. Takes the absolute value
|
|
||||||
-- of the passed number `mod` the length of the passed list.
|
|
||||||
absNum :: Integral a => a -> [b] -> Int
|
|
||||||
absNum rawNum lst = abs (fromIntegral rawNum) `mod` length lst
|
|
||||||
|
|
||||||
-- |Utility Function: Checks to see if a list is empty.
|
|
||||||
-- If the list is empty, returns False.
|
|
||||||
-- If the list is not empty, returns True.
|
|
||||||
notEmptyStack :: Lens' State [a] -> State -> Bool
|
|
||||||
notEmptyStack accessor state = not . null $ view accessor state
|
|
||||||
|
|
||||||
-- |Duplicates the top of a stack based on a lens.
|
-- |Duplicates the top of a stack based on a lens.
|
||||||
instructionDup :: Lens' State [a] -> State -> State
|
instructionDup :: Lens' State [a] -> State -> State
|
||||||
instructionDup accessor state =
|
instructionDup accessor state =
|
||||||
|
@ -2,30 +2,9 @@ module HushGP.Instructions.StringInstructions where
|
|||||||
|
|
||||||
import HushGP.State
|
import HushGP.State
|
||||||
import HushGP.Instructions.GenericInstructions
|
import HushGP.Instructions.GenericInstructions
|
||||||
|
import HushGP.Instructions.Utility
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
|
|
||||||
-- |Utility String: Whitespack characters.
|
|
||||||
-- shamelessly stolen from https://hackage.haskell.org/package/MissingH-1.6.0.1/docs/src/Data.String.Utils.html#strip
|
|
||||||
wschars :: String
|
|
||||||
wschars = " \t\r\n"
|
|
||||||
|
|
||||||
-- |Utility Function: Strips a string of its whitespace on both sides.
|
|
||||||
strip :: String -> String
|
|
||||||
strip = lstrip . rstrip
|
|
||||||
|
|
||||||
-- |Utility Function: Strips a string of its whitespace on the left side.
|
|
||||||
lstrip :: String -> String
|
|
||||||
lstrip s = case s of
|
|
||||||
[] -> []
|
|
||||||
(x:xs) -> if x `elem` wschars
|
|
||||||
then lstrip xs
|
|
||||||
else s
|
|
||||||
|
|
||||||
-- |Utility Function: Strips a string of its whitespace on the right side.
|
|
||||||
-- this is a tad inefficient
|
|
||||||
rstrip :: String -> String
|
|
||||||
rstrip = reverse . lstrip . reverse
|
|
||||||
|
|
||||||
-- |Concats the top two strings on the string stack and pushes the result.
|
-- |Concats the top two strings on the string stack and pushes the result.
|
||||||
instructionStringConcat :: State -> State
|
instructionStringConcat :: State -> State
|
||||||
instructionStringConcat = instructionVectorConcat string
|
instructionStringConcat = instructionVectorConcat string
|
||||||
|
249
src/HushGP/Instructions/Utility.hs
Normal file
249
src/HushGP/Instructions/Utility.hs
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
module HushGP.Instructions.Utility where
|
||||||
|
|
||||||
|
import Control.Lens hiding (index)
|
||||||
|
import HushGP.State
|
||||||
|
import Data.Char
|
||||||
|
|
||||||
|
-- generic utility
|
||||||
|
|
||||||
|
-- |Utility Function: Deletes an item from a list at a specified index.
|
||||||
|
deleteAt :: Int -> [a] -> [a]
|
||||||
|
deleteAt idx xs = take idx xs <> drop 1 (drop idx xs)
|
||||||
|
|
||||||
|
-- |Utility Function: Combines two tuples containing lists with a value placed between them.
|
||||||
|
combineTuple :: a -> ([a], [a]) -> [a]
|
||||||
|
combineTuple val = combineTupleList [val]
|
||||||
|
|
||||||
|
-- |Utility Function: Combines two tuples containing lists with a list placed between them.
|
||||||
|
combineTupleList :: [a] -> ([a], [a]) -> [a]
|
||||||
|
combineTupleList val tup = fst tup <> val <> snd tup
|
||||||
|
|
||||||
|
-- |Utility Function: Inserts a value based on an int at a specified index.
|
||||||
|
insertAt :: Int -> a -> [a] -> [a]
|
||||||
|
insertAt idx val xs = combineTuple val (splitAt idx xs)
|
||||||
|
|
||||||
|
-- |Utility Function: Replaces a value based on an int at a specified index.
|
||||||
|
replaceAt :: Int -> a -> [a] -> [a]
|
||||||
|
replaceAt idx val xs = deleteAt (idx + 1) (insertAt idx val xs)
|
||||||
|
|
||||||
|
-- |Utility Function: Takes two ints as indicies. Sorts them low to high, sets the start to
|
||||||
|
-- 0 if the lowest start is less than 0 and the end to the length of the list - 1 if the end
|
||||||
|
-- if larger than the list. Grabs the sub list of adjusted indicies.
|
||||||
|
subList :: Int -> Int -> [a] -> [a]
|
||||||
|
subList idx0 idx1 xs =
|
||||||
|
let
|
||||||
|
(start, end) = if idx0 <= idx1 then (idx0, idx1) else (idx1, idx0)
|
||||||
|
adjStart = max 0 start
|
||||||
|
adjEnd = min end (length xs)
|
||||||
|
in
|
||||||
|
take adjEnd (drop adjStart xs)
|
||||||
|
|
||||||
|
-- |Utility Function: Finds the index of the second list inside of the first index.
|
||||||
|
-- If the sublist passed is larger than the full list, returns -1
|
||||||
|
-- If the lists are of equal length, and then contents are equal, returns 0. If not equal, returns -1
|
||||||
|
-- Recursively shortens the full list until the sub list is found.
|
||||||
|
findSubA :: forall a. Eq a => [a] -> [a] -> Int
|
||||||
|
findSubA fullA subA
|
||||||
|
| length fullA < length subA = -1
|
||||||
|
| length fullA == length subA = if fullA == subA then 0 else -1
|
||||||
|
| otherwise = findSubA' fullA subA 0
|
||||||
|
where
|
||||||
|
findSubA' :: [a] -> [a] -> Int -> Int
|
||||||
|
findSubA' fA sA subIndex
|
||||||
|
| null fA = -1
|
||||||
|
| length sA > length fA = -1
|
||||||
|
| sA == take (length sA) fA = subIndex
|
||||||
|
| otherwise = findSubA' (drop 1 fA) sA (subIndex + 1)
|
||||||
|
|
||||||
|
-- |Utility Function: Replaces a number of instances of old with new in a list.
|
||||||
|
-- The Maybe Int is the amount of olds to replace with new. Nothing means replace all.
|
||||||
|
-- Just chain findSubA calls.
|
||||||
|
-- May not be the most efficient method with the findSubA calls.
|
||||||
|
replace :: Eq a => [a] -> [a] -> [a] -> Maybe Int -> [a]
|
||||||
|
replace fullA old new (Just amt) =
|
||||||
|
if findSubA fullA old /= -1 && amt > 0
|
||||||
|
then replace (take (findSubA fullA old) fullA <> new <> drop (findSubA fullA old + length old) fullA) old new (Just $ amt - 1)
|
||||||
|
else fullA
|
||||||
|
replace fullA old new Nothing =
|
||||||
|
if findSubA fullA old /= -1
|
||||||
|
then replace (take (findSubA fullA old) fullA <> new <> drop (findSubA fullA old + length old) fullA) old new Nothing
|
||||||
|
else fullA
|
||||||
|
|
||||||
|
-- |Utility Function: Counts the amount of occurrences of a sub list inside
|
||||||
|
-- of a larger list.
|
||||||
|
amtOccurences :: forall a. Eq a => [a] -> [a] -> Int
|
||||||
|
amtOccurences fullA subA = amtOccurences' fullA subA 0
|
||||||
|
where
|
||||||
|
amtOccurences' :: [a] -> [a] -> Int -> Int
|
||||||
|
amtOccurences' fA sA count =
|
||||||
|
if findSubA fA sA /= -1
|
||||||
|
then amtOccurences' (replace fA sA mempty (Just 1)) sA (count + 1)
|
||||||
|
else count
|
||||||
|
|
||||||
|
-- |Utility Function: Takes the last N elements of a list.
|
||||||
|
takeR :: Int -> [a] -> [a]
|
||||||
|
takeR amt fullA = drop (length fullA - amt) fullA
|
||||||
|
|
||||||
|
-- |Utility Function: Drops the last N elements of a list.
|
||||||
|
dropR :: Int -> [a] -> [a]
|
||||||
|
dropR amt fullA = take (length fullA - amt) fullA
|
||||||
|
|
||||||
|
-- |Utility Function: A safe version of init. If the list is empty, returns the empty list.
|
||||||
|
-- If the list has items, takes the init of the list.
|
||||||
|
safeInit :: [a] -> [a]
|
||||||
|
safeInit [] = []
|
||||||
|
safeInit xs = init xs
|
||||||
|
|
||||||
|
-- |Utility Function: An indexing strategy used in parts of Hush. Takes the absolute value
|
||||||
|
-- of the passed number `mod` the length of the passed list.
|
||||||
|
absNum :: Integral a => a -> [b] -> Int
|
||||||
|
absNum rawNum lst = abs (fromIntegral rawNum) `mod` length lst
|
||||||
|
|
||||||
|
-- |Utility Function: Checks to see if a list is empty.
|
||||||
|
-- If the list is empty, returns False.
|
||||||
|
-- If the list is not empty, returns True.
|
||||||
|
notEmptyStack :: Lens' State [a] -> State -> Bool
|
||||||
|
notEmptyStack accessor state = not . null $ view accessor state
|
||||||
|
|
||||||
|
-- bool utility
|
||||||
|
|
||||||
|
-- |A template function to make bool comparisons concise.
|
||||||
|
boolTemplate :: (Bool -> Bool -> Bool) -> State -> State
|
||||||
|
boolTemplate func state@(State {_bool = b1 : b2 : bs}) = state {_bool = func b1 b2 : bs}
|
||||||
|
boolTemplate _ state = state
|
||||||
|
|
||||||
|
-- |Utility function. Haskell doesn't have its own xor operation.
|
||||||
|
xor :: Bool -> Bool -> Bool
|
||||||
|
xor b1 b2
|
||||||
|
| b1 && not b2 = True
|
||||||
|
| not b1 && b2 = True
|
||||||
|
| otherwise = False
|
||||||
|
|
||||||
|
-- char utility
|
||||||
|
|
||||||
|
-- |Utility: Converts a whole number `mod` 128 to a char.
|
||||||
|
intToAscii :: Integral a => a -> Char
|
||||||
|
intToAscii val = chr (abs (fromIntegral val) `mod` 128)
|
||||||
|
|
||||||
|
-- code utility
|
||||||
|
|
||||||
|
-- |Utility function: Checks to see if a gene is a code block.
|
||||||
|
-- If it is a block, returns true, else returns false
|
||||||
|
isBlock :: Gene -> Bool
|
||||||
|
isBlock (Block _) = True
|
||||||
|
isBlock _ = False
|
||||||
|
|
||||||
|
-- |Utility function: Returns the length of the passed block.
|
||||||
|
-- If the gene isn't a block, returns 1
|
||||||
|
blockLength :: Gene -> Int
|
||||||
|
blockLength (Block bxs) = length bxs
|
||||||
|
blockLength _ = 1
|
||||||
|
|
||||||
|
-- |Utility function: Returns true if the passed block is empty, false is not.
|
||||||
|
-- If the passed gene is not a block, returns false
|
||||||
|
blockIsNull :: Gene -> Bool
|
||||||
|
blockIsNull (Block bxs) = null bxs
|
||||||
|
blockIsNull _ = False
|
||||||
|
|
||||||
|
-- |Utility Function: A helper function for instructionCodeContainer. The full description is there.
|
||||||
|
-- https://faculty.hampshire.edu/lspector/push3-description.html#Type
|
||||||
|
-- CODE.CONTAINER
|
||||||
|
findContainer :: Gene -> Gene -> Gene
|
||||||
|
findContainer (Block fullA) gene
|
||||||
|
| length fullA <= blockLength gene = Block []
|
||||||
|
| gene `elem` fullA = Block [] -- Not allowed to be top level
|
||||||
|
| any isBlock fullA = findContainer' (filter isBlock fullA) gene
|
||||||
|
| otherwise = Block []
|
||||||
|
where
|
||||||
|
findContainer' :: [Gene] -> Gene -> Gene
|
||||||
|
findContainer' [] _ = Block []
|
||||||
|
findContainer' ((Block bx1) : bxs) g = if g `elem` bx1 then Block bx1 else findContainer' bxs g
|
||||||
|
findContainer' _ _ = Block [] -- This should never happen
|
||||||
|
findContainer _ _ = Block []
|
||||||
|
|
||||||
|
-- |Utility Function: A helper function for instructionCodeDiscrepancy. The full description is there.
|
||||||
|
countDiscrepancy :: Gene -> Gene -> Int
|
||||||
|
countDiscrepancy (Block xs) (Block ys) = sum [if uncurry (==) tup then 0 else 1 | tup <- zip xs ys] + abs (length xs - length ys)
|
||||||
|
countDiscrepancy xgene ygene = if xgene == ygene then 1 else 0
|
||||||
|
|
||||||
|
-- |Utility Function: Extracts the first gene from a block. Returns itself if not a block
|
||||||
|
extractFirstFromBlock :: Gene -> Gene
|
||||||
|
extractFirstFromBlock (Block (bx1 : _)) = bx1
|
||||||
|
extractFirstFromBlock gene = gene
|
||||||
|
|
||||||
|
-- |Utility Function: Returns the last gene from a block, [] if the block is empty, and itself if not a block
|
||||||
|
extractLastFromBlock :: Gene -> Gene
|
||||||
|
extractLastFromBlock (Block []) = Block []
|
||||||
|
extractLastFromBlock (Block bxs) = last bxs
|
||||||
|
extractLastFromBlock gene = gene
|
||||||
|
|
||||||
|
-- |Utility Function: Calls init on a block. If the block is empty, returns []. If gene isn't a block, returns itself
|
||||||
|
extractInitFromBlock :: Gene -> Gene
|
||||||
|
extractInitFromBlock (Block bxs) = Block (safeInit bxs)
|
||||||
|
extractInitFromBlock gene = gene
|
||||||
|
|
||||||
|
-- |Utility Function: Calls `drop 1` on a block. If gene isn't a block, returns itself
|
||||||
|
extractTailFromBlock :: Gene -> Gene
|
||||||
|
extractTailFromBlock (Block bxs) = Block (drop 1 bxs)
|
||||||
|
extractTailFromBlock _ = Block []
|
||||||
|
|
||||||
|
-- |Utility Function: Extracts the code at a point in the genome. Recurses into a nested Block if found. The
|
||||||
|
-- point is based on an int.
|
||||||
|
codeAtPoint :: [Gene] -> Int -> Gene
|
||||||
|
codeAtPoint (gene : _) 0 = gene
|
||||||
|
codeAtPoint [] _ = Block [] -- Should only happen if an empty block is last Gene in the list of Genes
|
||||||
|
codeAtPoint ((Block nestedGenes) : genes) index = codeAtPoint (nestedGenes <> genes) (index - 1)
|
||||||
|
codeAtPoint (_ : genes) index = codeAtPoint genes (index - 1)
|
||||||
|
|
||||||
|
-- |Utility Function: Inserts code at a point in the genome. Recurses into a block if found. The point is based
|
||||||
|
-- on an integer
|
||||||
|
codeInsertAtPoint :: [Gene] -> Gene -> Int -> [Gene]
|
||||||
|
codeInsertAtPoint oldGenes gene 0 = gene : oldGenes
|
||||||
|
codeInsertAtPoint [] gene _ = [gene] -- This shouldn't happen (lol)
|
||||||
|
codeInsertAtPoint ((Block genes) : oldGenes) gene index = Block (codeInsertAtPoint genes gene (index - 1)) : oldGenes
|
||||||
|
codeInsertAtPoint (oldGene : oldGenes) gene index = oldGene : codeInsertAtPoint oldGenes gene (index - 1)
|
||||||
|
|
||||||
|
-- |Utility Function: Combines two genes together into a block.
|
||||||
|
codeCombine :: Gene -> Gene -> Gene
|
||||||
|
codeCombine (Block bxs) (Block bys) = Block (bxs <> bys)
|
||||||
|
codeCombine (Block bxs) ygene = Block (ygene : bxs)
|
||||||
|
codeCombine xgene (Block bys) = Block (xgene : bys)
|
||||||
|
codeCombine xgene ygene = Block [xgene, ygene]
|
||||||
|
|
||||||
|
-- |Utility Function: Determines if the second gene is a member of the first gene.
|
||||||
|
-- If the first gene is a Block and the second gene is also a Block, does a sublist search for the second block in the first block.
|
||||||
|
-- if the first gene is a Block and the second gene is not, the block is searched for the second gene.
|
||||||
|
-- If neither of the genes are blocks, returns False.
|
||||||
|
codeMember :: Gene -> Gene -> Bool
|
||||||
|
codeMember (Block bxs) (Block bys) = findSubA bxs bys /= (-1)
|
||||||
|
codeMember (Block bxs) ygene = ygene `elem` bxs
|
||||||
|
codeMember _ _ = False
|
||||||
|
|
||||||
|
-- |Utility Function: Calculates the size of a Block including counting the nested Blocks recursively
|
||||||
|
codeRecursiveSize :: Gene -> Int
|
||||||
|
codeRecursiveSize (Block bxs) = sum [codeRecursiveSize x + if isBlock x then 1 else 0 | x <- bxs]
|
||||||
|
codeRecursiveSize _ = 1
|
||||||
|
|
||||||
|
-- string utility
|
||||||
|
|
||||||
|
-- |Utility String: Whitespack characters.
|
||||||
|
-- shamelessly stolen from https://hackage.haskell.org/package/MissingH-1.6.0.1/docs/src/Data.String.Utils.html#strip
|
||||||
|
wschars :: String
|
||||||
|
wschars = " \t\r\n"
|
||||||
|
|
||||||
|
-- |Utility Function: Strips a string of its whitespace on both sides.
|
||||||
|
strip :: String -> String
|
||||||
|
strip = lstrip . rstrip
|
||||||
|
|
||||||
|
-- |Utility Function: Strips a string of its whitespace on the left side.
|
||||||
|
lstrip :: String -> String
|
||||||
|
lstrip s = case s of
|
||||||
|
[] -> []
|
||||||
|
(x:xs) -> if x `elem` wschars
|
||||||
|
then lstrip xs
|
||||||
|
else s
|
||||||
|
|
||||||
|
-- |Utility Function: Strips a string of its whitespace on the right side.
|
||||||
|
-- this is a tad inefficient
|
||||||
|
rstrip :: String -> String
|
||||||
|
rstrip = reverse . lstrip . reverse
|
@ -1,6 +1,6 @@
|
|||||||
module HushGP.PushTests.UtilTests where
|
module HushGP.PushTests.UtilTests where
|
||||||
|
|
||||||
import HushGP.Instructions.GenericInstructions
|
import HushGP.Instructions.Utility
|
||||||
import Test.QuickCheck
|
import Test.QuickCheck
|
||||||
|
|
||||||
prop_DeleteAtTest :: Int -> [Int] -> Property
|
prop_DeleteAtTest :: Int -> [Int] -> Property
|
||||||
|
Loading…
x
Reference in New Issue
Block a user