palindromes 0.4 → 1.0
raw patch · 51 files changed
+8634/−1316 lines, 51 filesdep +HUnitdep +QuickCheckdep +conduitdep −arraydep −bytestringdep −containersdep ~basesetup-changed
Dependencies added: HUnit, QuickCheck, conduit, criterion, deepseq, directory, filepath, levenshtein, palindromes, strict, vector
Dependencies removed: array, bytestring, containers
Dependency ranges changed: base
Files
- CREDITS +37/−24
- LICENSE +28/−28
- README +0/−122
- README.md +159/−0
- RELEASE_HISTORY +0/−68
- Setup.lhs +0/−4
- app/FlagsToSettings.hs +151/−0
- app/Main.hs +130/−0
- app/Options.hs +199/−0
- benchmarking/Main.hs +179/−0
- changelog.md +105/−0
- palindromes.cabal +130/−47
- profiling/Main.hs +54/−0
- src/Data/Algorithms/Palindromes/Algorithms.hs +63/−0
- src/Data/Algorithms/Palindromes/ApproximateAlgorithm.hs +240/−0
- src/Data/Algorithms/Palindromes/DNA.hs +110/−0
- src/Data/Algorithms/Palindromes/Finders.hs +238/−0
- src/Data/Algorithms/Palindromes/LinearAlgorithm.hs +195/−0
- src/Data/Algorithms/Palindromes/Main.hs +0/−54
- src/Data/Algorithms/Palindromes/Options.hs +0/−234
- src/Data/Algorithms/Palindromes/Output.hs +99/−0
- src/Data/Algorithms/Palindromes/PalEq.hs +47/−0
- src/Data/Algorithms/Palindromes/Palindrome.hs +45/−0
- src/Data/Algorithms/Palindromes/Palindromes.hs +0/−325
- src/Data/Algorithms/Palindromes/PalindromesUtils.hs +0/−175
- src/Data/Algorithms/Palindromes/PostProcessing.hs +48/−0
- src/Data/Algorithms/Palindromes/PreProcessing.hs +95/−0
- src/Data/Algorithms/Palindromes/QuadraticAlgorithm.hs +207/−0
- src/Data/Algorithms/Palindromes/RangeFunctions.hs +54/−0
- src/Data/Algorithms/Palindromes/Settings.hs +88/−0
- src/Data/Algorithms/Palindromes/Streaming.hs +129/−0
- tests/ITApproximate.hs +981/−0
- tests/ITLinear.hs +799/−0
- tests/ITQuadratic.hs +981/−0
- tests/Main.hs +61/−235
- tests/PalindromeMethods.hs +64/−0
- tests/QuickCheckGenerators.hs +177/−0
- tests/QuickCheckProperties.hs +287/−0
- tests/QuickCheckSettings.hs +363/−0
- tests/UTApproximateAlgorithm.hs +595/−0
- tests/UTDNAPals.hs +25/−0
- tests/UTExtendPals.hs +72/−0
- tests/UTFinders.hs +111/−0
- tests/UTGetLeftRight.hs +194/−0
- tests/UTLinearAlgorithm.hs +368/−0
- tests/UTPalEq.hs +104/−0
- tests/UTProcessing.hs +96/−0
- tests/UTPunctuationPals.hs +50/−0
- tests/UTQuadraticAlgorithm.hs +316/−0
- tests/UTTextPals.hs +52/−0
- tests/UTWordPals.hs +108/−0
CREDITS view
@@ -1,24 +1,37 @@--Credits for Finding Palindromes-===============================--This is a list of those who have contributed to the research, -concept, code, and/or other issues of Finding Palindromes.--Research and code--------------------* Johan Jeuring-* Bastiaan Heeren developed an implementation of palindromes - using suffix trees. This version was slower, and could - process less data than this released version.--Bug reports, testing, feature requests-----------------------------------* Rafael Cunha de Almeida-* Henning Thielemann-* Anjana Ramnath-* Jennifer Hughes--+ +Credits for Finding Palindromes +=============================== + +This is a list of those who have contributed to the research, +concept, code, and/or other issues of Finding Palindromes. + +Research and code +----------------- + +* Johan Jeuring +* Bastiaan Heeren developed an implementation of palindromes + using suffix trees. This version was slower, and could + process less data than this released version. + +As part of the Software Project course at the Utrecht University, a group of students +called "Pal's Lab" worked on this code in 2025. These students are: +* Ruben de Boer +* Nick Broeks +* David van Deursen +* Jonathan van Dijk +* Quincy Einmahl +* Qun Franken +* Geerten Helmers +* Freek van 't Hof +* Goof Vos +* Rens de Wit + +Bug reports, testing, feature requests +-------------------------------- + +* Rafael Cunha de Almeida +* Henning Thielemann +* Anjana Ramnath +* Jennifer Hughes + +
LICENSE view
@@ -1,28 +1,28 @@-Copyright (c) 2007 - 2013 Johan Jeuring-All rights reserved.--Redistribution and use in source and binary forms, with or without modification,-are permitted provided that the following conditions are met:--1. Redistributions of source code must retain the above copyright notice, this- list of conditions and the following disclaimer.--2. Redistributions in binary form must reproduce the above copyright notice,- this list of conditions and the following disclaimer in the documentation- and/or other materials provided with the distribution.--3. Neither the name of Johan Jeuring nor the names of its contributors- may be used to endorse or promote products derived from this software without- specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-+Copyright (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of Johan Jeuring nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +
− README
@@ -1,122 +0,0 @@--Palindromes-==============================================--[Palindromes] is a package for finding palindromes in files.--[Palindromes]: http://www.jeuring.net/homepage/palindromes/index.html---Features-----------The primary features of [Palindromes] include:--* Linear-time algorithm for finding exact palindromes-* Linear-time algorithm for finding text palindromes, - ignoring spaces, case of characters, and punctuation - symbols.-* Linear-time algorithm for finding word palindromes,- text palindromes surrounded by (if at all) non-letters.-* Linear-time algorithm for finding palindromes in DNA.-* Quadratic-time algorithm for finding approximate - palindromes, in which a limited number of symbols- may be substituted by other symbols-* Quadratic-time algorithm for finding palindromes with- gaps in the center.---Requirements---------------[Palindromes] has the following requirements:--* [GHC] version 6.8.1 or later - It has been tested with version 7.4.1.-* [Cabal] library version 1.2.1 or later - It has been tested with version - 1.10.2.0.--[GHC]: http://www.haskell.org/ghc/-[Cabal]: http://www.haskell.org/cabal/---Download & Installation--------------------------*If you have [cabal-install]*, you should use that to install the package,-because it will handle everything for you.-- cabal install palindromes--*If you don't have cabal-install*, you must download the [Palindromes package] -from HackageDB and install it manually. Get the `tar.gz` file and decompress it.--Once downloaded, use the following commands for configuring, building, and-installing the library.-- runghc Setup.lhs configure- runghc Setup.lhs build- runghc Setup.lhs install--For more details on the general options available, refer to the [Cabal User's-Guide].--[Palindromes package]: - http://hackage.haskell.org/package/palindromes-[cabal-install]: - http://www.haskell.org/haskellwiki/Cabal-Install-[Cabal User's Guide]: - http://www.haskell.org/cabal/users-guide/---Documentation----------------The API is documented using [Haddock] and available on the [Palindromes package] -site.--[Haddock]: http://hackage.haskell.org/package/haddock-[Palindromes package]: - http://hackage.haskell.org/package/palindromes---Examples-----------You can find example palindromes, on which Palindromes has been tested, in the -[`examples` directory] of the source distribution.--[`examples` directory]: - https://subversion.cs.uu.nl/repos/staff.johanj.palindromes/trunk/examples/palindromes---Bugs & Support-----------------To report bugs, use the Google Code [project page for Palindromes].--For general concerns and questions, [email the author].--[project page for Palindromes]: http://code.google.com/p/palindromes/-[email the author]: johan at jeuring.net---Licensing------------Palindromes is licensed under the so-called [BSD3 license]. See the included -`LICENSE` file.--[BSD3 license]: http://www.opensource.org/licenses/bsd-license.php---Credits----------Palindromes is based on the functional program developed by [Johan Jeuring] in -his PhD thesis. --The current authors and maintainer of palindromes is [Johan Jeuring].--[Johan Jeuring]: http://www.jeuring.net/--
+ README.md view
@@ -0,0 +1,159 @@+# Palindromes + +Palindromes is a package for finding palindromes in files. + +## Features + +Palindromes includes three algorithms: a linear complexity algorithm, a quadratic time complexity algorithm and another quadratic time algorithm for finding approximate palindromes. + +All three algorithms support the following features: +- Finding plain palindromes +- Finding text palindromes, + ignoring spaces, case of characters, and punctuation + symbols. +- Finding palindromes in DNA. +- Finding word palindromes, + palindromes made up of words instead of characters. + +Now follows an overview of features the individual algorithms support. +There is some overlap between these features, these are mentioned twice. +We also mention advantages and disadvantages of the algorithms. + +The linear algorithm further support: +- Finding punctuation palindromes, + text palindromes surrounded by (if at all) non-letters. + This requires a quadratic postprocessing step. +- When there is many very large palindromes in the text, this algorithm is the fastest. + +The quadratic algorithm further supports: +- Finding punctuation palindromes, + text palindromes surrounded by (if at all) non-letters. + This requires a quadratic postprocessing step. +- Finding palindromes with substitution errors, + in which a limited number of symbols may be substituted by other symbols to get palindromes. + Like 'river', which is a perfect palindrome if the 'i' is substituted for an 'e'. +- Finding (approximate) palindromes with + gaps in the center. +- This algorithm is faster than the approximate algorithm. It is also the fastest for most regular texts. + +The approximate palindrome algorithm further supports: +- Finding approximate palindromes with insertion, deletion and substitution errors, + in which a limited number of insertion, deletion or substitution operations on the 'left arm' of the approximate palindrome results in a palindrome. A simple example is 'levels', which is a palindrome if you insert one 's' at the start of the word. +- Finding (approximate) palindromes with + gaps in the center. + +The algorithms search for maximal palindromes but use different definitions of maximal. +For the linear and quadratic algorithm a maximal palindrome is the possible palindrome from a center (a position on a letter or inbetween two letters), from which the palindrome is extended on both sides. This means the algorithm will find a palindrome for each center. In approximate algorithm a maximal palindrome is any substring which cannot be extended on one or both sides without exceeding the allowed amount of insertions, deletions or substitions. + +For more information on the different algorithms and the different kinds of palindromes, see the tutorial on [our website](https://palindromes.science.uu.nl/smallsites/tutorial.html). + +## Requirements + +Palindromes has the following requirements: + +- [GHC] version 9.4.8 or later - It has been tested with version 9.4.8 and 9.8.2 +- [Cabal] library version 3.12.1 or later - It has been tested with this version + +[GHC]: http://www.haskell.org/ghc/ +[Cabal]: http://www.haskell.org/cabal/ + +## Download & Installation of the executable + +_If you have [cabal-install]_, you should use that to install the package, +because it will handle everything for you. + + cabal install exe:palindromes + +_If you don't have cabal-install_, you must download the [Palindromes package] +from HackageDB and install it manually. Get the `tar.gz` file and decompress it. + +Once downloaded, use the following commands for configuring, building, and +installing the library. + + runghc Setup.lhs configure + runghc Setup.lhs build + runghc Setup.lhs install + +For more details on the general options available, refer to the [Cabal User's +Guide]. + +[Palindromes package]: http://hackage.haskell.org/package/palindromes +[cabal-install]: http://www.haskell.org/haskellwiki/Cabal-Install +[Cabal User's Guide]: http://www.haskell.org/cabal/users-guide/ + +## Usage of the executable + +run the following commands, with changing `<path-to-file-or-directory>` to the file or directory of files containing the input, and `<options>` with the flags you want enabled +``` + palindromes <path-to-file-or-directory> -<options> +``` +Here are some examples of working flags, provided input.txt is a file in the same directory as the palindromes.cabal file: + +``` + palindromes input.txt + palindromes input.txt --quadratic --punctuation + palindromes input.txt -Q + palindromes input.txt -Q3+0 + palindromes input.txt -L --longest + palindromes input.txt -A0+2 --all --details --minlength=6 + palindromes -i --dna +``` + +To see all the options run one of these: + +``` + palindromes + palindromes -h + palindromes --help +``` + +If you want to see unicode characters in the output in a PowerShell terminal on Windows, try to use the following commands in the terminal: +``` + $OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8 +``` + +When working on the package in a code editor you can use: +``` + cabal run palindromes -- +``` +Instead of +``` + palindromes +``` + +## Usage of the library +If you want to use the palindromes library in your code, you probably want to use the finder functions in the Finder module. +These functions, like findPalindromes, return the found palindromes using the algorithms based on your arguments. + +If your datatype does not use the standard Eq relation for 'palindrome equality', you can define an instance of PalEq for +your datatype. For example, this is used for DNA, where A matches with T and G matches with C. +If you do not explicitly define a PalEq instance for your datatype, but you do define an Eq instance, the Eq instance is used. + +## Documentation + +The API is documented using [Haddock] and available per module on Hackage +site. + +[Haddock]: http://hackage.haskell.org/package/haddock +[Palindromes package]: http://hackage.haskell.org/package/palindromes + +## Licensing + +Palindromes is licensed under the so-called [BSD3 license]. See the included +`LICENSE` file. + +[BSD3 license]: http://www.opensource.org/licenses/bsd-license.php + +## Credits + +Palindromes is based on the functional program developed by [Johan Jeuring]. + +The current authors and maintainer of palindromes is [Johan Jeuring]. + +[Johan Jeuring]: http://www.jeuring.net/ + +## Copyright +This program has been developed by students from the bachelor Computer Science at Utrecht +University within the Software Project course. + +© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring
− RELEASE_HISTORY
@@ -1,68 +0,0 @@-Release history:-----------08072012 Version 0.4----------Cleaned up the options, to make them available for other kinds-of palindromes besides DNA palindromes. Code size has been reduced-by more than 40% by using higher-order functions and laziness to-properly deal with variability.-----------08072012 Version 0.3.2----------Only maximal palindromes are shown by the maximalEvenPalindromesLengthBetweenDNA-function.-----------03072012 Version 0.3.1----------Also showing length in DNA palindromes.-----------01072012 Version 0.3----------Uses Data.Bytestring instead of String-Includes functionality for determining palindromes in DNA-Added many flags for determining the length of the palindromes returned-----------19032012 Version 0.2.2.2----------Corrects a non-critical error in finalWordCentres-----------19032012 Version 0.2.2.1----------Corrects a link-----------17032012 Version 0.2.2----------Corrects the word palindromes solution-----------26122011 Version 0.2.1----------Updates base dependency from <=4 to <5-Uses latin1 character set for input files-----------10012010 Version 0.2----------Reads from standard input, via the flag -i-More flexible flag handling-Reads multiple files-Specifies minimum length of palindromes returned, via the flag -m int-----------07092009 Version 0.1.1----------Corrects two errors in the flags-----------06092009 Version 0.1----------First version of the package--
− Setup.lhs
@@ -1,4 +0,0 @@-#! /usr/bin/env runhaskell--> import Distribution.Simple-> main = defaultMain
+ app/FlagsToSettings.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE PatternGuards #-}++{- |+Module : FlagsToSettings+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module contains functions that are used to get settings from the flags.+-}+module FlagsToSettings+ ( getSettings+ , defaultSettings+ )+where++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ )+import Data.Algorithms.Palindromes.Settings (Settings (..))+import Options (Flag (..))++-- | If no flags are given to modify settings default settings are used+defaultSettings :: Settings+defaultSettings =+ Settings+ { algorithm = defaultAlgorithm+ , variant = defaultVariant+ , outputFormat = defaultOutputFormat+ , outputFilter = defaultOutputFilter+ , minLength = defaultMinLength+ }++defaultAlgorithm :: Algorithm+defaultAlgorithm = AlgQuadratic{algGapSize = 0, algMaxErrors = 0}++defaultVariant :: Variant+defaultVariant = VarText++defaultOutputFormat :: OutputFormat+defaultOutputFormat = FormatText++defaultOutputFilter :: OutputFilter+defaultOutputFilter = SelectLongest++defaultMinLength :: Int+defaultMinLength = 2++{- | Gets settings from the list of input flags. Uses default if no flags are given.+Evaluates all Settings records to WHNF using bang patterns to ensure all flags are valid+before calculation begins+-}+getSettings :: [Flag] -> Settings+getSettings flags =+ Settings+ { algorithm = alg+ , variant = var+ , outputFormat = fmt+ , outputFilter = flt+ , minLength = minL+ }+ where+ !alg = getAlgorithm flags+ !var = getVariant flags+ !fmt = getOutputFormat flags+ !flt = getOutputFilter flags+ !minL = getMinLength flags++ {- From all input flags, gets the algorithm setting. If more than one algorithm flag+ is given, it throws an error, as this is not suppported by our program. If none are give it+ uses the default option. -}+ getAlgorithm :: [Flag] -> Algorithm+ getAlgorithm xs+ | null algorithmFlags = defaultAlgorithm+ | [Algorithm a] <- algorithmFlags = a+ | otherwise = error "Multiple algorithm flags detected."+ where+ isAlgorithm :: Flag -> Bool+ isAlgorithm (Algorithm _) = True+ isAlgorithm _ = False+ algorithmFlags :: [Flag]+ algorithmFlags = filter isAlgorithm xs++ {- From all input flags, gets the variant setting. If more than one variant flag is+ given, it throws an error, as this is not suppported by our program. If none are give it+ uses the default option. -}+ getVariant :: [Flag] -> Variant+ getVariant xs+ | null variantFlags = defaultVariant+ | [Variant v] <- variantFlags = v+ | otherwise = error "Multiple variant flags detected."+ where+ isVariant :: Flag -> Bool+ isVariant (Variant _) = True+ isVariant _ = False+ variantFlags :: [Flag]+ variantFlags = filter isVariant xs++ {- From all input flags, gets the output format setting. If more than one output format+ flag is given, it throws an error, as this is not suppported by our program. If none are+ give it uses the default option. -}+ getOutputFormat :: [Flag] -> OutputFormat+ getOutputFormat xs+ | null outputFormatFlags = defaultOutputFormat+ | [OutputFormat o] <- outputFormatFlags = o+ | otherwise = error "Multiple outputFormat flags detected."+ where+ isOutputFormat :: Flag -> Bool+ isOutputFormat (OutputFormat _) = True+ isOutputFormat _ = False+ outputFormatFlags :: [Flag]+ outputFormatFlags = filter isOutputFormat xs++ {- From all input flags, gets the output filter setting. If more than one output filter+ flag is given, it throws an error, as this is not suppported by our program. If none are+ give it uses the default option. -}+ getOutputFilter :: [Flag] -> OutputFilter+ getOutputFilter xs+ | null outputFilterFlags = defaultOutputFilter+ | [OutputFilter o] <- outputFilterFlags = o+ | otherwise = error "Multiple outputFilter flags detected."+ where+ isOutputFilter :: Flag -> Bool+ isOutputFilter (OutputFilter _) = True+ isOutputFilter _ = False+ outputFilterFlags :: [Flag]+ outputFilterFlags = filter isOutputFilter xs++ {- From all input flags, gets the length modifier setting. If more than one length+ modifier flag is given, it throws an error, as this is not suppported by our program. If+ none are give it uses the default option. -}+ getMinLength :: [Flag] -> Int+ getMinLength xs+ | null minLengthFlags = defaultMinLength+ | [MinLength m] <- minLengthFlags = m+ | otherwise = error "Multiple minimum lengths found."+ where+ isMinLength (MinLength _) = True+ isMinLength _ = False+ minLengthFlags :: [Flag]+ minLengthFlags = filter isMinLength xs
+ app/Main.hs view
@@ -0,0 +1,130 @@+{- |+Module : Main+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++The starting point of the program which handles commandline/IO.+-}+module Main where++import Control.Monad (filterM)+import System.Console.GetOpt (ArgOrder (Permute), getOpt, usageInfo)+import System.Environment (getArgs)++import Data.Algorithms.Palindromes.Settings (applySettingsToFinder, checkSettingsWarnings)+import FlagsToSettings (getSettings)+import Options (Flag (..), options)++import qualified System.Directory as Dir+import qualified System.IO as Sys++-----------------------------------------------------------------------------+-- main+-----------------------------------------------------------------------------++{- |+ Read a single file+-}+handleFileWith :: (String -> IO String) -> String -> IO ()+handleFileWith f file = do+ putStrLn $ "Reading file: " ++ file+ file' <- Sys.openFile file Sys.ReadMode+ Sys.hSetEncoding file' Sys.utf8+ Sys.hSetEncoding Sys.stdout Sys.utf8+ input <- Sys.hGetContents file'+ res <- f input+ putStrLn $ '\r' : "Palindromes:" ++ replicate 40 ' ' ++ "\n" ++ res+ Sys.hClose file'+ putStrLn "--------------------------------------------------------------"++{- |+ Read all files in a directory. Ignore nested folders+-}+handleDirectoryWith :: (String -> IO String) -> String -> IO ()+handleDirectoryWith f dir = do+ print $ "Reading directory: " ++ dir+ content <- Dir.listDirectory dir+ let paths = map (\file -> dir ++ '/' : file) content+ files <- filterM Dir.doesFileExist paths+ handlePathsWith f files++{- |+ Read multiple paths, regardless of whether it's a file or directory+-}+handlePathsWith :: (String -> IO String) -> [String] -> IO ()+handlePathsWith f [] = do+ res <- f ""+ putStrLn $ "\r" ++ res ++ replicate 40 ' '+handlePathsWith f paths = handlePathsWith' f paths+ where+ -- Helper exists to not run algorithm on empty string after processing all other files+ handlePathsWith' _ [] = return ()+ handlePathsWith' f' (x : xs) = do+ handlePathWith f' x+ handlePathsWith' f' xs++{- |+ Read a path, regardless of whether it's a file or directory+-}+handlePathWith :: (String -> IO String) -> String -> IO ()+handlePathWith f path = do+ isFile <- Dir.doesFileExist path+ if isFile then handleFileWith f path else handleDirectoryWith f path++handleStandardInputWith :: (String -> IO String) -> IO ()+handleStandardInputWith function =+ do+ putStrLn "Write your input:"+ input <- getLine+ res <- function input+ putStrLn $ '\r' : "Palindromes:" ++ replicate 40 ' ' ++ "\n" ++ res+main :: IO ()+main = do+ args <- getArgs+ let (optionArgs, files, errors) = getOpt Permute options args+ if not (null errors)+ then putStrLn (concat errors)+ else+ let (function, standardInput) = handleFlags optionArgs (not $ null files)+ in if standardInput+ then handleStandardInputWith function+ else handlePathsWith function files+ where+ {- Based on input flags, gets a tuple with a function that directly encapsulates+ everything from the input string to the output string. Also encodes whether input string+ is from a file or standard input. -}+ handleFlags+ :: [Flag]+ -> Bool+ -> ( String -> IO String -- function from input to output+ , Bool -- if input is standard input+ )+ handleFlags flags hasFiles =+ ( if Help `elem` flags || (null flags && not hasFiles)+ then const $ return (usageInfo headerHelpMessage options)+ else \inputString -> do+ putStrLn $ checkSettingsWarnings settings+ applySettingsToFinder progressDisabled settings inputString+ , StandardInput `elem` flags+ )+ where+ progressDisabled = ProgressDisabled `elem` flags+ settings = getSettings flags++ -- The header of the help message.+ headerHelpMessage :: String+ headerHelpMessage =+ "*********************\n"+ ++ "* Palindrome Finder *\n"+ ++ "* version 1.0 *\n"+ ++ "*********************\n"+ ++ "Usage: \n"+ ++ "Either give the path to a file or directory or use the flag -i for manual input in the terminal. "+ ++ "The following flags can be used to change settings."
+ app/Options.hs view
@@ -0,0 +1,199 @@+{- |+Module : Options+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++Gives the options for flags that can be inputted in the command line and contains+functions for parsing to some flags.+-}+module Options (Flag (..), options) where++import Data.Maybe (fromJust, isNothing)+import System.Console.GetOpt+ ( ArgDescr (..)+ , OptDescr (..)+ )+import Text.Read (readMaybe)++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ )++data Flag+ = Help+ | StandardInput+ | Algorithm Algorithm+ | Variant Variant+ | OutputFormat OutputFormat+ | OutputFilter OutputFilter+ | MinLength Int+ | ProgressDisabled+ deriving (Eq)++-----------------------------------------------------------------------------+-- Options+-----------------------------------------------------------------------------++{- Options describe the input flags that can be used in the command line. -}+options :: [OptDescr Flag]+options =+ [ Option+ ['h']+ ["help"]+ (NoArg Help)+ "This message"+ , Option+ ['L']+ ["linear"]+ (NoArg (Algorithm AlgLinear))+ "Use the linear algorithm"+ , Option+ ['Q']+ ["quadratic"]+ (OptArg parseQuadratic "gapSize+maxErrors")+ "Use the quadratic algorithm (default). Optional arguments gapSize and maxErrors, default is 0."+ , Option+ ['A']+ ["approximate"]+ (OptArg parseApproximate "gapSize+maxErrors")+ "Use approximate algorithm. Optional arguments gapSize and maxErrors, default is 0."+ , Option+ ['R']+ ["plain", "regular"]+ (NoArg (Variant VarPlain))+ "plain (r for regular) palindrome"+ , Option+ []+ ["text"]+ (NoArg (Variant VarText))+ "Palindrome ignoring case, spacing and punctuation (default)"+ , Option+ ['P']+ ["punctuation"]+ (NoArg (Variant VarPunctuation))+ "Palindrome surrounded by punctuation (if any)"+ , Option+ ['W']+ ["word"]+ (NoArg (Variant VarWord))+ "Word palindrome"+ , Option+ ['D']+ ["dna"]+ (NoArg (Variant VarDNA))+ "DNA palindrome"+ , Option+ []+ ["textformat"]+ (NoArg (OutputFormat FormatText))+ "Output the text of the palindromes (default)"+ , Option+ ['l']+ ["length"]+ (NoArg (OutputFormat FormatLength))+ "Output the length of the palindromes"+ , Option+ ['r']+ ["range"]+ (NoArg (OutputFormat FormatRange))+ "Output the range of the palindromes"+ , Option+ ['d']+ ["details"]+ (NoArg (OutputFormat FormatAllDetails))+ "Output the text, range and length of the palindromes"+ , Option+ []+ ["longest"]+ (NoArg (OutputFilter SelectLongest))+ "Select only the longest palindromes, can be multiple of same length (default)"+ , Option+ ['a']+ ["all"]+ (NoArg (OutputFilter SelectAll))+ "Select all maximal palindromes"+ , Option+ ['c']+ ["center"]+ (ReqArg (OutputFilter . SelectAt . (read :: String -> Int)) "arg")+ "Find only the palindromes around the center [arg]"+ , Option+ ['m']+ ["minlength", "min"]+ (ReqArg (MinLength . (read :: String -> Int)) "arg")+ "Maximal palindromes of length at least [arg]. A value larger than 1 is strongly recommended to avoid trivial palindromes."+ , Option+ ['i']+ ["input"]+ (NoArg StandardInput)+ "Read input from standard input"+ , Option+ ['p']+ ["disable-progress"]+ (NoArg ProgressDisabled)+ "Disable the progress bar, this can help boost preformance."+ ]++{- | Parses the optional error and gap input to a Flag. If invalid inputs are given, an+error is thrown.+-}+parseApproximate :: Maybe String -> Flag+parseApproximate str+ | isNothing str = Algorithm AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ | null y =+ error $+ "Invalid arguments for -A/--approximate: \'"+ ++ fromJust str+ ++ "\'. Enter arguments as 2 numbers after seperated by a '+'. For example: '-A1+2'."+ | y == "+" =+ error $+ "Invalid arguments for -A/--approximate: \'"+ ++ fromJust str+ ++ "\'. Please enter second argument"+ | isNothing gapSize || isNothing maxErrors =+ error $+ "Invalid arguments for -A/--approximate: \'"+ ++ fromJust str+ ++ "\'. Arguments must be integers."+ | otherwise =+ Algorithm AlgApproximate{algGapSize = fromJust gapSize, algMaxErrors = fromJust maxErrors}+ where+ (x, y) = break (== '+') $ fromJust str+ (gapSize, maxErrors) = (readMaybe x, readMaybe (drop 1 y))++{- | Parses the optional error input to a Flag. If invalid inputs are given, an+error is thrown.+-}+parseQuadratic :: Maybe String -> Flag+parseQuadratic str+ | isNothing str = Algorithm AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ | null y =+ error $+ "Invalid arguments for -Q/--quadratic: \'"+ ++ fromJust str+ ++ "\'. Enter arguments as 2 numbers after seperated by a '+'. For example: '-Q1+2'."+ | y == "+" =+ error $+ "Invalid arguments for -Q/--quadratic: \'"+ ++ fromJust str+ ++ "\'. Please enter second argument"+ | isNothing gapSize || isNothing maxErrors =+ error $+ "Invalid arguments for -Q/--quadratic: \'"+ ++ fromJust str+ ++ "\'. Arguments must be integers."+ | otherwise =+ Algorithm AlgQuadratic{algGapSize = fromJust gapSize, algMaxErrors = fromJust maxErrors}+ where+ (x, y) = break (== '+') $ fromJust str+ (gapSize, maxErrors) = (readMaybe x, readMaybe (drop 1 y))
+ benchmarking/Main.hs view
@@ -0,0 +1,179 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE StandaloneDeriving #-}++{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module Main (main) where++import Control.DeepSeq (NFData)+import Criterion.Main (Benchmark, bench, bgroup, defaultConfig, defaultMainWith, env, nf)+import Criterion.Types (Config (..))+import Data.List (isSuffixOf)+import GHC.Generics (Generic)+import System.Directory (getDirectoryContents)+import System.FilePath (takeFileName)++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ , findPalindromes+ , findPalindromesFormatted+ )+import Data.Algorithms.Palindromes.Palindrome (Palindrome (..))++import qualified System.IO as Sys+import qualified System.IO.Strict as Strict++{- Next two lines allow for force evaluation of the Palindrome datatype to Normal Form+(NF) -}+deriving instance Generic Palindrome+deriving instance NFData Palindrome++-- | Benchmarks every file in the benchmarking-files folder+main =+ do+ textFiles <- getTextFiles+ let algorithmBenchmarks =+ bgroup "algorithm" $ map (`benchFile` benchAlgorithm) textFiles+ let textVariantBenchmarks =+ bgroup "text-variants" $ map (`benchFile` benchTextVariants) textFiles+ let outputBenchmarks =+ bgroup "output" $ map (`benchFile` benchOutputOptions) textFiles++ dnaFiles <- getDnaFiles+ let dnaBenchmarks = bgroup "dna" $ map (`benchFile` benchDna) dnaFiles++ defaultMainWith+ config+ [algorithmBenchmarks, textVariantBenchmarks, outputBenchmarks, dnaBenchmarks]++-- | Contains the location where we want the report file to be located+config :: Config+config = defaultConfig{reportFile = Just "benchmark-report.html"}++{- | Benchmark a single file with a function that does multiple benchmarks on that+file+-}+benchFile :: String -> (String -> [Benchmark]) -> Benchmark+benchFile filePath benchmarks =+ env (getFileContentUtf8 filePath) $+ \content ->+ bgroup (takeFileName filePath) (benchmarks content)++{- | Takes a string and creates a benchmark for every algorithm option of findPalindromes+on that string.+-}+benchAlgorithm :: String -> [Benchmark]+benchAlgorithm content =+ [ bench "quadratic" $+ nf+ (findPalindromes VarText (AlgQuadratic 0 0) 0)+ content+ , bench "linear" $+ nf+ (findPalindromes VarText AlgLinear 0)+ content+ , bench "approximate" $+ nf+ (findPalindromes VarText (AlgApproximate 0 0) 0)+ content+ ]++{- | Takes a string and creates a benchmark for every text based palindrome variant of+findPalindromes on that string.+-}+benchTextVariants :: String -> [Benchmark]+benchTextVariants content =+ [ bench "plain" $+ nf+ (findPalindromes VarPlain (AlgQuadratic 0 0) 0)+ content+ , bench "text" $+ nf+ (findPalindromes VarText (AlgQuadratic 0 0) 0)+ content+ , bench "punctuation" $+ nf+ (findPalindromes VarPunctuation (AlgQuadratic 0 0) 0)+ content+ , bench "word" $+ nf+ (findPalindromes VarWord (AlgQuadratic 0 0) 0)+ content+ ]++{- | Takes a string and creates a benchmark for every output option for+findPalindromesFormatted on that string.+-}+benchOutputOptions :: String -> [Benchmark]+benchOutputOptions content =+ [ bench "length" $+ nf+ (findPalindromesFormatted VarText FormatLength SelectLongest (AlgQuadratic 0 0) 0)+ content+ , bench "lengths" $+ nf+ (findPalindromesFormatted VarText FormatLength SelectAll (AlgQuadratic 0 0) 0)+ content+ , bench "word" $+ nf+ (findPalindromesFormatted VarText FormatText SelectLongest (AlgQuadratic 0 0) 0)+ content+ , bench "words" $+ nf+ (findPalindromesFormatted VarText FormatText SelectAll (AlgQuadratic 0 0) 0)+ content+ ]++{- | Takes a string and creates a benchmark for every output option for+findPalindromesFormatted on that string.+-}+benchDna :: String -> [Benchmark]+benchDna content =+ [ bench "plain" $+ nf+ (findPalindromes VarPlain (AlgQuadratic 0 0) 0)+ content+ , bench "dna" $+ nf+ (findPalindromes VarDNA (AlgQuadratic 0 0) 0)+ content+ , bench "odd gapped dna" $+ nf+ (findPalindromes VarDNA (AlgQuadratic 1 0) 0)+ content+ ]++getTextFiles :: IO [String]+getTextFiles = do+ files <- getDirectoryContentsWithPath "benchmarking/benchmarking-files/text-files"+ return $ filter (isSuffixOf ".txt") files++getDnaFiles :: IO [String]+getDnaFiles = do+ files <- getDirectoryContentsWithPath "benchmarking/benchmarking-files/dna-files"+ return $ filter (isSuffixOf ".txt") files++{- | Gets the file names of every file in the given directory and then prepends the+directory to the filepath+-}+getDirectoryContentsWithPath :: String -> IO [String]+getDirectoryContentsWithPath dir = do+ files <- getDirectoryContents dir+ return (map ((dir ++ "/") ++) files)++-- | Reads the content of a file in UTF-8 encoding, also sets UTF-8 as output encoding+getFileContentUtf8 :: String -> IO String+getFileContentUtf8 fileName = do+ handle <- Sys.openFile fileName Sys.ReadMode+ Sys.hSetEncoding handle Sys.utf8+ Sys.hSetEncoding Sys.stdout Sys.utf8+ content <- Strict.hGetContents handle+ Sys.hClose handle+ return content
+ changelog.md view
@@ -0,0 +1,105 @@+Release history: + +-------- +19062025 Version 1.0 +-------- +Features: +- Add approximate palindrome algorithm. +- Add benchmarking and profiling. +- Optimizations to the finding algorithms. +- Add --details and --ranges flags. +- Directory can now be input. +- Add progress bar. + +Fixes: +- Support odd gapped palindromes for DNA. +- Seperate executable from library. +- Improved flag names. +- Remove maxLength option. +- Rename 'Complexity' datatype to 'Algorithms' + +-------- +07042025 Version 0.5 +-------- +Does a big clean up of the whole package: +- Generalize the input data type. Any abstract data type of the PalEq class, with the (=:=) operator, can be the input for the palindrome finding algorithms. +- Define a new output type. This can be found in src\Data\Algorithms\Palindromes\Palindrome.hs. +- Rewrite functions to be clearer. +- Split the package into more modules. +- Split the pre- and post-processing from the algorithms themselves. This allows for adding more pre- and postprocessing easily in the future. +- Add Haddock documentation. Every function has a Haddock-style comment, allowing Haddock to make automatic documentation for the package. +- Add support for word palindromes. +- Change the way punctuation palindromes are found. Every punctuation palindrome is a substring of the maximal palindrome at the same center. So, we find punctuation palindromes easily by shrinking maximal palindromes until we have a punctuation palindrome, solving this problem with a post-processing solution. +- Add many unit tests. +- Add QuickCheck generators for texts with (large) palindromes and properties for palindromes. + +-------- +08072012 Version 0.4 +-------- +Cleaned up the options, to make them available for other kinds +of palindromes besides DNA palindromes. Code size has been reduced +by more than 40% by using higher-order functions and laziness to +properly deal with variability. + +-------- +08072012 Version 0.3.2 +-------- +Only maximal palindromes are shown by the maximalEvenPalindromesLengthBetweenDNA +function. + +-------- +03072012 Version 0.3.1 +-------- +Also showing length in DNA palindromes. + +-------- +01072012 Version 0.3 +-------- +Uses Data.Bytestring instead of String +Includes functionality for determining palindromes in DNA +Added many flags for determining the length of the palindromes returned + +-------- +19032012 Version 0.2.2.2 +-------- +Corrects a non-critical error in finalWordCentres + +-------- +19032012 Version 0.2.2.1 +-------- +Corrects a link + +-------- +17032012 Version 0.2.2 +-------- +Corrects the word palindromes solution + +-------- +26122011 Version 0.2.1 +-------- +Updates base dependency from <=4 to <5 +Uses latin1 character set for input files + +-------- +10012010 Version 0.2 +-------- +Reads from standard input, via the flag -i +More flexible flag handling +Reads multiple files +Specifies minimum length of palindromes returned, via the flag -m int + +-------- +07092009 Version 0.1.1 +-------- +Corrects two errors in the flags + +-------- +06092009 Version 0.1 +-------- +First version of the package + + +This program has been developed by students from the bachelor Computer Science at Utrecht +University within the Software Project course. + +© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring
palindromes.cabal view
@@ -1,47 +1,130 @@-name: palindromes-version: 0.4-synopsis: Finding palindromes in strings-homepage: http://www.jeuring.net/homepage/palindromes/index.html-description:-- palindromes is an executable and a library which takes a file name, and - returns information about palindromes in the file.--category: Algorithms-copyright: (c) 2007 - 2013 Johan Jeuring-license: BSD3-license-file: LICENSE-author: Johan Jeuring-maintainer: johan@jeuring.net-stability: experimental-extra-source-files: README,- CREDITS,- RELEASE_HISTORY- tests/Main.hs-build-type: Simple-cabal-version: >= 1.6-tested-with: GHC == 7.4.1-source-repository this- type: svn- location: https://svn.science.uu.nl/repos/sci.jeuri101.palindromes- tag: 0.4-----------------------------------------------------------------------------------Library- hs-source-dirs: src- exposed-modules: Data.Algorithms.Palindromes.Palindromes--Executable palindromes- Main-is: Data/Algorithms/Palindromes/Main.hs- ghc-options: -Wall -O2 -rtsopts -threaded- hs-source-dirs: src- other-modules: Data.Algorithms.Palindromes.Palindromes,- Data.Algorithms.Palindromes.PalindromesUtils,- Data.Algorithms.Palindromes.Options- build-depends: base >= 3.0 && < 5,- array,- bytestring,- containers-----------------------------------------------------------------------------------+cabal-version: 3.12 +name: palindromes +version: 1.0 +synopsis: Finding palindromes in strings +description: + palindromes is an executable and a library which takes a file name, and + returns information about palindromes in the file. + +category: Algorithms +copyright: + (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring + +license: BSD-3-Clause +license-file: LICENSE +author: + Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring + +maintainer: johan@jeuring.net +extra-doc-files: + changelog.md + CREDITS + README.md + +build-type: Simple +tested-with: GHC >=9.10 && <9.11 + +library + hs-source-dirs: src + default-language: Haskell2010 + exposed-modules: + Data.Algorithms.Palindromes.Algorithms + Data.Algorithms.Palindromes.ApproximateAlgorithm + Data.Algorithms.Palindromes.DNA + Data.Algorithms.Palindromes.Finders + Data.Algorithms.Palindromes.LinearAlgorithm + Data.Algorithms.Palindromes.Output + Data.Algorithms.Palindromes.PalEq + Data.Algorithms.Palindromes.Palindrome + Data.Algorithms.Palindromes.PostProcessing + Data.Algorithms.Palindromes.PreProcessing + Data.Algorithms.Palindromes.QuadraticAlgorithm + Data.Algorithms.Palindromes.RangeFunctions + Data.Algorithms.Palindromes.Settings + Data.Algorithms.Palindromes.Streaming + + build-depends: + , base >=4.17 && <5 + , conduit >=1.3 && <1.4 + , vector >=0.13 && <0.14 + +executable palindromes + main-is: Main.hs + ghc-options: -Wall -rtsopts + hs-source-dirs: app + default-language: Haskell2010 + build-depends: + , base >=4.17 && <5 + , directory >=1.3 && <1.4 + , palindromes + + -- Do not bound dependency on a library provided by the same package. + other-modules: + FlagsToSettings + Options + +test-suite tests-palindromes + type: exitcode-stdio-1.0 + hs-source-dirs: tests + main-is: Main.hs + default-language: Haskell2010 + other-modules: + ITApproximate + ITLinear + ITQuadratic + PalindromeMethods + QuickCheckGenerators + QuickCheckProperties + QuickCheckSettings + UTApproximateAlgorithm + UTDNAPals + UTExtendPals + UTFinders + UTGetLeftRight + UTLinearAlgorithm + UTPalEq + UTProcessing + UTPunctuationPals + UTQuadraticAlgorithm + UTTextPals + UTWordPals + + build-depends: + , base >=4.17 && <5 + , HUnit >=1.6 && <1.7 + , levenshtein >=0.2 && <0.3 + , palindromes + , QuickCheck >=2.14 && <3.0 + , vector >=0.13 && <0.14 + +benchmark benchmark + type: exitcode-stdio-1.0 + hs-source-dirs: benchmarking + main-is: Main.hs + default-language: Haskell2010 + build-depends: + , base >=4.17 && <5 + , criterion >=1.6 && <1.7 + , deepseq >=1.5 && <1.6 + , directory >=1.3 && <1.4 + , filepath >=1.5 && <1.6 + , palindromes + , strict >=0.3 && <0.6 + +benchmark profiling + type: exitcode-stdio-1.0 + hs-source-dirs: profiling + main-is: Main.hs + ghc-options: -rtsopts + default-language: Haskell2010 + build-depends: + , base >=4.17 && <5 + , deepseq >=1.5 && <1.6 + , directory >=1.3 && <1.4 + , filepath >=1.5 && <1.6 + , palindromes + , strict >=0.3 && <0.6 + +-- This program has been developed by students from the bachelor Computer Science at Utrecht +-- University within the Software Project course. +-- © Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring
+ profiling/Main.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE StandaloneDeriving #-}++{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++import Control.DeepSeq (NFData, force)+import Control.Exception (evaluate)+import GHC.Generics (Generic)++import Data.Algorithms.Palindromes.ApproximateAlgorithm (approximateAlgorithm)+import Data.Algorithms.Palindromes.Finders (Algorithm (..), Variant (..), findPalindromes)+import Data.Algorithms.Palindromes.Palindrome (Palindrome (..))++import qualified System.IO as Sys+import qualified System.IO.Strict as Strict++deriving instance Generic Palindrome+deriving instance NFData Palindrome++{- | The point of this build target is to have an easy way to+forcefully evaluate functions so you can analyse their result using profiling.++Currently it contains an example comparing the linear and quadratic implementation of the findPalindromes function.+The annotation {\-# SCC "linear" #-\} is used to create a cost centre within the profiling overview+with the label being linear.+-}+main :: IO ()+main = do+ as <-+ getFileContentLatin1 "benchmarking/benchmarking-files/text-files/aaaaaaaaaaaaaas.txt"++ _ <-+ {-# SCC "linear" #-}+ evaluate $ force $ findPalindromes VarText AlgLinear 0 as+ _ <-+ {-# SCC "quadratic" #-}+ evaluate $ force $ findPalindromes VarText (AlgQuadratic 0 0) 0 as+ _ <-+ {-# SCC "approximateAlgorithm" #-}+ evaluate $ force $ findPalindromes VarText (AlgApproximate 0 0) 0 as+ return ()++-- | Strictly loads the content of a file from Latin1 encoding+getFileContentLatin1 :: String -> IO String+getFileContentLatin1 fileName = do+ handle <- Sys.openFile fileName Sys.ReadMode+ Sys.hSetEncoding handle Sys.latin1+ content <- Strict.hGetContents handle+ Sys.hClose handle+ return content
+ src/Data/Algorithms/Palindromes/Algorithms.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE MonoLocalBinds #-}++{- |+Module : Data.Algorithms.Palindromes.Algorithms+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module exports three functions that run algorithms for finding palindromes.+One runs a linear time algorithms and the other a quadratic algorithm.+These assume text has been preprocessed.+-}+module Data.Algorithms.Palindromes.Algorithms+ ( linearAlgorithm+ , quadraticAlgorithm+ , approximateAlgorithm+ ) where++import Data.Algorithms.Palindromes.ApproximateAlgorithm (approximateAlgorithm)+import Data.Algorithms.Palindromes.LinearAlgorithm (extendPalindromeS)+import Data.Algorithms.Palindromes.PalEq (PalEq)+import Data.Algorithms.Palindromes.QuadraticAlgorithm+ ( gappedApproximatePalindromesAroundCentres+ )++import qualified Data.Vector.Generic as G++{- | Search for palindromes using the linear time algorithm. Returns a list of the maximum+length palindromes which were found at each center index in the input.+-}+linearAlgorithm+ :: (PalEq a, G.Vector v a)+ => Bool+ -- ^ isAntiReflexive, antireflexive types only need to check even indices+ -> v a+ -> [Int]+linearAlgorithm isAntiReflexive input =+ reverse $+ extendPalindromeS isAntiReflexive input 0 [] 0++{- | Search for palindromes using the quadratic algorithm. Returns a list of the maximum+length palindromes which were found at each center index in the input. Gaps allow the+palindrome to have a gap at the center of given length. Errors allow some substitution+mistakes in the palindrome.+-}+quadraticAlgorithm+ :: (PalEq a, G.Vector v a)+ => Bool+ -- ^ isAntiReflexive+ -> Int+ -- ^ gapSize+ -> Int+ -- ^ maxErrors+ -> v a+ -- ^ input+ -> [Int]+quadraticAlgorithm = gappedApproximatePalindromesAroundCentres
+ src/Data/Algorithms/Palindromes/ApproximateAlgorithm.hs view
@@ -0,0 +1,240 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE MonoLocalBinds #-}++{- |+Module : Data.Algorithms.Palindromes.ApproximateAlgorithm+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+++The approximate algorithm for finding maximal gapped approximate palindromes with a+maximum number of insertion, deletion and substitution errors. The main function is+approximateAlgorithm, which returns the ranges of the found maximal (gapped) approximate+palindromes.+-}+module Data.Algorithms.Palindromes.ApproximateAlgorithm (Cell (..), approximateAlgorithm, sparsify) where++import Data.Algorithms.Palindromes.PalEq (PalEq, (=:=))++import qualified Data.Vector.Generic as G++{- | Represents the range of the substring of the input string containing a palindrome.+Format: ([start index (inclusive)], [end index (exclusive)]).+-}+type PalRange = (Int, Int)++{- | Represents a cell in the matrix. Each cell corresponds to some substring of the input+string. The row is the index of the first character (inclusive) and the column is the+index of the last character (inclusive) of the substring.+-}+data Cell = Cell+ { cellColumn :: Int+ , cellBudget :: Budget+ }+ deriving (Show, Eq)++-- | Represents a row in the matrix.+type Row = [Cell]++{- | The budget of a cell is the number of errors that can be added to the substring the+cell corresponds to without exceeding the maximum number of errors.+-}+type Budget = Int++{- | Find all maximal gapped approximate palindromes with a certain gap and a certain+maximum number of errors.+-}+approximateAlgorithm+ :: (PalEq a, G.Vector v a)+ => Int+ -- ^ The size of the gap+ -> Int+ -- ^ The maximum number of errors+ -> v a+ -- ^ The input vector+ -> [PalRange]+ -- ^ The list of found maximal gapped approximate palindromes+approximateAlgorithm gapSize maxErrors input = concatMap (\(_, palRanges, _) -> palRanges) states+ where+ -- Bound the used gapSize to not be more than the length of the input.+ gapSize' = min gapSize (G.length input)+ -- Use takeIterations to get the states for efficiency.+ states = takeIterations nrOfIterations (fillRow input gapSize' maxErrors) startState+ {- Required number of iterations is (+ 2) to also be able to spot maximal palindromes+ in the two upper rows. -}+ nrOfIterations = maxRow + 2+ startState =+ (+ [ Cell+ { {- We start the matrix on the bottom right, so at the last index of the+ input. -}+ cellColumn = lastIndex+ , -- This cell corresponds to an empty substring, so it has no errors.+ cellBudget = maxErrors+ }+ ] -- This defines the entire bottom row of the matrix.+ , [] -- no maximal palindromes found yet.+ , maxRow - 1 -- row number of the row above the bottom row of the matrix.+ )+ lastIndex = G.length input - 1+ -- The index of the last row, adjusted with the gap size to ignore errors in the gap.+ maxRow = lastIndex - gapSize' + 1++-- | Fills the next row and finds maximal palindromes in the previous row+fillRow+ :: (PalEq a, G.Vector v a)+ => v a+ -- ^ Input vector+ -> Int+ -- ^ Maximum size of the gap+ -> Int+ -- ^ Maximum number of errors+ -> (Row, [PalRange], Int)+ -- ^ Old state+ -> (Row, [PalRange], Int)+ -- ^ New state+fillRow input gapSize maxErrors (row, _, rowIndex) =+ (firstCell ++ newRow, foundMaxPals, rowIndex - 1)+ where+ {- The first cell of the current row. A new cell needs to be added at+ the start of this row because we don't add one in the evaluatePosition part+ and every row has one more cell to the left than the previous row. -}+ firstCell+ | initialColumn >= 0 = [Cell{cellColumn = initialColumn, cellBudget = initialBudget}]+ | otherwise = []++ -- The initial column is directly to the left of the diagonal on this row.+ initialColumn = rowIndex + gapSize - 1++ -- The budget of the first cell of this row+ initialBudget :: Budget+ initialBudget+ {- For rows or columns out of bounds, the first cell of the previous row has no+ budget left, because it represents an invalid substring. -}+ | rowIndex < 0 || initialColumn >= G.length input = -1+ {- In general, the first cell of the previous row has a budget of maxErrors,+ because it represent an empty substring, which has no errors. -}+ | otherwise =+ maxErrors++ -- Sparsify the previous row.+ sparsePrevRow =+ sparsify row++ {- EvaluatePosition generates tuples with the cell at a position as the+ second element and in the third position the cell to the bottomleft of the evaluated position as a found+ gapped approximate maximal palindrome if it is one. We concat map these so we only traverse once,+ by compiler optimisation. We thus find the new row and the the updated found palindromes.+ -}+ scannedRow =+ drop 1 $+ scanl (evaluatePosition input rowIndex) ((maxErrors, maxErrors), [], []) sparsePrevRow+ newRow = concatMap (\(_, rowSegment, _) -> rowSegment) scannedRow+ foundMaxPals = concatMap (\(_, _, palRanges) -> palRanges) scannedRow++{- | Define a new cell (the cell above the input cell) with the correct budget and add+bottom left cell to maxPals if it is maximal.++Consider the following matrix:++@+------------------------------+| topLeft topRight |+| bottomLeft bottomRight |+------------------------------+@++We want to define the budget in topRight and check whether bottomLeft is maximal.+-}+evaluatePosition+ :: (PalEq a, G.Vector v a)+ => v a+ -- ^ Input vector+ -> Int+ -- ^ row index+ -> ((Budget, Budget), Row, [PalRange])+ -- ^ Old state+ -> Cell+ -- ^ Input cell+ -> ((Budget, Budget), Row, [PalRange])+ -- ^ New state+evaluatePosition input rowIndex ((topLeft, bottomLeft), _, _) (Cell{cellColumn = column, cellBudget = bottomRight}) =+ ((topRight, bottomRight), [Cell column topRight], maxpals)+ where+ topRight+ | rowIndex >= 0 && column < G.length input =+ maximum+ [ topLeft - 1+ , bottomRight - 1+ , bottomLeft - errorCostAtPosition input (rowIndex, column)+ ]+ | otherwise = -1+ maxpals+ {- add (+ 1) to get inclusive start index and exclusive end index for the found+ maximal palindromes -}+ | bottomLeft >= 0 && topLeft < 0 && topRight < 0 && bottomRight < 0 =+ [(rowIndex + 1, column)]+ | otherwise = []++{- | Replace long sequences of cells with (-1) budgets with two cells with (-1) budgets,+one on either end of the sequence.+-}+sparsify :: Row -> Row+sparsify [] = []+sparsify row@(Cell{cellColumn = firstColumnIndex, cellBudget = _} : _) = sparseRow+ where+ -- due to haskells lazy evaluation this only traverses the list once.+ sparseRow =+ -- Extracts the sparsified row by concatmapping all the second elements of the accumulator+ concatMapWithEndFunction snd getFinalCell $+ -- We filter the negatives from the row and add back negatives at positions at the+ scanl insertNegatives (firstColumnIndex, []) (filter ((>= 0) . cellBudget) row)++ insertNegatives :: (Int, Row) -> Cell -> (Int, Row)+ insertNegatives (lastind, _) newCell@Cell{cellColumn = newIndex}+ -- Place two cells on either side of the sequence of negative budgets.+ | newIndex - lastind > 2 =+ ( newIndex+ ,+ [ Cell{cellColumn = lastind + 1, cellBudget = -1}+ , Cell{cellColumn = newIndex - 1, cellBudget = -1}+ , newCell+ ]+ )+ -- Add one cell with (-1) budget back after it has apparently been filtered out before.+ | newIndex - lastind == 2 =+ (newIndex, [Cell{cellColumn = lastind + 1, cellBudget = -1}, newCell])+ -- Do nothing.+ | otherwise = (newIndex, [newCell])++ -- We always must add one -1 to the end of the sparsified row+ getFinalCell (lastPositiveColumnIndex, _) =+ [Cell{cellColumn = lastPositiveColumnIndex + 1, cellBudget = -1}]++ -- concatMap but we also apply an "end function" to the final element+ concatMapWithEndFunction _ _ [] = []+ concatMapWithEndFunction f endf [s] = f s ++ endf s+ concatMapWithEndFunction f endf (s : x : t) =+ f s+ ++ concatMapWithEndFunction+ f+ endf+ (x : t)++-- | Returns first n elements of iterate f on start.+takeIterations :: Int -> (a -> a) -> a -> [a]+takeIterations n f start = take n $ iterate f start++{- If elements are palindrome equal at position then no error cost, otherwise error cost+of 1 for a substitution error. -}+errorCostAtPosition :: (PalEq a, G.Vector v a) => v a -> (Int, Int) -> Int+errorCostAtPosition input (row, column)+ | (input G.! row) =:= (input G.! column) = 0+ | otherwise = 1
+ src/Data/Algorithms/Palindromes/DNA.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}++{- |+Module : Data.Algorithms.Palindromes.DNA+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module contains the DNA datatype and corresponding functions.+This type encodes a representation for DNA that can be used as input for finding+palindromes.+-}+module Data.Algorithms.Palindromes.DNA where++import Data.Char (toUpper)+import Data.Maybe (fromJust, isNothing)+import Data.Word (Word8)++import Data.Algorithms.Palindromes.PalEq (PalEq (..))++import qualified Data.Vector.Generic as G (Vector (..))+import qualified Data.Vector.Generic.Mutable as GM (MVector (..))+import qualified Data.Vector.Unboxed as U (MVector, Unbox, Vector, any, map)++{- | Datatype for the different DNA, note that (=)/Eq is not suitable for checking if DNA+ has palindromes, instead PalEq should be used.+-}+data DNA = A | T | C | G | N deriving (Show, Eq, Enum)++newtype instance U.MVector s DNA = MV_DNA (U.MVector s Word8)+newtype instance U.Vector DNA = V_DNA (U.Vector Word8)++instance GM.MVector U.MVector DNA where+ {-# INLINE basicLength #-}+ basicLength (MV_DNA v) = GM.basicLength v+ {-# INLINE basicUnsafeSlice #-}+ basicUnsafeSlice a b (MV_DNA v) = MV_DNA $ GM.basicUnsafeSlice a b v+ {-# INLINE basicOverlaps #-}+ basicOverlaps (MV_DNA a) (MV_DNA b) = GM.basicOverlaps a b+ {-# INLINE basicUnsafeNew #-}+ basicUnsafeNew i = MV_DNA <$> GM.basicUnsafeNew i+ {-# INLINE basicInitialize #-}+ basicInitialize (MV_DNA v) = GM.basicInitialize v+ {-# INLINE basicUnsafeRead #-}+ basicUnsafeRead (MV_DNA v) i = toEnum . fromIntegral <$> GM.basicUnsafeRead v i+ {-# INLINE basicUnsafeWrite #-}+ basicUnsafeWrite (MV_DNA v) i = GM.basicUnsafeWrite v i . fromIntegral . fromEnum++instance G.Vector U.Vector DNA where+ {-# INLINE basicUnsafeFreeze #-}+ basicUnsafeFreeze (MV_DNA v) = V_DNA <$> G.basicUnsafeFreeze v+ {-# INLINE basicUnsafeThaw #-}+ basicUnsafeThaw (V_DNA v) = MV_DNA <$> G.basicUnsafeThaw v+ {-# INLINE basicLength #-}+ basicLength (V_DNA v) = G.basicLength v+ {-# INLINE basicUnsafeSlice #-}+ basicUnsafeSlice a b (V_DNA v) = V_DNA $ G.basicUnsafeSlice a b v+ {-# INLINE basicUnsafeIndexM #-}+ basicUnsafeIndexM (V_DNA v) i = toEnum . fromIntegral <$> G.basicUnsafeIndexM v i++instance U.Unbox DNA++-- | Declare instance PalEq for DNA. A and T form a couple, C and G form a couple.+instance {-# OVERLAPPING #-} PalEq DNA where+ A =:= T = True+ T =:= A = True+ G =:= C = True+ C =:= G = True+ _ =:= _ = False++{- | Parsed a foldable with chars to a foldable with the DNA datatype. Returns Nothing if+ the input cannot be fully parsed to DNA.+-}+toDNA :: U.Vector Char -> Maybe (U.Vector DNA)+toDNA x+ | hasNothing = Nothing+ | otherwise = Just $ U.map (fromJust . charToDNA) x+ where+ hasNothing = U.any (isNothing . charToDNA) x++-- | Parses a single Char to the DNA datatype. Returns Nothing if this is not possible.+charToDNA :: Char -> Maybe DNA+charToDNA 'A' = Just A+charToDNA 'T' = Just T+charToDNA 'C' = Just C+charToDNA 'G' = Just G+charToDNA 'U' = Just T+charToDNA 'a' = Just A+charToDNA 't' = Just T+charToDNA 'c' = Just C+charToDNA 'g' = Just G+charToDNA 'u' = Just T+charToDNA c+ | toUpper c `elem` "RYKMSWBDHVN" = Just N+ | otherwise = Nothing++-- | Converts the DNA datatype to the corresponding Char symbol+dnaToChar :: DNA -> Char+dnaToChar A = 'A'+dnaToChar T = 'T'+dnaToChar G = 'G'+dnaToChar C = 'C'+dnaToChar N = 'N'
+ src/Data/Algorithms/Palindromes/Finders.hs view
@@ -0,0 +1,238 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MonoLocalBinds #-}++{- |+Module : Data.Algorithms.Palindromes.Finders+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module is the core of this package and contains the functions that find palindromes.+Most useful perhaps is the findPalindromesFormatted which also formats the palindrome+based on the outputFormat data type as described in this module. For more statistics the+findPalindromes which outputs a palindrome can be used.+-}+module Data.Algorithms.Palindromes.Finders+ ( findPalindromes+ , findPalindromeRanges+ , findPalindromesFormatted+ , formatPalindromes+ , Variant (..)+ , OutputFormat (..)+ , OutputFilter (..)+ , Algorithm (..)+ , filterPalindromes+ ) where++-- This import might throw a compiler warnings on GHC version 9.12 or higher,+-- but the import is necessary on older versions.+import Data.List (foldl')++import Data.Algorithms.Palindromes.Algorithms+ ( approximateAlgorithm+ , linearAlgorithm+ , quadraticAlgorithm+ )+import Data.Algorithms.Palindromes.Output+ ( indicesInOutputText+ , indicesInOutputWord+ , longest+ , rangeToText+ , showAll+ , showLengths+ , showRanges+ , showTexts+ )+import Data.Algorithms.Palindromes.PalEq (PalEq)+import Data.Algorithms.Palindromes.Palindrome (Palindrome (..))+import Data.Algorithms.Palindromes.PostProcessing (filterPunctuation)+import Data.Algorithms.Palindromes.PreProcessing+ ( filterLetters+ , filterLetters'+ , textToWords+ , textToWordsWithIndices+ , tryParseDNA+ )+import Data.Algorithms.Palindromes.RangeFunctions+ ( Range+ , indexedLengthToRange+ , rangeToLength+ , rangeToPalindromeCenter+ )++import qualified Data.Vector.Generic as G+import qualified Data.Vector.Unboxed as U++{- | Used as a setting for palindrome finding functions. This describes the kind of+palindrome we want to find.+-}+data Variant+ = -- | Convert the text to DNA, then match A with T and G with C.+ VarDNA+ | {- | Find text palindromes, then shrink each palindrome until it is surrounded by+ punctuation so that no palindrome can contain only part of a word.+ -}+ VarPunctuation+ | -- | Find palindromes only based on letters, ignore all other characters.+ VarText+ | -- | Find palindromes in the text exactly as it was given.+ VarPlain+ | -- | Compare words instead of individual characters to look for palindromes.+ VarWord+ deriving (Eq, Show)++{- | Used to describe different possible output formats of palindromes. Used as a setting+in finding functions.+-}+data OutputFormat+ = -- | Output the length of the palindromes+ FormatLength+ | -- | Output palindrome as text+ FormatText+ | -- | Output the ranges of the palindromes+ FormatRange+ | -- | Output all details: Text, range and length+ FormatAllDetails+ deriving (Eq, Show)++data OutputFilter+ = -- | Select longest (can be multiple of same length)+ SelectLongest+ | -- | Select to only keep palindromes with certain center position+ SelectAt Int+ | -- | Select all palindromes+ SelectAll+ deriving (Eq, Show)++{- | Used as a setting for what algorithm to run. The quadratic algorithm also has+functionality for including gaps and errors, therefore this is given as an extra setting.+-}+data Algorithm+ = AlgLinear+ | AlgQuadratic {algGapSize :: Int, algMaxErrors :: Int}+ | AlgApproximate {algGapSize :: Int, algMaxErrors :: Int}+ deriving (Eq, Show)++{- | This method returns whether uneven palindromes are impossible to exist based on the+query settings.+-}+onlyEvenPals :: Variant -> Algorithm -> Bool+onlyEvenPals VarDNA (AlgQuadratic gapSize _) = even gapSize+onlyEvenPals VarDNA AlgLinear = True+onlyEvenPals _ _ = False++{- | This function combines three phases based on the settings and input given: The+pre-processing phase, the algorithm phase and the post-processing phase. It finds and+returns a list of ranges of every found palindrome in the input.+-}+findPalindromeRanges+ :: Variant -> Algorithm -> U.Vector Char -> [Range]+findPalindromeRanges variant algorithm input =+ (post . preAlg) input+ where+ {- The pre-processing phase parses the text input based on the Variant provided to a+ vector of PalEq items. -}+ preAlg :: U.Vector Char -> [Range]+ preAlg = case variant of+ VarText -> alg . filterLetters+ VarPunctuation -> alg . filterLetters+ VarDNA -> alg . tryParseDNA+ VarWord -> alg . textToWords+ _ -> alg++ {- The algorithm phase runs one of the algorithms that finds the ranges, since the linear and quadratic+ find indexLists we must convert these to ranges. -}+ alg :: (PalEq b, G.Vector v b) => v b -> [Range]+ alg = case algorithm of+ AlgLinear -> indexListToRanges . linearAlgorithm (onlyEvenPals variant algorithm)+ AlgQuadratic gapSize maxErrors ->+ indexListToRanges+ . quadraticAlgorithm+ (onlyEvenPals variant algorithm)+ gapSize+ maxErrors+ AlgApproximate gapSize maxErrors -> approximateAlgorithm gapSize maxErrors++ indexListToRanges :: [Int] -> [Range]+ indexListToRanges = go 0+ where+ go _ [] = []+ -- This code adds indexes for the indexedLengthToRange function to calculate the ranges+ -- This implementation is preferred over using list generators for performance reasons+ go !i (x : xs) = indexedLengthToRange (i, x) : go (i + increment) xs+ increment+ | onlyEvenPals variant algorithm = 2+ | otherwise = 1++ {- The post-processing phase changes the list of ranges so that they fit the+ requirements in the case of punctuation palindromes -}+ post :: [Range] -> [Range]+ post = case variant of+ VarPunctuation -> filterPunctuation input+ _ -> id++{- | This function combines all the phases required to find palindromes.+It first finds all the palindrome ranges based on the settings,+then filters them by length and finally converts the found ranges to the Palindrome datatype+-}+findPalindromes :: Variant -> Algorithm -> Int -> String -> [Palindrome]+findPalindromes variant algorithm minlen input =+ map rangeToPalindrome $ filterRanges $ findPalindromeRanges variant algorithm inputVector+ where+ rangeToPalindrome :: Range -> Palindrome+ rangeToPalindrome r =+ Palindrome+ { palRange = r+ , palText = rangeToText (indicesInOriginal r) inputVector+ , palRangeInText = indicesInOriginal r+ }++ filterRanges :: [Range] -> [Range]+ filterRanges = filter ((>= minlen) . rangeToLength)++ -- Takes a range in the pre-processed input and returns the range in the original input.+ indicesInOriginal :: Range -> Range+ indicesInOriginal range = case variant of+ VarText -> indicesInOutputText range inputLength (filterLetters' inputVector)+ VarPunctuation -> indicesInOutputText range inputLength (filterLetters' inputVector)+ VarDNA -> indicesInOutputText range inputLength (filterLetters' inputVector)+ VarPlain -> range+ VarWord -> indicesInOutputWord range inputLength (textToWordsWithIndices inputVector)+ !inputVector = U.fromList input+ !inputLength = U.length inputVector++{- | This function combines four phases based on the settings and input given: The+pre-processing, the algorithm phase, the post processing phase, the parsing phase and the+output phase. The final phase takes the filter and format flags into account and returns a+String that can be printed. It return the palindrome found using the settings, formatted+to the given filter and format.+-}+findPalindromesFormatted+ :: Variant -> OutputFormat -> OutputFilter -> Algorithm -> Int -> String -> String+findPalindromesFormatted variant outputFormat outputFilter algorithm minlen input =+ formatPalindromes outputFormat $+ filterPalindromes outputFilter $+ findPalindromes variant algorithm minlen input++filterPalindromes :: OutputFilter -> [Palindrome] -> [Palindrome]+filterPalindromes outputFilter = case outputFilter of+ -- reverse foldl' is more efficient in memory than foldr+ -- This is because know the fold can be applied as soon as the result of the algorithm is computed+ -- With foldr we would first have to compute the entire list before we can apply the filter+ SelectLongest -> reverse . foldl' longest []+ SelectAt n -> filter ((== n) . rangeToPalindromeCenter . palRange)+ SelectAll -> id++formatPalindromes :: OutputFormat -> [Palindrome] -> String+formatPalindromes _ [] = "No palindromes found"+formatPalindromes outputFormat pals = case outputFormat of+ FormatLength -> showLengths pals+ FormatText -> showTexts pals+ FormatRange -> showRanges pals+ FormatAllDetails -> showAll pals
+ src/Data/Algorithms/Palindromes/LinearAlgorithm.hs view
@@ -0,0 +1,195 @@+{-# LANGUAGE MonoLocalBinds #-}++{- |+Module : Data.Algorithms.Palindromes.LinearAlgorithm+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module contains an implementation of a linear algorithm to find palindromes.+-}+module Data.Algorithms.Palindromes.LinearAlgorithm+ ( extendPalindromeS+ , finalPalindromesS+ , moveCenterS+ ) where++import Data.Algorithms.Palindromes.PalEq (PalEq (..), palEqToItselfAtIndex)++import qualified Data.Vector.Generic as G++-- | This function traverses input linearly, using an accumulator.+extendPalindromeS+ :: (PalEq a, G.Vector v a)+ => Bool+ -- ^ indicates whether the input datatype is anti-reflexive+ -> v a+ -- ^ input, with only the elements we want to find palindromes in+ -> Int+ -- ^ the rightmost index which is checked by the algorithm+ -> [Int]+ -- ^ length of palindromes that are already found+ -> Int+ -- ^ the length of the palindrome currently being expanded+ -> [Int]+ -- ^ the final list of maximal palindrome lengths+extendPalindromeS onlyEvenPals input rightmost maximalPalindromesIn currentPalindrome+ | rightmost > lastPos =+ -- reached the end of the array+ finalPalindromesS+ onlyEvenPals+ currentPalindrome+ maximalPalindromesIn+ (currentPalindrome : maximalPalindromesIn)+ | rightmost - currentPalindrome == first+ || not ((input G.! rightmost) =:= (input G.! (rightmost - currentPalindrome - 1))) =+ -- the current palindrome extends to the start of the array, or it cannot be+ -- extended+ moveCenterS+ onlyEvenPals+ input+ rightmost+ (currentPalindrome : maximalPalindromesIn)+ maximalPalindromesIn+ currentPalindrome+ | otherwise =+ -- the current palindrome can be extended+ extendPalindromeS+ onlyEvenPals+ input+ (rightmost + 1)+ maximalPalindromesIn+ (currentPalindrome + 2)+ where+ first = 0 -- first index of the input+ lastPos = G.length input - 1 -- last index of the input++-- | If the current palindrome cannot be extended anymore, this function will move the centers one step+moveCenterS+ :: (PalEq a, G.Vector v a)+ => Bool+ -- ^ indicates whether the input datatype is anti-reflexive+ -> v a+ -- ^ input, with only the elements we want to find palindromes in+ -> Int+ -- ^ the rightmost index which is checked by the algorithm+ -> [Int]+ -- ^ length of all maximal palindromes that are already found+ -> [Int]+ {- ^ length of maximal palindromes that are already found, where head is always the+ maximal palindrome at the 'mirrored' index+ -}+ -> Int+ -- ^ the number of centers moveCenterS still has to find maximal palindromes for+ -> [Int]+ -- ^ the final list of maximal palindrome lengths+moveCenterS+ antiReflexive+ input+ rightmost+ maximalPalindromesIn+ maximalPalindromesIn'+ nrOfCenters+ | nrOfCenters == 0 =+ -- the last centre is on the last element: try to extend the tail+ let (newPalLength, inputForExtend) =+ case (antiReflexive, palEqToItselfAtIndex input rightmost) of+ {- Non-anti-reflexive type, but element at `rightmost` is not+ PalEq to itself. We found an empty maximal palindrome. Add it to+ the list and continue searching. -}+ (False, False) -> (0, 0 : maximalPalindromesIn)+ {- Non-anti-reflexive type, element at `rightmost` is+ PalEq to itself. Found a palindrome of at least length 1, so try to+ extend it. -}+ (False, True) -> (1, maximalPalindromesIn)+ {- Anti-reflexive type: only centers between elements matter. We+ assume an empty palindrome and continue extending. -}+ (True, _) -> (0, maximalPalindromesIn)+ in extendPalindromeS+ antiReflexive+ input+ (rightmost + 1)+ inputForExtend+ newPalLength+ | otherwise =+ {- move the centres one step and add the length of the longest palindrome to+ the centres -}+ case maximalPalindromesIn' of+ (headq : tailq) ->+ if headq == nrOfCenters - centerfactor+ then+ {- The previous element in the centre list reaches exactly to the end of the+ last tail palindrome. Use the mirror property of palindromes to find the+ longest tail palindrome -}+ extendPalindromeS+ antiReflexive+ input+ rightmost+ maximalPalindromesIn+ (nrOfCenters - centerfactor)+ else+ {- move the centres one step and add the length of the longest palindrome to+ the centres -}+ moveCenterS+ antiReflexive+ input+ rightmost+ (min headq (nrOfCenters - centerfactor) : maximalPalindromesIn)+ tailq+ (nrOfCenters - centerfactor)+ [] -> error "extendPalindromeS: empty sequence"+ where+ {- If type is anti-reflexive, we can skip centers on elements, so take steps of+ size 2. -}+ centerfactor+ | antiReflexive = 2+ | otherwise = 1++{- | After the current palindrome reached the end of the input vector, this function will+find and return the final palindromes using the pal in pal property.+-}+finalPalindromesS+ :: Bool+ -- ^ indicates whether the input datatype is anti-reflexive.+ -> Int+ -- ^ number of centers that haven't been extended yet.+ -> [Int]+ {- ^ list of found palindrome lengths, where the head corresponds to the value which+ must be copied next.+ -}+ -> [Int]+ {- ^ the lengths of all the palindromes that are found, including palindromes found by+ this function. This is used as an accumulator.+ -}+ -> [Int]+ -- ^ the lengths of all found maximal palindromes in reverse order.+finalPalindromesS antiReflexive nrOfCenters maximalPalindromesIn acc+ | nrOfCenters == 0 =+ acc+ | nrOfCenters > 0 =+ case maximalPalindromesIn of+ (p : ps) ->+ {- for a center, add the (truncated) copied palindrome to the accumulator+ and recurse over nrOfCenters. -}+ finalPalindromesS+ antiReflexive+ (nrOfCenters - centerfactor)+ ps+ {- the palindrome cannot be bigger than the remaining number of+ centers minus the centerfactor. Truncate the palindrome if necessary.+ -}+ (min p (nrOfCenters - centerfactor) : acc)+ [] -> error "finalPalindromesS: empty sequence"+ | otherwise = error "finalPalindromesS: input < 0"+ where+ {- If type is anti-reflexive, we can skip centers on elements, so take steps of+ size 2. -}+ centerfactor+ | antiReflexive = 2+ | otherwise = 1
− src/Data/Algorithms/Palindromes/Main.hs
@@ -1,54 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Data.Algorithms.Palindromes.Main--- Copyright : (c) 2007 - 2013 Johan Jeuring--- License : BSD3------ Maintainer : johan@jeuring.net--- Stability : experimental--- Portability : portable----------------------------------------------------------------------------------module Main where--import System.Environment (getArgs)-import System.Console.GetOpt -import System.IO--import qualified Data.ByteString as B--import Data.Algorithms.Palindromes.Options---------------------------------------------------------------------------------- main--------------------------------------------------------------------------------handleFilesWith :: (B.ByteString -> String) -> [String] -> IO ()-handleFilesWith f [] = putStr $ f undefined -handleFilesWith f xs = - let hFW filenames = - case filenames of- [] -> putStr ""- (fn:fns) -> do fn' <- openFile fn ReadMode- hSetEncoding fn' latin1 - input <- B.hGetContents fn' - putStrLn (f input)- hClose fn'- hFW fns- in hFW xs --handleStandardInputWith :: (B.ByteString -> String) -> IO ()-handleStandardInputWith function = - do input <- B.getContents- putStrLn (function input) --main :: IO ()-main = do args <- getArgs- let (optionArgs,files,errors) = getOpt Permute options args- if not (null errors) - then putStrLn (concat errors) - else let (function,standardInput) = handleOptions optionArgs- in if standardInput - then handleStandardInputWith function - else handleFilesWith function files -
− src/Data/Algorithms/Palindromes/Options.hs
@@ -1,234 +0,0 @@--- Did not yet translate all options. Complete the table in dispatchFlags.--- Default doesn't work yet------------------------------------------------------------------------------------- Module : Data.Algorithms.Palindromes.Options--- Copyright : (c) 2007 - 2013 Johan Jeuring--- License : BSD3------ Maintainer : johan@jeuring.net--- Stability : experimental--- Portability : portable----------------------------------------------------------------------------------module Data.Algorithms.Palindromes.Options where--import System.Console.GetOpt --import qualified Data.ByteString as B--import Data.Algorithms.Palindromes.PalindromesUtils (Flag(..))-import Data.Algorithms.Palindromes.Palindromes (palindrome,dnaLengthGappedApproximatePalindromeAround)---------------------------------------------------------------------------------- Options---------------------------------------------------------------------------------- I am using single letter options here (except for help): getOpt handles --- options too flexible: in case a letter within a multiple letter option is --- recognized, it is taken as a single letter option.-options :: [OptDescr Flag] -options = - [Option "h" ["help"] (NoArg Help)- "This message"- ,Option "p" [] (NoArg Plain) - "Plain palindrome (default)"- ,Option "t" [] (NoArg Text)- "Palindrome ignoring case, spacing and punctuation"- ,Option "w" [] (NoArg Word)- "Palindrome surrounded by punctuation (if any)"- ,Option "d" [] (NoArg DNA)- "DNA palindrome"- ,Option "l" [] (NoArg Longest)- "Longest palindrome (deafult)"- ,Option "e" [] (NoArg LengthLongest)- "Length of the longest palindrome"- ,Option "m" [] (NoArg Maximal)- "Maximal palindrome around each position in the input"- ,Option "a" [] (NoArg LengthMaximal)- "Length of the maximal palindrome around each position in the input"- ,Option "g" [] (ReqArg (Gap . (read :: String -> Int)) "arg")- "Allow a gap of length [arg] in the palindrome"- ,Option "n" [] (ReqArg (NrOfErrors . (read :: String -> Int)) "arg")- "Allow at most [arg] errors in the palindrome"- ,Option "b" [] (ReqArg (LengthAtLeast . (read :: String -> Int)) "arg")- "Maximal palindromes of length at least [arg]"- ,Option "c" [] (ReqArg (LengthAtMost . (read :: String -> Int)) "arg")- "Maximal palindromes (possibly cut off) of length at most [arg]"- ,Option "f" [] (ReqArg (LengthExact . (read :: String -> Int)) "arg")- "Maximal palindromes (possibly cut off) of length exactly [arg]"- ,Option "r" [] (NoArg Linear)- "Use the linear algorithm"- ,Option "q" [] (NoArg Quadratic)- "Use the potentially quadratic algorithm (default)"- ,Option "i" [] (NoArg StandardInput)- "Read input from standard input"- ,Option "x" [] (ReqArg (Extend . (read :: String -> Int)) "arg")- "Extend a palindrome around center [arg]"- ]--isHelp :: Flag -> Bool-isHelp Help = True-isHelp _ = False --isPlain :: Flag -> Bool-isPlain Plain = True-isPlain _ = False --isText :: Flag -> Bool-isText Text = True-isText _ = False --isWord :: Flag -> Bool-isWord Word = True-isWord _ = False --isDNA :: Flag -> Bool-isDNA DNA = True-isDNA _ = False --isLongest :: Flag -> Bool-isLongest Longest = True-isLongest _ = False --isLengthLongest :: Flag -> Bool-isLengthLongest LengthLongest = True-isLengthLongest _ = False --isMaximal :: Flag -> Bool-isMaximal Maximal = True-isMaximal _ = False --isLengthMaximal :: Flag -> Bool-isLengthMaximal LengthMaximal = True-isLengthMaximal _ = False --isGap :: Flag -> Bool-isGap (Gap _) = True-isGap _ = False --isNrOfErrors :: Flag -> Bool-isNrOfErrors (NrOfErrors _) = True-isNrOfErrors _ = False --isLengthAtLeast :: Flag -> Bool-isLengthAtLeast (LengthAtLeast _) = True-isLengthAtLeast _ = False --isLengthAtMost :: Flag -> Bool-isLengthAtMost (LengthAtMost _) = True-isLengthAtMost _ = False --isLengthExact :: Flag -> Bool-isLengthExact (LengthExact _) = True-isLengthExact _ = False --isLinear :: Flag -> Bool-isLinear Linear = True-isLinear _ = False --isQuadratic :: Flag -> Bool-isQuadratic Quadratic = True-isQuadratic _ = False --isStandardInput :: Flag -> Bool-isStandardInput StandardInput = True-isStandardInput _ = False --isExtend :: Flag -> Bool-isExtend (Extend _) = True-isExtend _ = False --palindromeVariant :: [Flag] -> Maybe Flag-palindromeVariant flags- | any isHelp flags = Just Help- | any isPlain flags = Just Plain- | any isText flags = Just Text- | any isWord flags = Just Word- | any isDNA flags = Just DNA- | any isExtend flags = Just $ head $ filter isExtend flags- | otherwise = Nothing--outputFormat :: [Flag] -> Maybe Flag-outputFormat flags- | any isLongest flags = Just Longest- | any isLengthLongest flags = Just LengthLongest- | any isMaximal flags = Just Maximal- | any isLengthMaximal flags = Just LengthMaximal- | otherwise = Nothing--algorithmComplexity :: [Flag] -> Maybe Flag-algorithmComplexity flags- | any isLinear flags = Just Linear- | any isQuadratic flags = Just Quadratic- | otherwise = Nothing--lengthModifier :: [Flag] -> Maybe Flag-lengthModifier flags- | any isLengthExact flags = Just $ head $ filter isLengthExact flags- | any isLengthAtLeast flags - && any isLengthAtMost flags = Just $ LengthBetween (getLengthAtLeasts flags) (getLengthAtMosts flags)- | any isLengthAtLeast flags = Just $ head $ filter isLengthAtLeast flags- | any isLengthAtMost flags = Just $ head $ filter isLengthAtMost flags- | otherwise = Nothing--gap :: [Flag] -> Maybe Flag-gap flags - | any isGap flags = Just $ head $ filter isGap flags- | otherwise = Nothing--nrOfErrors :: [Flag] -> Maybe Flag-nrOfErrors flags- | any isNrOfErrors flags = Just $ head $ filter isNrOfErrors flags- | otherwise = Nothing--isLengthInBetween :: [Flag] -> Bool-isLengthInBetween flags = length flags == 2- && any isLengthAtLeast flags - && any isLengthAtMost flags - -getLengthAtLeast :: Flag -> Int-getLengthAtLeast (LengthAtLeast n) = n -getLengthAtLeast _ = error "No length at least specified"--getLengthAtLeasts :: [Flag] -> Int-getLengthAtLeasts flags = case filter isLengthAtLeast flags of- [lal] -> getLengthAtLeast lal- _ -> error "No or too many length at least specified"--getLengthAtMost :: Flag -> Int-getLengthAtMost (LengthAtMost n) = n -getLengthAtMost _ = error "No length at most specified"--getLengthAtMosts :: [Flag] -> Int-getLengthAtMosts flags = case filter isLengthAtMost flags of- [lal] -> getLengthAtMost lal- _ -> error "No or too many length at least specified"--handleOptions :: [Flag] -> (B.ByteString -> String,Bool)-handleOptions flags = - (dispatchFlags - (palindromeVariant flags)- (outputFormat flags)- (algorithmComplexity flags)- (lengthModifier flags)- (gap flags)- (nrOfErrors flags)- ,any isStandardInput flags- )--dispatchFlags :: Maybe Flag -> Maybe Flag -> Maybe Flag -> Maybe Flag -> Maybe Flag -> Maybe Flag -> B.ByteString -> String-dispatchFlags pvariant out ac l g k = case pvariant of- Nothing -> const (usageInfo headerHelpMessage options)- Just Help -> const (usageInfo headerHelpMessage options)- Just (Extend c) -> dnaLengthGappedApproximatePalindromeAround g k c- _ -> palindrome pvariant out ac l g k--headerHelpMessage :: String-headerHelpMessage = - "*********************\n"- ++ "* Palindrome Finder *\n"- ++ "* version 0.4 *\n"- ++ "*********************\n"- ++ "Usage:"
+ src/Data/Algorithms/Palindromes/Output.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE BangPatterns #-}++{- |+Module : Data.Algorithms.Palindromes.Output+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module contains functions that apply different ways of formatting the output of the+algorithm functions (found in Data.Algorithms.Palindromes.Algorithms).+-}+module Data.Algorithms.Palindromes.Output+ ( indicesInOutputText+ , indicesInOutputWord+ , rangeToText+ , longest+ , showLengths+ , showTexts+ , showRanges+ , showAll+ ) where++import Data.List (intercalate)++import Data.Algorithms.Palindromes.Palindrome+ ( Palindrome (..)+ , getLength+ )+import Data.Algorithms.Palindromes.RangeFunctions (Range)++import qualified Data.Vector as V+import qualified Data.Vector.Unboxed as U++{- | Takes a start and an end index in the filtered string and returns the indices+in the unfiltered string+-}+indicesInOutputText :: Range -> Int -> U.Vector Int -> Range+indicesInOutputText (start', end') !inputLength originalIndices+ | start' >= U.length originalIndices = (inputLength, inputLength)+ | end' - start' > 0 = (start, end)+ | otherwise = (start, start)+ where+ start = originalIndices U.! start'+ end = (originalIndices U.! (end' - 1)) + 1++{- | Takes a range in the vector containing words and returns the range of the text+of the word palindrome in the original string+-}+indicesInOutputWord :: Range -> Int -> V.Vector (Range, String) -> Range+indicesInOutputWord (start', end') !inputLength wordsWithIndices+ | start' >= length wordsWithIndices =+ (inputLength, inputLength)+ | end' - start' > 0 = (startIndex, endIndex)+ | otherwise = (startIndex, startIndex)+ where+ firstWord :: (Range, String)+ firstWord = wordsWithIndices V.! start'+ lastWord :: (Range, String)+ lastWord = wordsWithIndices V.! (end' - 1)++ startIndex :: Int+ startIndex = fst $ fst firstWord+ endIndex :: Int+ endIndex = snd (fst lastWord)++-- | Takes a start and end index (exclusive) and returns the substring in the text with that range+rangeToText :: Range -> U.Vector Char -> String+rangeToText (start, end) input+ | end - start > 0 = U.toList $ U.slice start (end - start) input+ | otherwise = ""++longest :: [Palindrome] -> Palindrome -> [Palindrome]+longest [] p = [p]+longest pals@(p1 : _) p2+ | getLength p1 == getLength p2 = p2 : pals+ | getLength p1 < getLength p2 = [p2]+ | otherwise = pals++-- | All maximal palindrome lengths+showLengths :: [Palindrome] -> String+showLengths pals = show $ map getLength pals++-- | All maximal palindromes as a list of strings, separated by a newline.+showTexts :: [Palindrome] -> String+showTexts pals = intercalate "\n" (map (\x -> "\"" ++ palText x ++ "\"") pals)++showRanges :: [Palindrome] -> String+showRanges pals = show $ map palRangeInText pals++showAll :: [Palindrome] -> String+showAll pals = intercalate "\n" (map palToDetailString pals)+ where+ palToDetailString pal = "\"" ++ palText pal ++ "\" " ++ show (palRange pal) ++ " " ++ show (getLength pal)
+ src/Data/Algorithms/Palindromes/PalEq.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE UndecidableInstances #-}++{- |+Module : Data.Algorithms.Palindromes.PalEq+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module describes the class PalEq. This is equality but for palindromes. For many+types with an instance of equality this can be used as such. Some types however such as+DNA, where we want characters to match to other characters we create our own instance.+This generalizes equal to a "palindromic equals".+-}+module Data.Algorithms.Palindromes.PalEq+ ( PalEq (..)+ , palEqToItselfAtIndex+ ) where++import qualified Data.Vector.Generic as G++{- | “(=:=) determines whether or not two elements are equal when finding palindromes.+This is not always standard equality for example, A (=:=) T in DNA, and 'z' (=:=) 'z' in normal text.+-}+class PalEq a where+ (=:=) :: a -> a -> Bool++-- | Define PalEq instance for any a of class Eq. Just use the equality relation.+instance (Eq a) => PalEq a where+ (=:=) = (==)++{- | Safe function which returns whether an element at an index in the input vector is+PalEq to itself.+-}+palEqToItselfAtIndex :: (PalEq a, G.Vector v a) => v a -> Int -> Bool+palEqToItselfAtIndex input index+ | index < 0 || index >= G.length input = False+ | otherwise = element =:= element+ where+ element = input G.! index
+ src/Data/Algorithms/Palindromes/Palindrome.hs view
@@ -0,0 +1,45 @@+{- |+Module : Data.Algorithms.Palindromes.Palindrome+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++Describes the palindrome datatype.+-}+module Data.Algorithms.Palindromes.Palindrome (Palindrome (..), getLength) where++import Data.Algorithms.Palindromes.RangeFunctions (Range, rangeToLength)++-- | Data type to represent a single found palindrome+data Palindrome+ = Palindrome+ { palRange :: Range+ -- ^ The range of the palindrome in the pre-pocessed input vector.+ , palText :: String+ {- ^ The text representing the found palindrome. Note that this must be a string,+ not some abstract datatype. This string must be a subarray of the original+ (not pre-processed) input string, meaning that e.g. present punctuation is in this+ string.+ -}+ , palRangeInText :: Range+ {- ^ The start (inclusive) and end (exclusive) index of the palindrome in the original+ string.+ -}+ }+ deriving (Show, Eq)++{- An example text Palindrome from plain input string "bab..ac" is+(Palindrome 5 3 "ab..a" (1,6)). The center is on the 'b' and has center index 5. The+pre-processed text palindrome is "aba", so the length is 3, and after adding back+punctuation, the start character index is 1 (the first 'a') and the end character index+is 6 (the 'c' after the second 'a'). The string representing this text palindrome is+"ab..a". -}++getLength :: Palindrome -> Int+getLength = rangeToLength . palRange
− src/Data/Algorithms/Palindromes/Palindromes.hs
@@ -1,325 +0,0 @@--- test strict integers--- >let input = Data.ByteString.pack (map Data.ByteString.Internal.c2w "yabadabadoo")---------------------------------------------------------------------------------- --- Module : Data.Algorithms.Palindromes.Palindromes--- Copyright : (c) 2007 - 2013 Johan Jeuring--- License : BSD3------ Maintainer : johan@jeuring.net--- Stability : experimental--- Portability : portable------------------------------------------------------------------------------------module Data.Algorithms.Palindromes.Palindromes - (palindrome- ,palindromesAroundCentres- ,dnaLengthGappedApproximatePalindromeAround- ) where- -import Data.List (maximumBy,intercalate)-import qualified Data.ByteString as B-import Data.Algorithms.Palindromes.PalindromesUtils - (showPalindrome- ,showPalindromeDNA- ,showTextPalindrome- ,myToLower- ,myIsLetterW- ,listArrayl0- ,appendseq- ,Flag(..)- ,(=:=)- ,surroundedByPunctuation- )-import qualified Data.Sequence as S -import Data.Word (Word8)-import Data.Array(Array,(!))----------------------------------------------------------------------------------- palindrome dispatches to the desired variant of the palindrome finding--- algorithm. It captures all the variablity, in input format, output format,--- and length restrictions. Variability has been `pushed down' into the code--- as much as possible, using extra arguments whenever needed, for example--- for word palindromes (which have not been implemented correctly at the --- moment: I do get the longest word palindromes, but shorter ones may --- actually not be word palindromes).---------------------------------------------------------------------------------- | palindrome captures all possible variants of finding palindromes.-palindrome :: Maybe Flag -> Maybe Flag -> Maybe Flag -> Maybe Flag -> Maybe Flag -> Maybe Flag -> B.ByteString -> String-palindrome palindromeVariant outputFormat algorithmComplexity lengthModifier gap nrOfErrors input = - let predicate = case lengthModifier of- Just (LengthAtLeast m) -> (m<=)- Just (LengthAtMost m) -> (<=m)- Just (LengthExact m) -> \l -> m<=l && (odd l == odd m)- Just (LengthBetween m n) -> \pl -> pl >= m && pl <= n- _ -> const True- post = case lengthModifier of- Just (LengthExact m) -> \_ -> m - _ -> id- textinput = B.map myToLower (B.filter myIsLetterW input) - positionTextInput = listArrayl0 (B.findIndices myIsLetterW input)- input' = case palindromeVariant of- Just Text -> textinput- Just Word -> textinput- _ -> input- show' = case palindromeVariant of- Just Text -> showTextPalindrome input positionTextInput- Just Word -> showTextPalindrome input positionTextInput- Just DNA -> showPalindromeDNA input- _ -> showPalindrome input- outputf = case outputFormat of- Just LengthLongest -> show . maximum . map post . filter predicate - Just Maximal -> intercalate "\n" . map show' . map (\(l,r) -> (post l,r)) . filter (predicate . fst) . flip zip [0..] - Just LengthMaximal -> show . map post . filter predicate - _ -> show' . maximumBy (\(l,_) (l',_) -> compare l l') . map (\(l,r) -> (post l,r)) . filter (predicate . fst) . flip zip [0..] - in outputf $ palindromesAroundCentres palindromeVariant algorithmComplexity gap nrOfErrors input input' positionTextInput--{- --- The following code is replaced by the equivalent code using a more efficient--- data structure. It is kept here because this is most probably easier to understand,--- and it is the code explained on the blog.---------------------------------------------------------------------------------- palindromesAroundCentres ------ The function that implements the palindrome finding algorithm.--- Used in all the above interface functions.---------------------------------------------------------------------------------- | palindromesAroundCentres is the central function of the module. It returns--- the list of lenghths of the longest palindrome around each position in a--- string.-palindromesAroundCentres :: B.ByteString -> [Int]-palindromesAroundCentres input = reverse $ extendPalindrome input 0 0 []--extendPalindrome :: B.ByteString -> Int -> Int -> [Int] -> [Int]-extendPalindrome input rightmost currentPalindrome currentMaximalPalindromes - | rightmost > last- -- reached the end of the array- = finalPalindromes currentPalindrome currentMaximalPalindromes (currentPalindrome:currentMaximalPalindromes)- | rightmost-currentPalindrome == first ||- not (B.index input rightmost == B.index input (rightmost-currentPalindrome-1))- -- the current palindrome extends to the start of the array, - -- or it cannot be extended - = moveCenter input rightmost (currentPalindrome:currentMaximalPalindromes) currentMaximalPalindromes currentPalindrome - | otherwise - -- the current palindrome can be extended- = extendPalindrome input (rightmost+1) (currentPalindrome+2) currentMaximalPalindromes - where first = 0- last = B.length input - 1--moveCenter :: B.ByteString -> Int -> [Int] -> [Int] -> Int -> [Int]-moveCenter input rightmost currentMaximalPalindromes previousMaximalPalindromes nrOfCenters- | nrOfCenters == 0- -- the last centre is on the last element: try to extend the tail of length 1- = extendPalindrome input (rightmost+1) 1 currentMaximalPalindromes- | nrOfCenters-1 == head previousMaximalPalindromes- -- the previous element in the centre list reaches exactly to the end of the last - -- tail palindrome use the mirror property of palindromes to find the longest tail palindrome- = extendPalindrome input rightmost (head previousMaximalPalindromes) currentMaximalPalindromes- | otherwise- -- move the centres one step add the length of the longest palindrome to the centres- = moveCenter input rightmost (min (head previousMaximalPalindromes) (nrOfCenters-1):currentMaximalPalindromes) (tail previousMaximalPalindromes) (nrOfCenters-1)--finalPalindromes :: Int -> [Int] -> [Int] -> [Int]-finalPalindromes nrOfCenters previousMaximalPalindromes currentMaximalPalindromes - | nrOfCenters == 0- = currentMaximalPalindromes- | nrOfCenters > 0- = finalPalindromes (nrOfCenters-1) (tail previousMaximalPalindromes) (min (head previousMaximalPalindromes) (nrOfCenters-1):currentMaximalPalindromes)- | otherwise - = error "finalCentres: input < 0" ---}---------------------------------------------------------------------------------- palindromesAroundCentresS ------ The function that implements the palindrome finding algorithm.--- Used in all the above interface functions.--- --- I use the Seq datatype to pass on the maximal palindromes that are used for --- finding the maximal palindromes to the right of the center of the current--- longest tail paindrome.---------------------------------------------------------------------------------- | palindromesAroundCentres is the central function of the module. It returns--- the list of lenghths of the longest palindrome around each position in a--- string. -palindromesAroundCentres :: Maybe Flag -> Maybe Flag -> Maybe Flag -> Maybe Flag -> B.ByteString -> B.ByteString -> Array Int Int -> [Int]-palindromesAroundCentres palindromeVariant algorithmComplexity gap nrOfErrors input input' positionTextInput = - case (algorithmComplexity,gap,nrOfErrors) of- (Just Linear ,Nothing,Nothing) -> case palindromeVariant of- Just DNA -> reverse $ appendseq $ extendPalindromeS 2 0 input' [] S.empty 0 0 - Just Word -> reverse $ map (head . snd) $ extendTailWord input input' positionTextInput [] 0 (0,[0]) - _ -> reverse $ appendseq $ extendPalindromeS 1 1 input' [] S.empty 0 0 - (Just Linear ,_ ,_ ) -> error "palindromesAroundCentres: cannot calculate approximate or gapped palindromes using the linear-time algorithm" - (Just Quadratic,g ,k ) -> let g' = case g of- Just (Gap g'') -> g''- _ -> 0- k' = case k of- Just (NrOfErrors k'') -> k''- _ -> 0 - in gappedApproximatePalindromesAroundCentres palindromeVariant input g' k' - (_ ,_ ,_ ) -> error "palindromesAroundCentres: case not defined"--extendPalindromeS :: Int -> Int -> B.ByteString -> [Int] -> S.Seq Int -> Int -> Int -> ([Int],S.Seq Int)-extendPalindromeS centerfactor tailfactor input = - let ePS maximalPalindromesPre maximalPalindromesIn rightmost currentPalindrome - | rightmost > lastPos- -- reached the end of the array- = finalPalindromesS centerfactor currentPalindrome maximalPalindromesPre (currentPalindrome S.<| maximalPalindromesIn) maximalPalindromesIn- | rightmost-currentPalindrome == first ||- not (B.index input rightmost == B.index input (rightmost-currentPalindrome-1))- -- the current palindrome extends to the start of the array, - -- or it cannot be extended - = mCS rightmost maximalPalindromesPre (currentPalindrome S.<| maximalPalindromesIn) maximalPalindromesIn currentPalindrome - | otherwise - -- the current palindrome can be extended- = let (left,rest) = splitAt 2 maximalPalindromesPre- in ePS rest (foldr (flip (S.|>)) maximalPalindromesIn left) (rightmost+1) (currentPalindrome+2) - where first = 0- lastPos = B.length input - 1- mCS rightmost maximalPalindromesPre maximalPalindromesIn maximalPalindromesIn' nrOfCenters- | nrOfCenters == 0- -- the last centre is on the last element: try to extend the tail of length 1- = ePS maximalPalindromesPre maximalPalindromesIn (rightmost+1) tailfactor - | nrOfCenters-centerfactor == S.index maximalPalindromesIn' 0- -- the previous element in the centre list reaches exactly to the end of the last - -- tail palindrome use the mirror property of palindromes to find the longest tail palindrome- = ePS maximalPalindromesPre maximalPalindromesIn rightmost (nrOfCenters-centerfactor)- | otherwise- -- move the centres one step add the length of the longest palindrome to the centres- = case S.viewl maximalPalindromesIn' of- headq S.:< tailq -> mCS rightmost maximalPalindromesPre (min headq (nrOfCenters-centerfactor) S.<| maximalPalindromesIn) tailq (nrOfCenters-centerfactor)- S.EmptyL -> error "extendPalindromeS: empty sequence"- in ePS---- moveCenterS :: B.ByteString -> Int -> [Int] -> S.Seq Int -> S.Seq Int -> Int -> ([Int],S.Seq Int)--finalPalindromesS :: Int -> Int -> [Int] -> S.Seq Int -> S.Seq Int -> ([Int],S.Seq Int)-finalPalindromesS centerfactor nrOfCenters maximalPalindromesPre maximalPalindromesIn maximalPalindromesIn' - | nrOfCenters == 0- = (maximalPalindromesPre,maximalPalindromesIn)- | nrOfCenters > 0- = case S.viewl maximalPalindromesIn' of- headq S.:< tailq -> finalPalindromesS centerfactor (nrOfCenters-centerfactor) maximalPalindromesPre (min headq (nrOfCenters-centerfactor) S.<| maximalPalindromesIn) tailq - S.EmptyL -> error "finalPalindromesS: empty sequence"- | otherwise - = error "finalPalindromesS: input < 0" --gappedApproximatePalindromesAroundCentres :: Maybe Flag -> B.ByteString -> Int -> Int -> [Int]-gappedApproximatePalindromesAroundCentres palindromeVariant input g k = - case palindromeVariant of- Just DNA -> map (lengthGappedApproximatePalindromeAround (=:=) 1 input g k) (if even g then [0 .. B.length input] else [0 .. B.length input-1])- _ -> map (lengthGappedApproximatePalindromeAround (==) 2 input g k) [0 .. 2*B.length input]---- I probably get the wrong positions printed for odd-gapped palindromes--- the next two functions should be mergable, with a centerdivfactor-lengthGappedApproximatePalindromeAround :: (Word8 -> Word8 -> Bool) -> Int -> B.ByteString -> Int -> Int -> Int -> Int-lengthGappedApproximatePalindromeAround (===) centerfactor input g k center =- let halfg = div g 2- c = div center centerfactor- lengthInput = B.length input- halfg' | c < halfg = c- | c + halfg > lengthInput = lengthInput-c- | otherwise = halfg- left = c-1-halfg'- right = if even g then c+halfg' else c+1+halfg' - in lengthApproximatePalindrome (===) input k left right--lengthApproximatePalindrome :: (Word8 -> Word8 -> Bool) -> B.ByteString -> Int -> Int -> Int -> Int -lengthApproximatePalindrome (===) input k start end - | start < 0 || end > lastPos = end-start-1- | B.index input start === B.index input end = lengthApproximatePalindrome (===) input k (start-1) (end+1) - | k > 0 = lengthApproximatePalindrome (===) input (k-1) (start-1) (end+1) - | otherwise = end-start-1- where lastPos = B.length input - 1- -dnaLengthGappedApproximatePalindromeAround :: Maybe Flag -> Maybe Flag -> Int -> B.ByteString -> String-dnaLengthGappedApproximatePalindromeAround (Just (Gap gap)) (Just (NrOfErrors k)) center input = show $ lengthGappedApproximatePalindromeAround (=:=) 1 input gap k center -dnaLengthGappedApproximatePalindromeAround _ _ center input = show $ lengthGappedApproximatePalindromeAround (=:=) 1 input 0 0 center --extendTailWord :: B.ByteString -> B.ByteString -> Array Int Int -> [(Int,[Int])] -> Int -> (Int,[Int]) -> [(Int,[Int])] -extendTailWord input textInput positionTextInput centres n current@(currentTail,currentTailWords) - | n > alast = - -- reached the end of the text input array - finalWordCentres input textInput positionTextInput (current:centres) currentTail centres (1+length centres)- | n-currentTail == afirst = - -- the current longest tail palindrome extends to the start of the text input array- extendWordCentres input textInput positionTextInput (current:centres) n centres currentTail- | B.index textInput n == B.index textInput (n-currentTail-1) = - -- the current longest tail palindrome can be extended- -- check whether or not the extended palindrome is a wordpalindrome- if surroundedByPunctuation (positionTextInput!(n-currentTail-1)) (positionTextInput!n) input- then extendTailWord input textInput positionTextInput centres (n+1) (currentTail+2,currentTail+2:currentTailWords) - else extendTailWord input textInput positionTextInput centres (n+1) (currentTail+2,currentTailWords) - | otherwise = - -- the current longest tail palindrome cannot be extended - extendWordCentres input textInput positionTextInput (current:centres) n centres currentTail- where (afirst,alast) = (0,B.length textInput -1)--extendWordCentres :: B.ByteString -> B.ByteString -> Array Int Int -> [(Int,[Int])] -> Int -> [(Int,[Int])] -> Int -> [(Int,[Int])]-extendWordCentres input textInput positionTextInput centres n tcentres centreDistance- | centreDistance == 0 = - -- the last centre is on the last element: - -- try to extend the tail of length 1- if surroundedByPunctuation (positionTextInput!n) (positionTextInput!n) input- then extendTailWord input textInput positionTextInput centres (n+1) (1,[1,0]) - else extendTailWord input textInput positionTextInput centres (n+1) (1,[0]) - | centreDistance-1 == fst (head tcentres) = - -- the previous element in the centre list - -- reaches exactly to the end of the last - -- tail palindrome use the mirror property - -- of palindromes to find the longest tail - -- palindrome- let (currentTail,oldWord:oldWords) = head tcentres- in if surroundedByPunctuation (positionTextInput!(n-currentTail)) (positionTextInput!(n-1)) input- then if oldWord == currentTail- then extendTailWord input textInput positionTextInput centres n (head tcentres) - else extendTailWord input textInput positionTextInput centres n (currentTail,currentTail:oldWord:oldWords) - else if oldWord == currentTail && oldWord > 0- then extendTailWord input textInput positionTextInput centres n (currentTail, tail (snd (head tcentres))) - else extendTailWord input textInput positionTextInput centres n (head tcentres) - | otherwise = - -- move the centres one step- -- add the length of the longest palindrome - -- to the centres- let newTail = min (fst (head tcentres)) (centreDistance-1)- oldWord = head (snd (head tcentres))- newWords | oldWord < newTail - = if surroundedByPunctuation (positionTextInput!(n-newTail+1)) (positionTextInput!n) input- then newTail:snd (head tcentres) - else snd (head tcentres) - | null (tail (snd (head tcentres)))- = snd (head tcentres) - | otherwise - = tail (snd (head tcentres))- in extendWordCentres input textInput positionTextInput ((newTail,newWords):centres) n (tail tcentres) (centreDistance-1)--finalWordCentres :: B.ByteString -> B.ByteString -> Array Int Int -> [(Int,[Int])] -> Int -> [(Int,[Int])] -> Int -> [(Int,[Int])]-finalWordCentres input textInput positionTextInput centres n tcentres mirrorPoint - | n == 0 = centres- | n > 0 = let tlast = B.length textInput - 1- (oldTail,oldWord:oldWords) = head tcentres- newTail = min oldTail (n-1)- newWord = min oldWord (n-1)- tailFirstMirror = min tlast (div (mirrorPoint - newTail) 2)- tailLastMirror = min tlast (if odd newTail then div (mirrorPoint + newTail) 2 else div (mirrorPoint + newTail) 2 - 1)- wordFirstMirror = min tlast (div (mirrorPoint - newWord) 2)- wordLastMirror = min tlast (if odd newWord then div (mirrorPoint + newTail) 2 else div (mirrorPoint + newTail) 2 - 1)- newWords | surroundedByPunctuation (positionTextInput!tailFirstMirror) (positionTextInput!tailLastMirror) input- = if newWord == newTail- then newTail:oldWords- else newTail:oldWord:oldWords- | surroundedByPunctuation (positionTextInput!wordFirstMirror) (positionTextInput!wordLastMirror) input ||- null oldWords = newWord:oldWords- | otherwise = oldWords- in finalWordCentres input textInput positionTextInput ((newTail,newWords):centres) (n-1) (tail tcentres) (mirrorPoint+1)- | otherwise = error "finalWordCentres: input < 0" -
− src/Data/Algorithms/Palindromes/PalindromesUtils.hs
@@ -1,175 +0,0 @@--------------------------------------------------------------------------------- --- Module : Data.Algorithms.Palindromes.PalindromesUtils--- Copyright : (c) 2007 - 2013 Johan Jeuring--- License : BSD3------ Maintainer : johan@jeuring.net--- Stability : experimental--- Portability : portable------------------------------------------------------------------------------------module Data.Algorithms.Palindromes.PalindromesUtils - (Flag(..)- ,negateDNA- ,showPalindromeDNA- ,(=:=)- ,showPalindrome- ,showTextPalindrome- ,myIsLetterC- ,myIsLetterW- ,myToLower- ,surroundedByPunctuation- ,appendseq- ,listArrayl0- ) where- -import Data.Word (Word8)-import Data.Char (toLower,toUpper,isPunctuation,isSpace,isControl)-import Data.Array (Array,bounds,listArray,(!)) -import qualified Data.ByteString as B-import Data.ByteString.Internal (w2c,c2w)-import qualified Data.Sequence as S---------------------------------------------------------------------------------- Flags a user can specify--------------------------------------------------------------------------------data Flag = -- Palindromic variants (choose 1 out of 6; mutually exclusive):- Help- | Plain- | Text- | Word- | DNA- | Extend Int - -- Algorithm complexity (choose 1 out of 2; mutually exclusive):- | Linear- | Quadratic- -- Output format (choose 1 out of 4; mutually exclusive):- | Longest - | LengthLongest - | Maximal - | LengthMaximal- -- Modifiers (choose 0 to 5; where the length restrictions need to fit together)- | Gap Int - | NrOfErrors Int - | LengthAtLeast Int - | LengthAtMost Int - | LengthExact Int- | LengthBetween Int Int -- input via AtLeast and AtMost. Adapt?- -- Input format- | StandardInput ---------------------------------------------------------------------------------- Equality on DNA--------------------------------------------------------------------------------negateDNA :: Char -> Char-negateDNA 'A' = 'T'-negateDNA 'T' = 'A'-negateDNA 'C' = 'G'-negateDNA 'G' = 'C'-negateDNA _ = error "negateDNA: not a DNA character"--(=:=) :: Word8 -> Word8 -> Bool-l =:= r = let cl = toUpper (w2c l)- cr = toUpper (w2c r)- in if cl `elem` "ATCG" && cr `elem` "ATCG" - then cl == negateDNA cr- else False---------------------------------------------------------------------------------- Showing DNA palindromes--------------------------------------------------------------------------------showPalindromeDNA :: B.ByteString -> (Int,Int) -> String-showPalindromeDNA input (len,pos) = - let startpos = pos - len `div` 2- in (show startpos ++) - . (" to " ++) - . (show (startpos+len) ++) - . ("\t" ++) - . (show (B.take len $ B.drop startpos input) ++) - . ("\t" ++) - $ show len---------------------------------------------------------------------------------- Showing palindromes and other text related functionality--------------------------------------------------------------------------------showPalindrome :: B.ByteString -> (Int,Int) -> String-showPalindrome input (len,pos) = - let startpos = pos `div` 2 - len `div` 2- in show $ B.take len $ B.drop startpos input --showTextPalindrome :: B.ByteString -> Array Int Int -> (Int,Int) -> String-showTextPalindrome input positionTextInput (len,pos) = - let startpos = pos `div` 2 - len `div` 2- endpos = if odd len - then pos `div` 2 + len `div` 2 - else pos `div` 2 + len `div` 2 - 1- (pfirst,plast) = bounds positionTextInput- (ifirst,ilast) = (0,1 + B.length input)- in if endpos < startpos- then []- else let start = if startpos > pfirst- then (positionTextInput!(startpos-1))+1- else ifirst - end = if endpos < plast- then (positionTextInput!(endpos+1))-1- else ilast- in show (B.take (end-start+1) (B.drop start input))--{- Using this code instead of the last else above shows text palindromes without - all punctuation around it. Right now this punctuation is shown.-- else let start = positionArray!!!startpos- end = positionArray!!!endpos--}---- For palindromes in strings, punctuation, spacing, and control characters--- are often ignored--myIsLetterW :: Word8 -> Bool-myIsLetterW c' = not (isPunctuation c)- && not (isControl c)- && not (isSpace c)- where c = w2c c'--myIsLetterC :: Char -> Bool-myIsLetterC c = not (isPunctuation c)- && not (isControl c)- && not (isSpace c)--myToLower :: Word8 -> Word8-myToLower = c2w . toLower . w2c--surroundedByPunctuation :: Int -> Int -> B.ByteString -> Bool-surroundedByPunctuation begin end input - | begin > afirst && end < alast = not (myIsLetterW (B.index input (begin-1))) && not (myIsLetterW (B.index input (end+1)))- | begin <= afirst && end < alast = not (myIsLetterW (B.index input (end+1)))- | begin <= afirst && end >= alast = True- | begin > afirst && end >= alast = not (myIsLetterW (B.index input (begin-1)))- | otherwise = error "surroundedByPunctuation"- where (afirst,alast) = (0,B.length input - 1)---------------------------------------------------------------------------------- Seq utils--------------------------------------------------------------------------------appendseq :: ([a],S.Seq a) -> [a]-appendseq (list,s) = tolist s ++ list--tolist :: S.Seq a -> [a]-tolist s = case S.viewl s of - S.EmptyL -> []- a S.:< r -> a:tolist r---------------------------------------------------------------------------------- Array utils--------------------------------------------------------------------------------listArrayl0 :: [a] -> Array Int a-listArrayl0 string = listArray (0,length string - 1) string
+ src/Data/Algorithms/Palindromes/PostProcessing.hs view
@@ -0,0 +1,48 @@+{- |+Module : Data.Algorithms.Palindromes.PostProcessing+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++Describes postprocessing functions. For now, this is used for the punctuation type to+shorten palindromes to punctuation.+-}+module Data.Algorithms.Palindromes.PostProcessing+ ( filterPunctuation+ ) where++import Data.Char (isLetter)++import Data.Algorithms.Palindromes.PreProcessing (filterLetters')+import Data.Algorithms.Palindromes.RangeFunctions (Range)++import qualified Data.Vector.Unboxed as U++-- | This function changes the a list of ranges for punctuation palindromes by shrinking to punctuation.+filterPunctuation :: U.Vector Char -> [Range] -> [Range]+filterPunctuation input = map shrinkRange+ where+ {- Shrinks a range on both sides until the resulting range is surrounded by+ punctuation in the original input. -}+ shrinkRange :: Range -> Range+ shrinkRange (startIndex, endIndex)+ | startIndex == endIndex = (startIndex, endIndex)+ | startIndex > endIndex = (endIndex, endIndex)+ | punctuationAt (originalStart - 1) && punctuationAt (originalEnd + 1) =+ (startIndex, endIndex)+ | otherwise = shrinkRange (startIndex + 1, endIndex - 1)+ where+ originalStart :: Int+ originalStart = filterLetters' input U.! startIndex+ originalEnd :: Int+ originalEnd = filterLetters' input U.! (endIndex - 1)+ punctuationAt :: Int -> Bool+ punctuationAt i+ | i < U.length input && i >= 0 = (not . isLetter) $ input U.! i+ | otherwise = True
+ src/Data/Algorithms/Palindromes/PreProcessing.hs view
@@ -0,0 +1,95 @@+{- |+Module : Data.Algorithms.Palindromes.PreProcessing+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++Functions for converting string input to different variants that can be used in the+algorithms.+-}+module Data.Algorithms.Palindromes.PreProcessing+ ( filterLetters+ , filterLetters'+ , textToWords+ , textToWordsWithIndices+ , tryParseDNA+ ) where++import Data.Char (isAlphaNum, isSpace, toLower)+import Data.Maybe (fromMaybe)++import Data.Algorithms.Palindromes.DNA+ ( DNA+ , toDNA+ )++import qualified Data.Vector as V+import qualified Data.Vector.Unboxed as U++-- Make sure all functions are of the type+-- (PalEq b) => String -> [b]++-- | A function that filters the string so that only letters remain+filterLetters :: U.Vector Char -> U.Vector Char+filterLetters x = U.map toLower $ U.filter isAlphaNum x++{- | A function that filters the string so that only letters remain, but remembers the+original index of each character.+-}+filterLetters' :: U.Vector Char -> U.Vector Int+filterLetters' x = U.map fst $ U.filter (isAlphaNum . snd) (U.indexed (U.map toLower x))++{- | A function that filters the string so that only letters and spaces remain, then+splits the result on every space so that only words remain.+-}+textToWords :: U.Vector Char -> V.Vector String+textToWords x =+ V.fromList $ words $ map toLower $ filter (\a -> isAlphaNum a || isSpace a) $ U.toList x++{- | A function that filters the string so that only letters and spaces remain, then+splits the result on every space so that only words remain. It remembers the original+start and end index of each word.+-}+textToWordsWithIndices :: U.Vector Char -> V.Vector ((Int, Int), String)+textToWordsWithIndices input = V.fromList $ map toWord $ wordsWithIndices indexedCharacters+ where+ indexedCharacters :: [(Int, Char)]+ indexedCharacters = U.toList $ filterSpaceAndLetters input++ -- Convert a list of indexed characters to an indexed string+ toWord :: [(Int, Char)] -> ((Int, Int), [Char])+ toWord [] = error "Empty string"+ toWord word@(firstIndexedChar : _) =+ ( (fst firstIndexedChar, fst (last word) + 1)+ , map snd word+ )++ -- The words function as written in Prelude, but on indexed characters+ wordsWithIndices :: [(Int, Char)] -> [[(Int, Char)]]+ wordsWithIndices s+ | null checking = []+ | otherwise = word : wordsWithIndices remaining+ where+ checking = dropWhile (isSpace . snd) s+ (word, remaining) = break (isSpace . snd) checking++ filterSpaceAndLetters :: U.Vector Char -> U.Vector (Int, Char)+ filterSpaceAndLetters w =+ U.filter+ (\x -> (isAlphaNum . snd) x || (isSpace . snd) x)+ (U.indexed (U.map toLower w))++-- If trying to parse the string to DNA would fail, throw a more readable error+tryParseDNA :: U.Vector Char -> U.Vector DNA+-- tryParseDNA input+-- | (isNothing . parseDna) input = error "Invalid DNA string"+-- | otherwise = (fromJust . parseDna) input+tryParseDNA input = fromMaybe (error "Invalid DNA string") (parseDna input)+parseDna :: U.Vector Char -> Maybe (U.Vector DNA)+parseDna = toDNA . filterLetters
+ src/Data/Algorithms/Palindromes/QuadraticAlgorithm.hs view
@@ -0,0 +1,207 @@+{-# LANGUAGE MonoLocalBinds #-}++{- |+Module : Data.Algorithms.Palindromes.QuadraticAlgorithm+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module contains an implementation of a quadratic algorithm to find palindromes.+-}+module Data.Algorithms.Palindromes.QuadraticAlgorithm+ ( gappedApproximatePalindromesAroundCentres+ , getLeftRightCenterBetweenElems+ , getLeftRightCenterOnElem+ , lengthPalAtCenterReflexive+ , lengthPalAtCenterAntiReflexive+ , getLeftRightReflexive+ , lengthApproximatePalindrome+ ) where++import Data.List as L++import Data.Algorithms.Palindromes.PalEq+ ( PalEq (..)+ )++import qualified Data.Vector.Generic as G++{- | For each center, finds the maximal palindrome around this center.+This function runs in O(m), where m is the sum of palindrome sizes.+-}+gappedApproximatePalindromesAroundCentres+ :: (PalEq a, G.Vector v a)+ => Bool+ -> Int+ -> Int+ -> v a+ -> [Int]+gappedApproximatePalindromesAroundCentres onlyEvenPals gapSize maxErrors input+ | onlyEvenPals =+ L.map+ (lengthPalAtCenterAntiReflexive input gapSize maxErrors)+ (if even gapSize then [0 .. G.length input] else [0 .. G.length input - 1])+ | otherwise =+ L.map+ (lengthPalAtCenterReflexive input gapSize maxErrors)+ [0 .. 2 * G.length input]++{- | Keep expanding the palindrome around the given center to get the maximal palindrome.+Allows a maximum of maxErrors errors. This function runs in O(k), where k is the size of+the found palindrome.+-}+lengthApproximatePalindrome+ :: (PalEq a, G.Vector v a) => v a -> Int -> Int -> Int -> Int+lengthApproximatePalindrome input maxErrors start end+ | start < 0 || end > lastPos = end - start - 1+ | (input G.! start) =:= (input G.! end) =+ lengthApproximatePalindrome input maxErrors (start - 1) (end + 1)+ | maxErrors > 0 =+ lengthApproximatePalindrome input (maxErrors - 1) (start - 1) (end + 1)+ | otherwise = end - start - 1+ where+ lastPos :: Int+ lastPos = G.length input - 1++{-+---------------------------------------------------------------------+ Begin getLeftRight functions+---------------------------------------------------------------------+-}++{- | Get the element index for the left and right characters to start expanding the+palindrome from, essentially ignoring the gap. This function must be used when the+palindrome center is between two elements. Note that if the inputted gap size is odd, the+actually used gap size will be (gapSize - 1).+-}+getLeftRightCenterBetweenElems+ :: Int+ -> Int+ -- ^ The index of the element to the right of the center+ -> Int+ -> (Int, Int)+getLeftRightCenterBetweenElems gapSize elementIndex lengthInput = (left, right)+ where+ halfg = gapSize `div` 2+ {- How far the gap can span to the left without going out of+ bounds to the left. -}+ leewayLeft = elementIndex+ {- How far the gap can span to the right without going out of+ bounds to the right. -}+ leewayRight = lengthInput - elementIndex+ -- make sure halfg' is not larger than leewayLeft or leewayRight+ halfg' = L.minimum [halfg, leewayLeft, leewayRight]+ left = elementIndex - 1 - halfg'+ right = elementIndex + halfg'++{- | Get the element index for the left and right characters to start expanding the+palindrome from, essentially ignoring the gap. This function must be used when the+palindrome center is on an element. Note that if the gapSize is even, the+resulting gap will be maximum (gapSize - 1) big.+-}+getLeftRightCenterOnElem+ :: Int+ -> Int+ -- ^ The index of the element on the center+ -> Int+ -> (Int, Int)+getLeftRightCenterOnElem gapSize elementIndex lengthInput = (left, right)+ where+ halfg = (gapSize + 1) `div` 2+ {- How far the gap can span to the left without going out of+ bounds to the left. -}+ leewayLeft = elementIndex + 1+ {- How far the gap can span to the right without going out of+ bounds to the right. -}+ leewayRight = lengthInput - elementIndex+ -- make sure halfg' is not larger than leewayLeft or leewayRight+ halfg' = L.minimum [halfg, leewayLeft, leewayRight]+ left = elementIndex - halfg'+ right = elementIndex + halfg'++{-+---------------------------------------------------------------------+ End getLeftRight functions+---------------------------------------------------------------------+-}++{-+---------------------------------------------------------------------+ Begin reflexive quadratic functions+---------------------------------------------------------------------+-}++-- | The length of the maximal palindrome around the specified center+lengthPalAtCenterReflexive+ :: (PalEq a, G.Vector v a)+ => v a+ -- ^ The total vector to find palindromes in+ -> Int+ -- ^ The size of the gap+ -> Int+ -- ^ The (maximum) number of allowed errors+ -> Int+ -- ^ The index of the center+ -> Int+ -- ^ The resulting length of the found maximal palindrome+lengthPalAtCenterReflexive input gapSize maxErrors center =+ let (left, right) = getLeftRightReflexive gapSize center (G.length input)+ in lengthApproximatePalindrome input maxErrors left right++{- | Get the two new character indexes for the left and right character to+start expanding from, ignoring the gap.+-}+getLeftRightReflexive+ :: Int+ -- ^ gap size+ -> Int+ -- ^ center index+ -> Int+ -- ^ the size of the whole input+ -> (Int, Int)+getLeftRightReflexive gapSize center lengthInput+ | even center = getLeftRightCenterBetweenElems gapSize elementIndex lengthInput+ | otherwise = getLeftRightCenterOnElem gapSize elementIndex lengthInput+ where+ elementIndex = center `div` 2++{-+---------------------------------------------------------------------+ End reflexive quadratic functions+---------------------------------------------------------------------+-}++{-+---------------------------------------------------------------------+ Begin anti-reflexive quadratic functions+---------------------------------------------------------------------+-}++lengthPalAtCenterAntiReflexive+ :: (PalEq a, G.Vector v a)+ => v a+ -- ^ The total vector to find palindromes in+ -> Int+ -- ^ The size of the gap+ -> Int+ -- ^ The (maximum) number of allowed errors+ -> Int+ -- ^ The index of the center+ -> Int+lengthPalAtCenterAntiReflexive input gapSize maxErrors center =+ -- We can just use getLeftRightCenterBetweenElems, because with anti reflexive data+ -- types, the center is aways between two elements+ let (left, right) = getLeftRightCenterBetweenElems gapSize center (G.length input)+ in lengthApproximatePalindrome input maxErrors left right++{-+---------------------------------------------------------------------+ End anti-reflexive quadratic functions+---------------------------------------------------------------------+-}
+ src/Data/Algorithms/Palindromes/RangeFunctions.hs view
@@ -0,0 +1,54 @@+{- |+Module : Data.Algorithms.Palindromes.RangeFunctions+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++Describes functions that do range calculations.+-}+module Data.Algorithms.Palindromes.RangeFunctions+ ( lengthsToRanges+ , indexedLengthToRange+ , rangeToLength+ , rangeToPalindromeCenter+ , Range+ ) where++-- | A range with format: ([start index (inclusive)], [end index (exclusive)]).+type Range = (Int, Int)++-- | Converts a list of palindrome center lengths to a list of (start, end) pairs.+lengthsToRanges :: [Int] -> [Range]+lengthsToRanges lengths = map indexedLengthToRange indexedLengths+ where+ indexedLengths :: [(Int, Int)]+ indexedLengths = zip [0 :: Int ..] lengths++{- | Converts a tuple with center index and length to a tuple with the starting character+ index and the end character index.+-}+indexedLengthToRange :: (Int, Int) -> Range+indexedLengthToRange (index, len) = (startIndex, endIndex)+ where+ startIndex :: Int+ startIndex = (index `div` 2) - (len `div` 2)+ endIndex :: Int+ endIndex = startIndex + len++{- Converts a (palindrome's) range to a palindrome length. We take max to cover an edge+case where the range is negative. The palindrome should then be empty. -}+rangeToLength :: Range -> Int+rangeToLength (start, end) = max 0 (end - start)++{- A center, in the context of palindromes, is the position in the string from where+the two arms of the palindrome extend. This can be on a character or inbetween two+characters. Therefore this scales twice as fast, hence we can add both sides of the+range in the string. -}+rangeToPalindromeCenter :: Range -> Int+rangeToPalindromeCenter = uncurry (+)
+ src/Data/Algorithms/Palindromes/Settings.hs view
@@ -0,0 +1,88 @@+{- |+Module : Data.Algorithms.Palindromes.Settings+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++Describes the settings for the palindrome finder functions.+-}+module Data.Algorithms.Palindromes.Settings+ ( Settings (..)+ , applySettingsToFinder+ , checkSettingsWarnings+ ) where++import Data.List (intercalate)++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ , findPalindromesFormatted+ , formatPalindromes+ )+import Data.Algorithms.Palindromes.Streaming (findPalindromesWithProgressBar)++-- | Data type with all the settings required for running algorithm.+data Settings = Settings+ { algorithm :: Algorithm+ , variant :: Variant+ , outputFormat :: OutputFormat+ , outputFilter :: OutputFilter+ , minLength :: Int+ }++instance Show Settings where+ show settings = intercalate ", " settingsSpecs+ where+ settingsSpecs =+ [ show (algorithm settings)+ , show (variant settings)+ , show (outputFormat settings)+ , show (outputFilter settings)+ , show (minLength settings)+ ]++-- | Finds all formatted palindromes given the settings. Can be done with and without a progress bar.+applySettingsToFinder+ :: Bool+ -- ^ Is the progress bar disabled+ -> Settings+ -- ^ The settings to find palindromes with+ -> (String -> IO String)+applySettingsToFinder+ progressDisabled+ ( Settings+ { algorithm = c+ , variant = v+ , outputFormat = o+ , outputFilter = f+ , minLength = l+ }+ )+ input+ | progressDisabled = return $ findPalindromesFormatted v o f c l input+ | otherwise = do+ pals <- findPalindromesWithProgressBar v c l filterOnlyLongest input+ return (formatPalindromes o pals)+ where+ filterOnlyLongest = case f of+ SelectLongest -> True+ _ -> False++{- | Checks whether the found settings have problems. If so, returns a warnings message.+Else, returns an empty string.+-}+checkSettingsWarnings :: Settings -> String+checkSettingsWarnings Settings{algorithm = AlgApproximate _ _, variant = VarPunctuation} =+ "WARNING: The approximate palindrome algorithm currently does not "+ ++ "garantee that all maximal punctuation palindromes "+ ++ "are found."+checkSettingsWarnings _ = ""
+ src/Data/Algorithms/Palindromes/Streaming.hs view
@@ -0,0 +1,129 @@+{-# LANGUAGE BangPatterns #-}++{- |+Module : Data.Algorithms.Palindromes.Streaming+Copyright : (c) 2007 - 2025 Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring+License : BSD3+Maintainer : johan@jeuring.net+Stability : provisional+Portability : portable++This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring++This module contains functions for streaming the search for palindromes. This is used for+the progress bar.+-}+module Data.Algorithms.Palindromes.Streaming (findPalindromesStream, findPalindromesWithProgressBar, findPalindromesVisualised) where++import Control.Monad.IO.Class (liftIO)+import System.IO (hFlush)++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , Variant (..)+ , findPalindromes+ )+import Data.Algorithms.Palindromes.Output (longest)+import Data.Algorithms.Palindromes.Palindrome (Palindrome (..), getLength)++import qualified Data.Conduit as C+import qualified Data.Conduit.Combinators as C+import qualified Data.Vector as V+import qualified System.IO as Sys++-- | Streams the result of the given settings+findPalindromesStream+ :: Variant -> Algorithm -> Int -> String -> C.ConduitT () Palindrome IO ()+findPalindromesStream variant algorithm minlen input =+ C.yieldMany $ findPalindromes variant algorithm minlen input++{- | Returns the result of finding palindromes with the settings (The first 3 params) on the string+whilst diplaying the intermediate progress using the given function+-}+findPalindromesVisualised+ :: Variant+ -> Algorithm+ -> Int+ -> Bool+ -- ^ Enable filtering to only return the longest palindromes+ -> String+ -> (Float -> IO ())+ -- ^ Function that defines how to visualise progress+ -> IO [Palindrome]+findPalindromesVisualised variant algorithm minLength filterLongest input visualiseProgress =+ do+ let chunkSize = 100+ -- Used for minimum detail level for progress, only use smaller than 2 if user explicitly overrides default+ let streamMinLength = min minLength 2+ let !inputLength = length input+ visualiseProgress 0+ result <-+ C.runConduit $+ findPalindromesStream variant algorithm streamMinLength input+ C..| C.conduitVector chunkSize -- Chunk result stream+ C..| calcVisualiseProgress inputLength algorithm visualiseProgress+ C..| C.concat+ C..| C.filter -- Filter to actual given filter size+ ((minLength <=) . getLength)+ C..| if filterLongest+ then+ C.foldl longest []+ else C.sinkList+ return $ if filterLongest then reverse result else result++{- | Consumes a Vector of Palindrome and prints the progress made+based on the centre of the palindrome range compared to the input length.+Then forces the values in the Vector to ensure progress has been made and passes them on.+-}+calcVisualiseProgress+ :: Int+ -- ^ Max length of the input vector, needed to calculate percentage+ -> Algorithm+ -- ^ Required because the Approximate algorithm returns the palindromes in reverse order+ -> (Float -> IO ())+ -- ^ Function that defines how to visualise the progress+ -> C.ConduitT (V.Vector Palindrome) (V.Vector Palindrome) IO ()+calcVisualiseProgress totalLen algorithm visualise = C.awaitForever $ \pals -> do+ let rawProgress = fromIntegral (sum $ palRangeInText (V.last pals)) / fromIntegral totalLen+ let progress = case algorithm of+ AlgApproximate _ _ -> 1 - rawProgress+ _ -> rawProgress+ liftIO $ visualise progress+ C.yield pals++-- | Wrapper for findPalindromesVisualised where the visualisation method is printProgressbar+findPalindromesWithProgressBar+ :: Variant+ -> Algorithm+ -> Int+ -> Bool+ -> String+ -> IO [Palindrome]+findPalindromesWithProgressBar variant algorithm minLength filterLongest input =+ findPalindromesVisualised+ variant+ algorithm+ minLength+ filterLongest+ input+ printProgressBar++{- | Prints a progress bar into the terminal with progress between 0 and 1,+then flushes stdout to force a write+-}+printProgressBar :: Float -> IO ()+printProgressBar progress = do+ let hashes = round $ progress * 40+ let dashes = 40 - hashes+ let percent = (round $ progress * 100) :: Int+ let bar =+ "["+ ++ replicate hashes '#'+ ++ replicate dashes '-'+ ++ "] "+ ++ show percent+ ++ "%"+ putStr $ "\r" ++ bar+ hFlush Sys.stdout
+ tests/ITApproximate.hs view
@@ -0,0 +1,981 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module ITApproximate (testListITApproximate) where++import Test.HUnit (Test (..), (~:), (~?=))++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ , findPalindromesFormatted+ )++testListITApproximate =+ [ testITApproximate1+ , testITApproximate2+ , testITApproximate3+ , testITApproximate4+ , testITApproximate5+ , testITApproximate6+ , testITApproximate7+ , testITApproximate8+ , testITApproximate9+ , testITApproximate10+ , testITApproximate11+ , testITApproximate12+ , testITApproximate13+ , testITApproximate14+ , testITApproximate15+ , testITApproximate16+ , testITApproximate17+ , testITApproximate18+ , testITApproximate19+ , testITApproximate20+ , testITApproximate21+ , testITApproximate22+ , testITApproximate23+ , testITApproximate24+ , testITApproximate25+ , testITApproximate26+ , testITApproximate27+ , testITApproximate28+ , testITApproximate29+ , testITApproximate30+ , testITApproximate31+ , testITApproximate32+ , testITApproximate33+ , testITApproximate34+ , testITApproximate35+ , testITApproximate36+ , testITApproximate37+ , testITApproximate38+ , testITApproximate39+ , testITApproximate40+ , testITApproximate41+ , testITApproximate42+ , testITApproximate43+ , testITApproximate44+ , testITApproximate45+ , testITApproximate46+ , testITApproximate47+ , testITApproximate48+ , testITApproximate49+ , testITApproximate50+ , testITApproximate51+ , testITApproximate52+ , testITApproximate53+ , testITApproximate54+ , testITApproximate55+ , testITApproximate56+ , testITApproximate57+ , testITApproximate58+ , testITApproximate59+ , testITApproximate60+ , testITApproximate61+ , testITApproximate62+ , testITApproximate63+ , testITApproximate64+ , testITApproximate65+ , testITApproximate66+ , testITApproximate67+ , testITApproximate68+ , testITApproximate69+ , testITApproximate70+ , testITApproximate71+ , testITApproximate72+ , testITApproximate73+ , testITApproximate74+ ]++testITApproximate1 =+ "testITApproximate1"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 0+ "AG\nTC"+ ~?= "[3,3]"++-- String: Contains a nested palindrome with punctuation+testITApproximate2 =+ "testITApproximate2"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 4+ "A&T-AT"+ ~?= "\"A&T-AT\""++-- String: Does not contain a palindrome+testITApproximate3 =+ "testITApproximate3"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 4}+ 1+ "AGTC"+ ~?= "[4]"++-- String: Contains a gapped even palindrome+testITApproximate4 =+ "testITApproximate4"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 2, algMaxErrors = 0}+ 2+ "ACCT"+ ~?= "[2,2,4]"++-- String: Contains an odd-gapped dna palindrome+testITApproximate5 =+ "testITApproximate5"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 1, algMaxErrors = 2}+ 3+ "“AC\nTA..,TTCT”"+ ~?= "\"AC\nTA..,TTCT\""++-- String: Contains an even nested palindrome+testITApproximate6 =+ "testITApproximate6"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 3+ "ATAT"+ ~?= "[4]"++-- String: Contains an even gapped palindrome with punctuation+testITApproximate7 =+ "testITApproximate7"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 4, algMaxErrors = 4}+ 2+ "Ac\nC,T”"+ ~?= "\"Ac\nC,T\""++-- String: Contains an odd gapped palindrome+testITApproximate8 =+ "testITApproximate8"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 1, algMaxErrors = 2}+ 2+ "ACTATTCT"+ ~?= "\"ACTATTCT\""++-- String: Contains an odd gapped palindrome+testITApproximate9 =+ "testITApproximate9"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 2, algMaxErrors = 0}+ 1+ "AGGGT"+ ~?= "[2,2,2,2]"++-- String: Contains an odd gapped palindrome with punctuation+testITApproximate10 =+ "testITApproximate10"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 5, algMaxErrors = 5}+ 0+ "A;G;G;G;T"+ ~?= "\"A;G;G;G;T\""++-- String: Contains a palindrome with punctuation+testITApproximate11 =+ "testITApproximate11"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 6+ "Ac.G-CgA "+ ~?= "[6]"++-- String: Contains an even palindrome+testITApproximate12 =+ "testITApproximate12"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 6+ "ACGCGA"+ ~?= "No palindromes found"++-- String: Contains an approximate palindrome+testITApproximate13 =+ "testITApproximate13"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 4+ "kabral"+ ~?= "\"abra\""++-- String: Contains no palindrome+testITApproximate14 =+ "testITApproximate14"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 6}+ 1+ "abcdef"+ ~?= "[6]"++-- String: Contains an even palindrome with punctuation+testITApproximate15 =+ "testITApproximate15"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 2}+ 3+ "a’b/ba"+ ~?= "[6]"++-- String: Contains an even palindrome+testITApproximate16 =+ "testITApproximate16"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 0+ "abba"+ ~?= "\"abba\""++-- String: Contains an odd palindrome with punctuation. Contains a special character.+testITApproximate17 =+ "testITApproximate17"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 3+ "l.e.p’e;l"+ ~?= "[3]"++-- String: Contains an odd palindrome+testITApproximate18 =+ "testITApproximate18"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 5, algMaxErrors = 5}+ 2+ "lepel"+ ~?= "\"lepel\""++-- String: Contains an approximate palindrome with punctuation+testITApproximate19 =+ "testITApproximate19"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 0+ "kab^ra.L"+ ~?= "[5]"++-- String: Contains no palindrome, contains punctuation+testITApproximate20 =+ "testITApproximate20"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 0+ "Abc'd/.ef"+ ~?= "\"f\"\n\"e\"\n\".\"\n\"/\"\n\"d\"\n\"'\"\n\"c\"\n\"b\"\n\"A\""++-- String: Contains an odd approximate palindrome, with punctuation+testITApproximate21 =+ "testITApproximate21"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 10}+ 2+ "zat.,s&tat"+ ~?= "[10]"++-- String: Contains an odd approximate palindrome+testITApproximate22 =+ "testITApproximate22"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 2+ "zatstat"+ ~?= "[3,5]"++-- String: Contains an even gapped palindrome, with punctuation+testITApproximate23 =+ "testITApproximate23"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 1, algMaxErrors = 2}+ 5+ "blaA\\Bc..dA;b.l#i"+ ~?= "\"b.l#i\"\n\";b.l#\"\n\"A;b.l\"\n\"..dA;\"\n\"..dA;b.\"\n\"Bc..dA\"\n\"\\Bc..\"\n\"A\\Bc.\"\n\"aA\\Bc\"\n\"laA\\B\"\n\"blaA\\\""++-- String: Contains an even gapped palindrome+testITApproximate24 =+ "testITApproximate24"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 2, algMaxErrors = 0}+ 1+ "blaABcdBAbli"+ ~?= "[2,2,2,2,2,2,2,6,2,2,2]"++-- String: Contains an odd gapped palindrome with punctuation+testITApproximate25 =+ "testITApproximate25"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 10, algMaxErrors = 10}+ 2+ "A-B*cde)BA"+ ~?= "\"A-B*cde)BA\""++-- String: Contains an odd gapped palindrome+testITApproximate26 =+ "testITApproximate26"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 3, algMaxErrors = 2}+ 4+ "ABcdeBA"+ ~?= "\"ABcdeBA\""++-- String: Contains an even palindrome, with punctuation, with special characters+testITApproximate27 :: Test+testITApproximate27 =+ "testITApproximate27"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 3+ "\"blaAPPab’li "+ ~?= "No palindromes found"++-- String: Contains an even palindrome+testITApproximate28 =+ "testITApproximate28"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 9}+ 0+ "blaAPPAbl"+ ~?= "\"blaAPPAbl\""++-- String: Contains an odd palindrome+testITApproximate29 =+ "testITApproximate29"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 0+ "blaAPAbli"+ ~?= "[1,1,1,1,1,3,1,1,1]"++-- String: Contains an odd palindrome with punctuation+testITApproximate30 =+ "testITApproximate30"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 4+ "/blaAPa.bl.i"+ ~?= "\".bl.\"\n\"aAPa\""++-- String: Contains an even palindrome with punctuation+testITApproximate31 =+ "testITApproximate31"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 2}+ 2+ "/abba/"+ ~?= "\"abba\""++-- String: Conains an even gapped palindrome+testITApproximate32 =+ "testITApproximate32"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 2, algMaxErrors = 0}+ 1+ ".,.ABcdBA,a"+ ~?= "[6]"++-- String: Contains an even palindrome with punctuation+testITApproximate33 =+ "testITApproximate33"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 5}+ 0+ "bla\\AP.PA.bli"+ ~?= "\"bla\\AP.PA.bli\""++-- String: Contains an odd punctuation palindrome+testITApproximate34 =+ "testITApproximate34"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 4+ "blaAPA)bli"+ ~?= "No palindromes found"++-- String: Contains an odd punctuation palindrome+testITApproximate35 =+ "testITApproximate35"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 2+ "lepel”"+ ~?= "[5]"++-- String: Contains an odd gapped palindrome with punctuation+testITApproximate36 =+ "testITApproximate36"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 2+ "AB/cde/BA"+ ~?= "No palindromes found"++-- String: Contains an approximate, even palindrome with punctuation+testITApproximate37 =+ "testITApproximate37"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 0+ "(ka(b)ral)"+ ~?= "[3,3]"++-- String: Contains an approximate odd palindrome+testITApproximate38 =+ "testITApproximate38"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 3+ "za.*ts&tat/”"+ ~?= "\"tat\""++-- String: Contains no palindrome, with punctuation+testITApproximate39 =+ "testITApproximate39"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 2+ "Abc'd/.ef"+ ~?= "No palindromes found"++-- String: Contains no palindrome+testITApproximate40 =+ "testITApproximate40"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 3}+ 5+ "abcdef"+ ~?= "[6]"++-- String: Contains an even palindrome, contains punctuation and special characters+testITApproximate41 =+ "testITApproximate41"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 1+ "a’b/ba"+ ~?= "\"a’b/ba\""++-- String: Contains an even palindrome+testITApproximate42 =+ "testITApproximate42"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 2+ "abba"+ ~?= "\"abba\""++-- String: Contains an odd palindrome, contains punctuations and special characters+testITApproximate43 =+ "testITApproximate43"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 2+ "l.e.p’e;l"+ ~?= "\"l.e.p’e;l\""++-- String: Contains an odd palindrome+testITApproximate44 =+ "testITApproximate44"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 2}+ 3+ "lepel"+ ~?= "\"lepel\""++-- String: Contains an approximate even palindrome+testITApproximate45 =+ "testITApproximate45"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 2}+ 6+ "kab^ra.L"+ ~?= "[6]"++-- String: Contains an approximate even palindrome+testITApproximate46 =+ "testITApproximate46"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 2, algMaxErrors = 0}+ 0+ "kabral"+ ~?= "\"abra\""++-- String: Contains an approximate odd palindrome+testITApproximate47 =+ "testITApproximate47"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 1+ "zat.,s&tat"+ ~?= "[1,1,3,1,1,5,1]"++-- String: Contains an approximate odd palindrome+testITApproximate48 =+ "testITApproximate48"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 7}+ 2+ "zatstat"+ ~?= "\"zatstat\""++-- String: Contains an even gapped palindrome with punctuation+testITApproximate49 =+ "testITApproximate49"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 0+ "blaA\\Bc..dA;b.l#i"+ ~?= "[5,5,5]"++-- String: Contains an even gapped palindrome+testITApproximate50 =+ "testITApproximate50"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 2+ "blaABcdBAbli"+ ~?= "\"BAb\""++-- String: Contains an odd gapped palindrome+testITApproximate51 =+ "testITApproximate51"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 8}+ 6+ "A-B*cde)BA"+ ~?= "[7]"++-- String: Contains an odd gapped palindrome+testITApproximate52 =+ "testITApproximate52"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 3, algMaxErrors = 0}+ 2+ "ABcdeBA"+ ~?= "[3,3,3,3,7]"++-- String: Contains an even palindrome with punctuation+testITApproximate53 =+ "testITApproximate53"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 2}+ 3+ "\"blaAPPab'li"+ ~?= "\"Pab'li\"\n\"blaAPP\"\n\"blaAPPab'li\""++-- String: Contains an even palindrome+testITApproximate54 =+ "testITApproximate54"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 1+ "blaAPPAbl"+ ~?= "\"l\"\n\"b\"\n\"A\"\n\"APPA\"\n\"aA\"\n\"l\"\n\"b\""++-- String: Contains an odd palindrome+testITApproximate55 =+ "testITApproximate55"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 9}+ 4+ "blaAPAbli"+ ~?= "[9]"++-- String: Contains an odd palindrome with punctuation+testITApproximate56 =+ "testITApproximate56"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 3, algMaxErrors = 2}+ 4+ "/blaAPa.bl.i.bl"+ ~?= "\"Pa.bl.i.bl\"\n\"APa.bl.i.b\"\n\"blaAPa.bl.i.b\""++-- String: Contains no palindromes, has punctuation+testITApproximate57 =+ "testITApproximate57"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 0+ "aba gdc."+ ~?= "[2]"++-- String: Contains no palindromes+testITApproximate58 =+ "testITApproximate58"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 0+ "aba gdc"+ ~?= "[1,1]"++-- String: Contains an even palindrome, has punctuation+testITApproximate59 =+ "testITApproximate59"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 2+ "Hello. hi hi “hello”"+ ~?= "\"Hello. hi hi “hello\""++-- String: Contains an even palindrome+testITApproximate60 =+ "testITApproximate60"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 2}+ 6+ "hello hi hi hello"+ ~?= "No palindromes found"++-- String: Contains an odd palindrome, contains multiple spaces+testITApproximate61 =+ "testITApproximate61"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 3}+ 2+ "bye so bye?"+ ~?= "\"bye so bye\""++-- String: Contains an odd palindrome+testITApproximate62 =+ "testITApproximate62"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 9}+ 3+ "bye so bye"+ ~?= "\"bye so bye\""++-- String: Contains an approximate even palindrome with punctuation+testITApproximate63 =+ "testITApproximate63"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 2}+ 2+ "Fout. Weer. Hi. Hi. Niet. Goed."+ ~?= "\"Fout. Weer. Hi. Hi. Niet. Goed\""++-- String: Contains an approximate even palindrome+testITApproximate64 =+ "testITApproximate64"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 0+ "fout weer hi hi niet goed"+ ~?= "[4]"++-- String: Contains odd approximate palindrome, has punctuation+testITApproximate65 =+ "testITApproximate65"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 2+ "Nope / fout / goed / niet / midden / oeps / goed / nee / ook"+ ~?= "No palindromes found"++-- String: Contains odd approximate palindrome+testITApproximate66 =+ "testITApproximate66"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 9}+ 4+ "nope fout goed niet midden oeps goed nee ook"+ ~?= "[9]"++-- String: Contains a gapped even palindrome with punctuation+testITApproximate67 =+ "testITApproximate67"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 2, algMaxErrors = 0}+ 2+ "Doei&& hi ik b(e)n ??? een mens hi doei"+ ~?= "[2,2,2,2,2,2,2]"++-- String: Contains a gapped even palindrome+testITApproximate68 =+ "testITApproximate68"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 2, algMaxErrors = 1}+ 3+ "doei hi ik ben een mens hi doei"+ ~?= "\"een mens hi doei\"\n\"ben een mens hi\"\n\"hi ik ben een\"\n\"doei hi ik ben\"\n\"doei hi ik ben een mens hi doei\""++-- String: Contains a gapped odd palindrome with punctuation+testITApproximate69 =+ "testITApproximate69"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 3, algMaxErrors = 1}+ 4+ "dag h?i dri/e gap size. ... hi dag"+ ~?= "\"dag h?i dri/e gap size. ... hi dag\""++-- String: Contains a gapped odd palindrome+testITApproximate70 =+ "testITApproximate70"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ AlgApproximate{algGapSize = 3, algMaxErrors = 0}+ 2+ "dag hi drie gap size hi dag"+ ~?= "[7]"++-- String: Contains an even palindrome with punctuation+testITApproximate71 =+ "testITApproximate71"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 6}+ 0+ ",onzin, .dit pal\n pal dit/ gek"+ ~?= "\"onzin, .dit pal\n pal dit/ gek\""++-- String: Contains an even palindrome+testITApproximate72 =+ "testITApproximate72"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ 0+ "onzin dit pal pal dit gek"+ ~?= "[1,1,1,4,1]"++-- String: Contains an odd palindrome with punctuation+testITApproximate73 =+ "testITApproximate73"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgApproximate{algGapSize = 0, algMaxErrors = 1}+ 2+ "Onzin. pAl is. Pal gek"+ ~?= "\"Onzin. pAl is. Pal gek\""++-- String: Contains an odd palindrome+testITApproximate74 =+ "testITApproximate74"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ AlgApproximate{algGapSize = 0, algMaxErrors = 2}+ 3+ "onzin pal is pal gek"+ ~?= "\"onzin pal is pal gek\""
+ tests/ITLinear.hs view
@@ -0,0 +1,799 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module ITLinear (testListITLinear) where++import Test.HUnit (Test (..), (~:), (~?=))++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ , findPalindromesFormatted+ )++testListITLinear =+ [ testITLinear1+ , testITLinear2+ , testITLinear3+ , testITLinear4+ , testITLinear5+ , testITLinear6+ , testITLinear7+ , testITLinear8+ , testITLinear9+ , testITLinear10+ , testITLinear11+ , testITLinear12+ , testITLinear13+ , testITLinear14+ , testITLinear15+ , testITLinear16+ , testITLinear17+ , testITLinear18+ , testITLinear19+ , testITLinear20+ , testITLinear21+ , testITLinear22+ , testITLinear23+ , testITLinear24+ , testITLinear25+ , testITLinear26+ , testITLinear27+ , testITLinear28+ , testITLinear29+ , testITLinear30+ , testITLinear31+ , testITLinear32+ , testITLinear33+ , testITLinear34+ , testITLinear35+ , testITLinear36+ , testITLinear37+ , testITLinear38+ , testITLinear39+ , testITLinear40+ , testITLinear41+ , testITLinear42+ , testITLinear43+ , testITLinear44+ , testITLinear45+ , testITLinear46+ , testITLinear47+ , testITLinear48+ , testITLinear49+ , testITLinear50+ , testITLinear51+ , testITLinear52+ , testITLinear53+ , testITLinear54+ , testITLinear55+ , testITLinear56+ , testITLinear57+ , testITLinear58+ , testITLinear59+ , testITLinear60+ ]++-- String: Has punctuation, is even+testITLinear1 =+ "testITLinear1"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgLinear+ 0+ "A\nTAT"+ ~?= "\"A\nTAT\""++-- String: Even palindrome+testITLinear2 =+ "testITLinear2"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgLinear+ 10+ "abcdeedcba"+ ~?= "[10]"++-- String: Has punctuation, even nested palindromes+testITLinear3 =+ "testITLinear3"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgLinear+ 7+ "Word, word, word, palindrome. Word. Word, word."+ ~?= "\"Word, word, word, palindrome. Word. Word, word\""++-- String: No palindromes+testITLinear4 =+ "testITLinear4"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgLinear+ 0+ "nopalindromes"+ ~?= "[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]"++-- String: Even, has punctuation+testITLinear5 =+ "testITLinear5"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ AlgLinear+ 6+ "Has? ...A palindrome; palindrome a has."+ ~?= "[6]"++-- String: Even, has punctuation+testITLinear6 =+ "testITLinear6"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgLinear+ 3+ "~ehhe~"+ ~?= "\"~ehhe~\""++-- String: Not a palindrome. Contains no punctuation+testITLinear7 =+ "testITLinear7"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgLinear+ 10+ "abcdefghij"+ ~?= "No palindromes found"++-- String: Contains an even punctuation palindrome+testITLinear8 =+ "testITLinear8"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgLinear+ 0+ "b abba, ...bc"+ ~?= "[4]"++-- String: Contains an even palindrome+testITLinear9 =+ "testITLinear9"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgLinear+ 0+ "damittimad"+ ~?= "[0,1,0,1,0,1,0,1,0,1,10,1,0,1,0,1,0,1,0,1,0]"++-- String: Contains an even, nested palindrome+testITLinear10 =+ "testITLinear10"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgLinear+ 0+ "yabaddabadoo"+ ~?= "\"abaddaba\""++-- String: Contains an even palindrome, contains punctuation+testITLinear11 =+ "testITLinear11"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectAll+ AlgLinear+ 0+ "dam'itt! \\ I'm ?ad."+ ~?= "\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"dam'itt! \\ I'm ?ad\"\n\"\"\n\"\"\n\"I\"\n\"\"\n\"m\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\""++-- String: Contains a nested odd palindrome.+testITLinear12 =+ "testITLinear12"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgLinear+ 23+ "level mad dog a goddam level"+ ~?= "\"level mad dog a goddam level\""++-- String: Contains an odd palindrome+testITLinear13 =+ "testITLinear13"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectAll+ AlgLinear+ 3+ "abcdcba-"+ ~?= "[7]"++-- String: Contains an even palindrome+testITLinear14 =+ "testITLinear14"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgLinear+ 0+ "word palindrome palindrome word"+ ~?= "\"\"\n\"word\"\n\"\"\n\"palindrome\"\n\"word palindrome palindrome word\"\n\"palindrome\"\n\"\"\n\"word\"\n\"\""++-- String: Contains an odd punctuation palindrome+testITLinear15 =+ "testITLinear15"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgLinear+ 23+ "keybo{ .. }ardmash, samdrao byek'"+ ~?= "\"keybo{ .. }ardmash, samdrao byek\""++-- String: Contains no palindrome, contains punctuation+testITLinear16 =+ "testITLinear16"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgLinear+ 1+ "a#b, ,c^D efg[h"+ ~?= "\"a\"\n\"b\"\n\"c\"\n\"D\"\n\"e\"\n\"f\"\n\"g\"\n\"h\""++-- String: Contains no palindrome+testITLinear17 =+ "testITLinear17"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgLinear+ 3+ "nopalindromes"+ ~?= "No palindromes found"++-- String: Contains an odd palindrome with punctuation+testITLinear18 =+ "testITLinear18"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ AlgLinear+ 2+ "Odd palindrome, odd- ly enough :)"+ ~?= "\"Odd palindrome, odd\""++-- String: Contains an even punctuation palindrome+testITLinear19 =+ "testITLinear19"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgLinear+ 2+ ".ehhe~"+ ~?= "[4]"++-- String: Contains an even nested palindrome+testITLinear20 =+ "testITLinear20"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgLinear+ 4+ "ATATGCGCATAT"+ ~?= "[12]"++-- String: Contains an even nested palindrome+testITLinear21 =+ "testITLinear21"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ AlgLinear+ 10+ "That that, that that that -that that that refers to-"+ ~?= "No palindromes found"++-- String: Contains an odd palindrome+testITLinear22 =+ "testITLinear22"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ AlgLinear+ 5+ "A simple palindrome. Simple, a (ye)?"+ ~?= "[5]"++-- String: Contains a nested even palindrome+testITLinear23 =+ "testITLinear23"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgLinear+ 2+ "ATTCGGCGCAAT"+ ~?= "[2,2,2,4,2,2]"++-- String: Contains an even palindrom with punctuation+testITLinear24 =+ "testITLinear24"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgLinear+ 6+ "ab:c|+cba..."+ ~?= "\"ab:c|+cba\""++-- String: Contains an odd nested palindrome+testITLinear25 =+ "testITLinear25"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgLinear+ 0+ "ennestedetsenne"+ ~?= "\"\"\n\"e\"\n\"\"\n\"n\"\n\"enne\"\n\"n\"\n\"\"\n\"e\"\n\"\"\n\"s\"\n\"\"\n\"t\"\n\"\"\n\"e\"\n\"\"\n\"ennestedetsenne\"\n\"\"\n\"e\"\n\"\"\n\"t\"\n\"\"\n\"s\"\n\"\"\n\"e\"\n\"\"\n\"n\"\n\"enne\"\n\"n\"\n\"\"\n\"e\"\n\"\""++-- String: Contains an odd palindrome with punctuation+testITLinear26 =+ "testITLinear26"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgLinear+ 7+ "*abc-dc ba#"+ ~?= "[7]"++-- String: Contains a nested odd palindrome+testITLinear27 =+ "testITLinear27"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ AlgLinear+ 0+ "nested odd word odd palindrome odd word odd nested"+ ~?= "[9]"++-- String: Contains an even palindrome, contains punctuation+testITLinear28 =+ "testITLinear28"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgLinear+ 0+ "TATG\nCGATC GCA.TAGC"+ ~?= "[14]"++-- String: Contains an even nested palindrome with punctuation+testITLinear29 =+ "testITLinear29"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgLinear+ 0+ "d*eif:ied a-+bba deifie;d!"+ ~?= "\"d*eif:ied a-+bba deifie;d\""++-- String: Contains an odd nested palindrome+testITLinear30 =+ "testITLinear30"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgLinear+ 0+ "abcbababcba"+ ~?= "[0,1,0,1,0,5,0,1,0,3,0,11,0,3,0,1,0,5,0,1,0,1,0]"++-- String: Contains an even nested palindrome with punctuation+testITLinear31 =+ "testITLinear31"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgLinear+ 4+ "AT\nATAT-A\tT"+ ~?= "[8]"++-- String: Contains an even palindrome+testITLinear32 =+ "testITLinear32"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgLinear+ 18+ "evil is a deed as I live"+ ~?= "\"evil is a deed as I live\""++-- String: Contains an even nested palindrome with punctuation+testITLinear33 =+ "testITLinear33"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgLinear+ 0+ "abbaccabba"+ ~?= "[0,1,0,1,4,1,0,1,0,1,10,1,0,1,0,1,4,1,0,1,0]"++-- String: Contains an even palindrome with punctuation+testITLinear34 =+ "testITLinear34"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectAll+ AlgLinear+ 14+ "TATG\nCGATC GCA.TA"+ ~?= "\"TATG\nCGATC GCA.TA\""++-- String: Contains no palindrome, contains punctuation+testITLinear35 =+ "testITLinear35"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ AlgLinear+ 3+ "Thi,s is not a p-alindro'me."+ ~?= "No palindromes found"++-- String: Contains an odd palindrome with punctuation+testITLinear36 =+ "testITLinear36"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgLinear+ 3+ "A simple palindrome. Simple, a (ye)?"+ ~?= "\"A simple palindrome. Simple, a\""++-- String: Contains an even nested palindrome+testITLinear37 =+ "testITLinear37"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectAll+ AlgLinear+ 1+ "d*eif:ied a-+bba deifie;d!"+ ~?= "\"d\"\n\"d*eif:ied\"\n\"a\"\n\"d*eif:ied a-+bba deifie;d\"\n\"deifie;d\"\n\"d\""++-- String: Contains no palindrome, contains punctuation+testITLinear38 =+ "testITLinear38"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectAll+ AlgLinear+ 21+ "Thi,s is not a p-alindro'me."+ ~?= "No palindromes found"++-- String: Contains an even palindrome+testITLinear39 =+ "testITLinear39"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgLinear+ 0+ "ATGCGCATTA"+ ~?= "\"ATGCGCAT\""++-- String: Contains no palindrome, contains punctuation+testITLinear40 =+ "testITLinear40"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgLinear+ 2+ "AN\nTC\tAGTC"+ ~?= "No palindromes found"++-- String: Contains no palindrome+testITLinear41 =+ "testITLinear41"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgLinear+ 1+ "NNNNNNNNNN"+ ~?= "No palindromes found"++-- String: Contains an odd punctuation palindrome+testITLinear42 =+ "testITLinear42"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgLinear+ 0+ "\nodddo!"+ ~?= "[0,1,0,1,0,1,2,5,2,1,0,1,0,1,0]"++-- String: Contains an odd palindrome+testITLinear43 =+ "testITLinear43"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgLinear+ 1+ "releveler"+ ~?= "\"r\"\n\"e\"\n\"ele\"\n\"e\"\n\"releveler\"\n\"e\"\n\"ele\"\n\"e\"\n\"r\""++-- String: Contains an odd nested palindrome+testITLinear44 =+ "testITLinear44"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgLinear+ 0+ "hi madam im adam bye"+ ~?= "\"madam im adam\""++-- String: Contains an odd nested palindrome+testITLinear45 =+ "testITLinear45"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ AlgLinear+ 3+ "Oi! You there! You! Stop!"+ ~?= "\"You there! You\""++-- String: Contains an odd nested palindrome+testITLinear46 =+ "testITLinear46"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgLinear+ 0+ "You! Rev Ile deliver, now!"+ ~?= "\"Rev Ile deliver\""++-- String: Contains an odd palindrome with punctuation+testITLinear47 =+ "testITLinear47"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgLinear+ 0+ "Revile.... Deliver!"+ ~?= "[0,1,0,1,0,1,0,1,0,1,0,1,0,13,0,1,0,1,0,1,0,1,0,1,0,1,0]"++-- String: Contains an even nested palindrome with punctuation+testITLinear48 =+ "testITLinear48"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgLinear+ 0+ "It's high noon..."+ ~?= "\"\"\n\"I\"\n\"\"\n\"t\"\n\"\"\n\"'\"\n\"\"\n\"s\"\n\"\"\n\" \"\n\"\"\n\"h\"\n\"\"\n\"i\"\n\"\"\n\"g\"\n\"\"\n\"h\"\n\"\"\n\" \"\n\"\"\n\"n\"\n\"\"\n\"o\"\n\"noon\"\n\"o\"\n\"\"\n\"n\"\n\"\"\n\".\"\n\"..\"\n\"...\"\n\"..\"\n\".\"\n\"\""++-- String: Contains an odd palindrome with punctuation+testITLinear49 =+ "testITLinear49"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgLinear+ 3+ "!dammit_timmad!"+ ~?= "\"!dammit_timmad!\""++-- String: Contains no punctuation palindrome+testITLinear50 =+ "testITLinear50"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgLinear+ 0+ "begone enoge"+ ~?= "[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"++-- String: Contains an odd and an even palindrome+testITLinear51 =+ "testITLinear51"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgLinear+ 2+ "madamoiselle"+ ~?= "[5,4]"++-- String: Contains an even palindrome with punctuation+testITLinear52 =+ "testITLinear52"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ AlgLinear+ 4+ "Hello? my.... my .. hello!"+ ~?= "[4]"++-- String: Contains an even punctuation palindrome+testITLinear53 =+ "testITLinear53"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgLinear+ 2+ "\nAT CG /AT/"+ ~?= "[6]"++-- String: Contains an even palindrome+testITLinear54 =+ "testITLinear54"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgLinear+ 4+ "CGCG"+ ~?= "\"CGCG\""++-- String: Contains an odd nested palindrome+testITLinear55 =+ "testITLinear55"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgLinear+ 0+ "hi madam i madam bye"+ ~?= "[15]"++-- String: Contains an even nested palindrome+testITLinear56 =+ "testITLinear56"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgLinear+ 6+ "NNTATATATANN"+ ~?= "[8]"++-- String: Contains an even palindrome with punctuation+testITLinear57 =+ "testITLinear57"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgLinear+ 5+ "!ma;dd;am!"+ ~?= "[10]"++-- String: Contains no palindrome+testITLinear58 =+ "testITLinear58"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ AlgLinear+ 2+ "word1 word2 word3 word4"+ ~?= "No palindromes found"++-- String: Contains an odd palindrome+testITLinear59 =+ "testITLinear59"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgLinear+ 9+ "Releveler"+ ~?= "\"Releveler\""++-- String: Contains an odd punctuation palindrome+testITLinear60 =+ "testITLinear60"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgLinear+ 5+ "\nOdd do!"+ ~?= "No palindromes found"
+ tests/ITQuadratic.hs view
@@ -0,0 +1,981 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module ITQuadratic (testListITQuadratic) where++import Test.HUnit (Test (..), (~:), (~?=))++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ , findPalindromesFormatted+ )++testListITQuadratic =+ [ testITQuadratic1+ , testITQuadratic2+ , testITQuadratic3+ , testITQuadratic4+ , testITQuadratic5+ , testITQuadratic6+ , testITQuadratic7+ , testITQuadratic8+ , testITQuadratic9+ , testITQuadratic10+ , testITQuadratic11+ , testITQuadratic12+ , testITQuadratic13+ , testITQuadratic14+ , testITQuadratic15+ , testITQuadratic16+ , testITQuadratic17+ , testITQuadratic18+ , testITQuadratic19+ , testITQuadratic20+ , testITQuadratic21+ , testITQuadratic22+ , testITQuadratic23+ , testITQuadratic24+ , testITQuadratic25+ , testITQuadratic26+ , testITQuadratic27+ , testITQuadratic28+ , testITQuadratic29+ , testITQuadratic30+ , testITQuadratic31+ , testITQuadratic32+ , testITQuadratic33+ , testITQuadratic34+ , testITQuadratic35+ , testITQuadratic36+ , testITQuadratic37+ , testITQuadratic38+ , testITQuadratic39+ , testITQuadratic40+ , testITQuadratic41+ , testITQuadratic42+ , testITQuadratic43+ , testITQuadratic44+ , testITQuadratic45+ , testITQuadratic46+ , testITQuadratic47+ , testITQuadratic48+ , testITQuadratic49+ , testITQuadratic50+ , testITQuadratic51+ , testITQuadratic52+ , testITQuadratic53+ , testITQuadratic54+ , testITQuadratic55+ , testITQuadratic56+ , testITQuadratic57+ , testITQuadratic58+ , testITQuadratic59+ , testITQuadratic60+ , testITQuadratic61+ , testITQuadratic62+ , testITQuadratic63+ , testITQuadratic64+ , testITQuadratic65+ , testITQuadratic66+ , testITQuadratic67+ , testITQuadratic68+ , testITQuadratic69+ , testITQuadratic70+ , testITQuadratic71+ , testITQuadratic72+ , testITQuadratic73+ , testITQuadratic74+ ]++-- String: Contains a gapped palindrome with punctuation+testITQuadratic1 =+ "testITQuadratic1"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 0+ "AG\nTC"+ ~?= "[2,2,2]"++-- String: Contains a nested palindrome with punctuation+testITQuadratic2 =+ "testITQuadratic2"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 4+ "A&T-AT"+ ~?= "\"A&T-AT\""++-- String: Does not contain a palindrome+testITQuadratic3 =+ "testITQuadratic3"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 4, algMaxErrors = 4}+ 1+ "AGTC"+ ~?= "[2,4,2]"++-- String: Contains a gapped even palindrome+testITQuadratic4 =+ "testITQuadratic4"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 2, algMaxErrors = 0}+ 2+ "ACCT"+ ~?= "[2,4,2]"++-- String: Contains an odd-gapped dna palindrome+testITQuadratic5 =+ "testITQuadratic5"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 1, algMaxErrors = 2}+ 3+ "“AC\nTA..,TTCT”"+ ~?= "\"AC\nT\"\n\"AC\nTA\"\n\"AC\nTA..,T\"\n\"AC\nTA..,TT\"\n\"C\nTA..,TT\"\n\"AC\nTA..,TTCT\"\n\"C\nTA..,TTCT\"\n\"A..,TTC\"\n\"A..,TTCT\"\n\"TTCT\"\n\"TCT\""++-- String: Contains an even nested palindrome+testITQuadratic6 =+ "testITQuadratic6"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 3+ "ATAT"+ ~?= "[4]"++-- String: Contains an even gapped palindrome with punctuation+testITQuadratic7 =+ "testITQuadratic7"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 4, algMaxErrors = 4}+ 2+ "Ac\nC,T”"+ ~?= "\"Ac\nC,T\""++-- String: Contains an odd gapped palindrome+testITQuadratic8 =+ "testITQuadratic8"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 1, algMaxErrors = 2}+ 2+ "ACTATTCT"+ ~?= "\"ACTATTCT\""++-- String: Contains an odd gapped palindrome+testITQuadratic9 =+ "testITQuadratic9"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 2, algMaxErrors = 0}+ 1+ "AGGGT"+ ~?= "[2,2,2,2]"++-- String: Contains an odd gapped palindrome with punctuation+testITQuadratic10 =+ "testITQuadratic10"+ ~: findPalindromesFormatted+ VarDNA+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 5, algMaxErrors = 5}+ 0+ "A;G;G;G;T"+ ~?= "\"\"\n\"A\"\n\"A;G\"\n\"A;G;G\"\n\"A;G;G;G\"\n\"A;G;G;G;T\"\n\"G;G;G;T\"\n\"G;G;T\"\n\"G;T\"\n\"T\"\n\"\""++-- String: Contains a palindrome with punctuation+testITQuadratic11 =+ "testITQuadratic11"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 6+ "Ac.G-CgA "+ ~?= "[6]"++-- String: Contains an even palindrome+testITQuadratic12 =+ "testITQuadratic12"+ ~: findPalindromesFormatted+ VarDNA+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 6+ "ACGCGA"+ ~?= "No palindromes found"++-- String: Contains an approximate palindrome+testITQuadratic13 =+ "testITQuadratic13"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 4+ "kabral"+ ~?= "\"abra\""++-- String: Contains no palindrome+testITQuadratic14 =+ "testITQuadratic14"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 6, algMaxErrors = 6}+ 1+ "abcdef"+ ~?= "[1,2,3,4,5,6,5,4,3,2,1]"++-- String: Contains an even palindrome with punctuation+testITQuadratic15 =+ "testITQuadratic15"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 1, algMaxErrors = 2}+ 3+ "a’b/ba"+ ~?= "[6]"++-- String: Contains an even palindrome+testITQuadratic16 =+ "testITQuadratic16"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 2, algMaxErrors = 0}+ 0+ "abba"+ ~?= "\"abba\""++-- String: Contains an odd palindrome with punctuation. Contains a special character.+testITQuadratic17 =+ "testITQuadratic17"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 3+ "l.e.p’e;l"+ ~?= "[3]"++-- String: Contains an odd palindrome+testITQuadratic18 =+ "testITQuadratic18"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 5, algMaxErrors = 5}+ 2+ "lepel"+ ~?= "\"lepel\""++-- String: Contains an approximate palindrome with punctuation+testITQuadratic19 =+ "testITQuadratic19"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 0+ "kab^ra.L"+ ~?= "[5]"++-- String: Contains no palindrome, contains punctuation+testITQuadratic20 =+ "testITQuadratic20"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 0+ "Abc'd/.ef"+ ~?= "\"A\"\n\"b\"\n\"c\"\n\"'\"\n\"d\"\n\"/\"\n\".\"\n\"e\"\n\"f\""++-- String: Contains an odd approximate palindrome, with punctuation+testITQuadratic21 =+ "testITQuadratic21"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 10, algMaxErrors = 10}+ 2+ "zat.,s&tat"+ ~?= "[2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2]"++-- String: Contains an odd approximate palindrome+testITQuadratic22 =+ "testITQuadratic22"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 2, algMaxErrors = 0}+ 2+ "zatstat"+ ~?= "[2,2,2,5,2,2,3,2]"++-- String: Contains an even gapped palindrome, with punctuation+testITQuadratic23 =+ "testITQuadratic23"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 1, algMaxErrors = 2}+ 5+ "blaA\\Bc..dA;b.l#i"+ ~?= "\"blaA\\\"\n\"laA\\B\"\n\"aA\\Bc\"\n\"A\\Bc.\"\n\"\\Bc..\"\n\"Bc..d\"\n\"Bc..dA\"\n\"c..dA\"\n\"..dA;\"\n\"..dA;b.\"\n\".dA;b.\"\n\"dA;b.\"\n\"A;b.l\"\n\";b.l#\"\n\"b.l#i\""++-- String: Contains an even gapped palindrome+testITQuadratic24 =+ "testITQuadratic24"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 1+ "blaABcdBAbli"+ ~?= "[1,1,1,1,1,1,1,1,1,1,1,1]"++-- String: Contains an odd gapped palindrome with punctuation+testITQuadratic25 =+ "testITQuadratic25"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 10, algMaxErrors = 10}+ 2+ "A-B*cde)BA"+ ~?= "\"A-B*cde)BA\""++-- String: Contains an odd gapped palindrome+testITQuadratic26 =+ "testITQuadratic26"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 3, algMaxErrors = 2}+ 4+ "ABcdeBA"+ ~?= "\"ABcdeBA\""++-- String: Contains an even palindrome, with punctuation, with special characters+testITQuadratic27 =+ "testITQuadratic27"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 2, algMaxErrors = 0}+ 3+ "\"blaAPPab’li "+ ~?= "No palindromes found"++-- String: Contains an even palindrome+testITQuadratic28 =+ "testITQuadratic28"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 9, algMaxErrors = 9}+ 0+ "blaAPPAbl"+ ~?= "\"\"\n\"b\"\n\"bl\"\n\"bla\"\n\"blaA\"\n\"blaAP\"\n\"blaAPP\"\n\"blaAPPA\"\n\"blaAPPAb\"\n\"blaAPPAbl\"\n\"laAPPAbl\"\n\"aAPPAbl\"\n\"APPAbl\"\n\"PPAbl\"\n\"PAbl\"\n\"Abl\"\n\"bl\"\n\"l\"\n\"\""++-- String: Contains an odd palindrome+testITQuadratic29 =+ "testITQuadratic29"+ ~: findPalindromesFormatted+ VarPlain+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 0+ "blaAPAbli"+ ~?= "[0,1,0,1,0,1,0,1,0,3,0,1,0,1,0,1,0,1,0]"++-- String: Contains an odd palindrome with punctuation+testITQuadratic30 =+ "testITQuadratic30"+ ~: findPalindromesFormatted+ VarPlain+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 4+ "/blaAPa.bl.i"+ ~?= "\"aAPa\"\n\".bl.\""++-- String: Contains an even palindrome with punctuation+testITQuadratic31 =+ "testITQuadratic31"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 3, algMaxErrors = 2}+ 2+ "/abba/"+ ~?= "\"abba\""++-- String: Conains an even gapped palindrome+testITQuadratic32 =+ "testITQuadratic32"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 2, algMaxErrors = 0}+ 1+ "ABcdBA"+ ~?= "[6]"++-- String: Contains an even palindrome with punctuation+testITQuadratic33 =+ "testITQuadratic33"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 10, algMaxErrors = 5}+ 0+ "bla\\AP.PA.bli"+ ~?= "\"\"\n\"\"\n\"\"\n\"bla\"\n\"\"\n\"bla\\AP\"\n\"\"\n\"bla\\AP.PA\"\n\"AP\"\n\"\"\n\"bla\\AP.PA.bli\"\n\"\"\n\"PA\"\n\"AP.PA.bli\"\n\"\"\n\"PA.bli\"\n\"\"\n\"bli\"\n\"\"\n\"\"\n\"\""++-- String: Contains an odd punctuation palindrome+testITQuadratic34 =+ "testITQuadratic34"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 3+ "bla(APA)bli"+ ~?= "[3,3,3]"++-- String: Contains an odd punctuation palindrome+testITQuadratic35 =+ "testITQuadratic35"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 2+ "lepel”"+ ~?= "[5]"++-- String: Contains an odd gapped palindrome with punctuation+testITQuadratic36 =+ "testITQuadratic36"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 2+ "AB/cde/BA"+ ~?= "No palindromes found"++-- String: Contains an approximate, even palindrome with punctuation+testITQuadratic37 =+ "testITQuadratic37"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 0+ "(ka(b)ral)"+ ~?= "[3,3]"++-- String: Contains an approximate odd palindrome+testITQuadratic38 =+ "testITQuadratic38"+ ~: findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 3+ "za.*ts&tat/”"+ ~?= "\"tat\""++-- String: Contains no palindrome, with punctuation+testITQuadratic39 =+ "testITQuadratic39"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 2, algMaxErrors = 0}+ 2+ "Abc'd/.ef"+ ~?= "[2,2,2,2,2]"++-- String: Contains no palindrome+testITQuadratic40 =+ "testITQuadratic40"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 6, algMaxErrors = 3}+ 5+ "abcdef"+ ~?= "[6]"++-- String: Contains an even palindrome, contains punctuation and special characters+testITQuadratic41 =+ "testITQuadratic41"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 1+ "a’b/ba"+ ~?= "\"a\8217b/ba\""++-- String: Contains an even palindrome+testITQuadratic42 =+ "testITQuadratic42"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 2+ "abba"+ ~?= "\"abba\""++-- String: Contains an odd palindrome, contains punctuations and special characters+testITQuadratic43 =+ "testITQuadratic43"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 2+ "l.e.p’e;l"+ ~?= "\"l.e.p’e;l\""++-- String: Contains an odd palindrome+testITQuadratic44 =+ "testITQuadratic44"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 5, algMaxErrors = 2}+ 3+ "lepel"+ ~?= "\"lep\"\n\"lepe\"\n\"lepel\"\n\"epel\"\n\"pel\""++-- String: Contains an approximate even palindrome+testITQuadratic45 =+ "testITQuadratic45"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 1, algMaxErrors = 2}+ 5+ "kab^ra.L"+ ~?= "[6]"++-- String: Contains an approximate even palindrome+testITQuadratic46 =+ "testITQuadratic46"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 2, algMaxErrors = 0}+ 0+ "kabral"+ ~?= "\"abra\""++-- String: Contains an approximate odd palindrome+testITQuadratic47 =+ "testITQuadratic47"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 1+ "zat.,s&tat"+ ~?= "[1,1,1,5,1,3,1]"++-- String: Contains an approximate odd palindrome+testITQuadratic48 =+ "testITQuadratic48"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 7, algMaxErrors = 7}+ 2+ "zatstat"+ ~?= "\"zatstat\""++-- String: Contains an even gapped palindrome with punctuation+testITQuadratic49 =+ "testITQuadratic49"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 1}+ 0+ "blaA\\Bc..dA;b.l#i"+ ~?= "[5,5,5]"++-- String: Contains an even gapped palindrome+testITQuadratic50 =+ "testITQuadratic50"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ 2+ "blaABcdBAbli"+ ~?= "\"BAb\""++-- String: Contains an odd gapped palindrome+testITQuadratic51 =+ "testITQuadratic51"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 0, algMaxErrors = 8}+ 6+ "A-B*cde)BA"+ ~?= "[6,7,6]"++-- String: Contains an odd gapped palindrome+testITQuadratic52 =+ "testITQuadratic52"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectAll+ AlgQuadratic{algGapSize = 3, algMaxErrors = 0}+ 2+ "ABcdeBA"+ ~?= "[2,3,2,3,2,7,2,3,2,3,2]"++-- String: Contains an even palindrome with punctuation+testITQuadratic53 =+ "testITQuadratic53"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ AlgQuadratic{algGapSize = 1, algMaxErrors = 2}+ 3+ "\"blaAPPab'li"+ ~?= "\"bla\"\n\"blaA\"\n\"blaAP\"\n\"blaAPP\"\n\"laAPP\"\n\"aAPP\"\n\"laAPPab\"\n\"blaAPPab'li\"\n\"APPab\"\n\"PPab\"\n\"PPab'l\"\n\"Pab'l\"\n\"Pab'li\"\n\"ab'li\"\n\"b'li\""++-- String: Contains an even palindrome+testITQuadratic54 =+ "testITQuadratic54"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectAll+ (AlgQuadratic 0 0)+ 1+ "blaAPPAbl"+ ~?= "\"b\"\n\"l\"\n\"a\"\n\"aA\"\n\"A\"\n\"P\"\n\"APPA\"\n\"P\"\n\"A\"\n\"b\"\n\"l\""++-- String: Contains an odd palindrome+testITQuadratic55 =+ "testITQuadratic55"+ ~: findPalindromesFormatted+ VarText+ FormatLength+ SelectLongest+ (AlgQuadratic 9 9)+ 4+ "blaAPAbli"+ ~?= "[9]"++-- String: Contains an odd palindrome with punctuation+testITQuadratic56 =+ "testITQuadratic56"+ ~: findPalindromesFormatted+ VarText+ FormatText+ SelectLongest+ (AlgQuadratic 3 2)+ 4+ "/blaAPa.bl.i.bl"+ ~?= "\"blaAPa.bl.i\""++-- String: Contains no palindromes, has punctuation+testITQuadratic57 =+ "testITQuadratic57"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ (AlgQuadratic 0 1)+ 0+ "aba gdc."+ ~?= "[2]"++-- String: Contains no palindromes+testITQuadratic58 =+ "testITQuadratic58"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ (AlgQuadratic 0 0)+ 0+ "aba gdc"+ ~?= "[0,1,0,1,0]"++-- String: Contains an even palindrome, has punctuation+testITQuadratic59 =+ "testITQuadratic59"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ (AlgQuadratic 0 1)+ 2+ "Hello. hi hi “hello”"+ ~?= "\"Hello. hi\"\n\"Hello. hi hi\"\n\"Hello. hi hi “hello\"\n\"hi hi “hello\"\n\"hi “hello\""++-- String: Contains an even palindrome+testITQuadratic60 =+ "testITQuadratic60"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ (AlgQuadratic 1 2)+ 6+ "hello hi hi hello"+ ~?= "No palindromes found"++-- String: Contains an odd palindrome, contains multiple spaces+testITQuadratic61 =+ "testITQuadratic61"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ (AlgQuadratic 3 3)+ 2+ "bye so bye?"+ ~?= "\"bye so\"\n\"bye so bye\"\n\"so bye\""++-- String: Contains an odd palindrome+testITQuadratic62 =+ "testITQuadratic62"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ (AlgQuadratic 0 9)+ 3+ "bye so bye"+ ~?= "\"bye so bye\""++-- String: Contains an approximate even palindrome with punctuation+testITQuadratic63 =+ "testITQuadratic63"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ (AlgQuadratic 0 2)+ 2+ "Fout. Weer. Hi. Hi. Niet. Goed."+ ~?= "\"Fout. Weer. Hi. Hi. Niet. Goed\""++-- String: Contains an approximate even palindrome+testITQuadratic64 =+ "testITQuadratic64"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ (AlgQuadratic 0 1)+ 0+ "fout weer hi hi niet goed"+ ~?= "[4]"++-- String: Contains odd approximate palindrome, has punctuation+testITQuadratic65 =+ "testITQuadratic65"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ (AlgQuadratic 0 0)+ 2+ "Nope / fout / goed / niet / midden / oeps / goed / nee / ook"+ ~?= "No palindromes found"++-- String: Contains odd approximate palindrome+testITQuadratic66 =+ "testITQuadratic66"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ (AlgQuadratic 9 9)+ 4+ "nope fout goed niet midden oeps goed nee ook"+ ~?= "[4,5,6,7,8,9,8,7,6,5,4]"++-- String: Contains a gapped even palindrome with punctuation+testITQuadratic67 =+ "testITQuadratic67"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ (AlgQuadratic 2 0)+ 2+ "Doei&& hi ik b(e)n ??? een mens hi doei"+ ~?= "[2,2,2,2,2,2,2]"++-- String: Contains a gapped even palindrome+testITQuadratic68 =+ "testITQuadratic68"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ (AlgQuadratic 2 1)+ 3+ "doei hi ik ben een mens hi doei"+ ~?= "\"doei hi ik\"\n\"doei hi ik ben\"\n\"hi ik ben\"\n\"hi ik ben een\"\n\"ik ben een\"\n\"doei hi ik ben een mens hi doei\"\n\"ben een mens\"\n\"ben een mens hi\"\n\"een mens hi\"\n\"een mens hi doei\"\n\"mens hi doei\""++-- String: Contains a gapped odd palindrome with punctuation+testITQuadratic69 =+ "testITQuadratic69"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ (AlgQuadratic 3 1)+ 4+ "dag h?i dri/e gap size. ... hi dag"+ ~?= "\"dag h?i dri/e gap size. ... hi dag\""++-- String: Contains a gapped odd palindrome+testITQuadratic70 =+ "testITQuadratic70"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectLongest+ (AlgQuadratic 3 0)+ 2+ "dag hi drie gap size hi dag"+ ~?= "[7]"++-- String: Contains an even palindrome with punctuation+testITQuadratic71 =+ "testITQuadratic71"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ (AlgQuadratic 6 6)+ 0+ ",onzin, .dit pal\n pal dit/ gek"+ ~?= "\"\"\n\"onzin\"\n\"onzin, .dit\"\n\"onzin, .dit pal\"\n\"onzin, .dit pal\n pal\"\n\"onzin, .dit pal\n pal dit\"\n\"onzin, .dit pal\n pal dit/ gek\"\n\"dit pal\n pal dit/ gek\"\n\"pal\n pal dit/ gek\"\n\"pal dit/ gek\"\n\"dit/ gek\"\n\"gek\"\n\"\""++-- String: Contains an even palindrome+testITQuadratic72 =+ "testITQuadratic72"+ ~: findPalindromesFormatted+ VarWord+ FormatLength+ SelectAll+ (AlgQuadratic 0 0)+ 0+ "onzin dit pal pal dit gek"+ ~?= "[0,1,0,1,0,1,4,1,0,1,0,1,0]"++-- String: Contains an odd palindrome with punctuation+testITQuadratic73 =+ "testITQuadratic73"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectAll+ (AlgQuadratic 0 1)+ 2+ "Onzin. pAl is. Pal gek"+ ~?= "\"Onzin. pAl\"\n\"Onzin. pAl is\"\n\"pAl is\"\n\"Onzin. pAl is. Pal gek\"\n\"is. Pal\"\n\"is. Pal gek\"\n\"Pal gek\""++-- String: Contains an odd palindrome+testITQuadratic74 =+ "testITQuadratic74"+ ~: findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ (AlgQuadratic 1 2)+ 3+ "onzin pal is pal gek"+ ~?= "\"onzin pal is pal gek\""
tests/Main.hs view
@@ -1,240 +1,64 @@--------------------------------------------------------------------------------- --- Module : tests.Main--- Copyright : (c) 2007 - 2013 Johan Jeuring--- License : BSD3------ Maintainer : johan@jeuring.net--- Stability : experimental--- Portability : portable-----------------------------------------------------------------------------------module Main where---import Data.Array-import Data.Char--import Test.QuickCheck-import Test.HUnit--import Data.Algorithms.Palindromes.Palindromes -import Data.Algorithms.Palindromes.PalindromesUtils-import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as BC---longestTextPalindrome = Data.Algorithms.Palindromes.Palindromes.palindrome (Just Text) (Just Longest) (Just Linear) Nothing Nothing Nothing-longestWordPalindrome = Data.Algorithms.Palindromes.Palindromes.palindrome (Just Word) (Just Longest) (Just Linear) Nothing Nothing Nothing--propPalindromesAroundCentres :: Property-propPalindromesAroundCentres = - forAll (arbitrary:: Gen [Char]) $ - \l -> let input = BC.pack l- in palindromesAroundCentres (Just Text) (Just Linear) Nothing Nothing input == longestPalindromesQ input--longestPalindromesQ :: B.ByteString -> [Int]-longestPalindromesQ input = - let (afirst,alast) = (0,B.length input - 1)- positions = [0 .. 2*(alast-afirst+1)]- in map (lengthPalindromeAround input) positions--lengthPalindromeAround :: B.ByteString - -> Int - -> Int-lengthPalindromeAround input position - | even position = - extendPalindromeAround (afirst+pos-1) (afirst+pos) - | odd position = - extendPalindromeAround (afirst+pos-1) (afirst+pos+1) - where pos = div position 2- (afirst,alast) = (0,B.length input -1)- extendPalindromeAround start end = - if start < 0 - || end > alast-afirst - || B.index input start /= B.index input end- then end-start-1- else extendPalindromeAround (start-1) (end+1) --propTextPalindrome :: Property-propTextPalindrome =- forAll (arbitrary:: Gen [Char]) $ - \l -> let ltp = longestTextPalindrome (BC.pack l)- ltp' = map toLower (filter myIsLetterC (unescape ltp))- in ltp' == reverse ltp'--unescape :: String -> String-unescape [] = []-unescape cs = case readLitChar cs of- (c,rest):xs -> c:unescape rest- [] -> [] --testTextPalindrome1, testTextPalindrome2, testTextPalindrome3, testTextPalindrome4, - testTextPalindrome5, testTextPalindrome6, testTextPalindrome7, testTextPalindrome8,- testTextPalindrome9, testTextPalindrome10, testTextPalindrome11 :: Test--testWordPalindrome1, testWordPalindrome2, testWordPalindrome3, testWordPalindrome4,- testWordPalindrome5, testWordPalindrome6 :: Test--testTextPalindrome1 =- TestCase (assertEqual - "textPalindrome1" - "\"a,ba.\"" - (longestTextPalindrome (BC.pack "abcdea,ba."))- )-testTextPalindrome2 =- TestCase (assertEqual - "textPalindrome2" - "\"a,ba\"" - (longestTextPalindrome (BC.pack "abcdea,ba"))- )-testTextPalindrome3 =- TestCase (assertEqual - "textPalindrome3" - "\".a,ba\"" - (longestTextPalindrome (BC.pack "abcde.a,ba"))- )-testTextPalindrome4 =- TestCase (assertEqual - "textPalindrome4" - "\".a,ba\"" - (longestTextPalindrome (BC.pack "abcde.a,baf"))- )-testTextPalindrome5 =- TestCase (assertEqual - "textPalindrome5" - "\".ab,a\"" - (longestTextPalindrome (BC.pack ".ab,acdef"))- )-testTextPalindrome6 =- TestCase (assertEqual - "textPalindrome6" - "\"ab,a\"" - (longestTextPalindrome (BC.pack "ab,acdef"))- )-testTextPalindrome7 =- TestCase (assertEqual - "textPalindrome7" - "\"ab,a.\"" - (longestTextPalindrome (BC.pack "ab,a.cdef"))- )-testTextPalindrome8 =- TestCase (assertEqual - "textPalindrome8" - "\".ab,a.\"" - (longestTextPalindrome (BC.pack "g.ab,a.cdef"))- )-testTextPalindrome9 =- TestCase (assertEqual - "textPalindrome9" - "" - (longestTextPalindrome B.empty)- )--testTextPalindrome10 =- TestCase (do string <- B.readFile "/Users/johan/Documents/Palindromes/Software/staff.johanj.palindromes/trunk/examples/palindromes/Damnitimmad.txt"- assertEqual - "textPalindrome10" - (concatMap (\c -> case c of- '\n' -> "\\n" - '\"' -> "\""--""\\\""- d -> [d]- )- (show string)- )- (longestTextPalindrome string)- )--testTextPalindrome11 =- TestCase (do string <- B.readFile "/Users/johan/Documents/Palindromes/Software/staff.johanj.palindromes/trunk/examples/palindromes/pal17.txt"- assertEqual - "textPalindrome11" - (concatMap (\c -> case c of- '\n' -> "\\n" - '\"' -> "\""- d -> [d]- )- (show string))- (longestTextPalindrome string)- )--testWordPalindrome1 =- TestCase (assertEqual- "wordPalindrome" - "\" is non si, \"" - (longestWordPalindrome (BC.pack "what is non si, not?"))- )--testWordPalindrome2 =- TestCase (assertEqual- "wordPalindrome" - "\" is non si\"" - (longestWordPalindrome (BC.pack "what is non si"))- )--testWordPalindrome3 =- TestCase (assertEqual- "wordPalindrome" - "\"is non si, \"" - (longestWordPalindrome (BC.pack "is non si, not?"))- )--testWordPalindrome4 =- TestCase (assertEqual- "wordPalindrome" - "" - (longestWordPalindrome (BC.pack "aaaaba"))- )+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course. -testWordPalindrome5 =- TestCase (assertEqual- "wordPalindrome" - "\" a\"" - (longestWordPalindrome (BC.pack "aaaab a"))- )+© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}+module Main (main) where -testWordPalindrome6 =- TestCase (assertEqual- "wordPalindrome" - "\" waaw \"" - (longestWordPalindrome (BC.pack "w waaw wo waw"))- )+import Test.HUnit (Counts, Test (..), runTestTT)+import Test.QuickCheck (quickCheck) -testWordPalindrome7 =- TestCase (assertEqual- "wordPalindrome" - "\" waaw \"" - (longestWordPalindrome (BC.pack "vwaawvxy v waaw v"))- )+import Data.Algorithms.Palindromes.Finders (Algorithm (..))+import ITApproximate (testListITApproximate)+import ITLinear (testListITLinear)+import ITQuadratic (testListITQuadratic)+import QuickCheckProperties (propertyList)+import UTApproximateAlgorithm (testListApproximateAlgorithm)+import UTDNAPals (testListDNA)+import UTExtendPals (testListExtend)+import UTFinders (testListFinders)+import UTGetLeftRight (testListGetLeftRight)+import UTLinearAlgorithm (testListLinearAlgorithm)+import UTPalEq (testListPalEq)+import UTProcessing (testListProcessing)+import UTPunctuationPals (testListPunctuation)+import UTQuadraticAlgorithm (testListQuadraticAlgorithm)+import UTTextPals (testListText)+import UTWordPals (testListWordPalindromes) tests :: Test-tests = TestList [TestLabel "testTextPalindrome1" testTextPalindrome1- ,TestLabel "testTextPalindrome2" testTextPalindrome2- ,TestLabel "testTextPalindrome3" testTextPalindrome3- ,TestLabel "testTextPalindrome4" testTextPalindrome4- ,TestLabel "testTextPalindrome5" testTextPalindrome5- ,TestLabel "testTextPalindrome6" testTextPalindrome6- ,TestLabel "testTextPalindrome7" testTextPalindrome7- ,TestLabel "testTextPalindrome8" testTextPalindrome8- ,TestLabel "testTextPalindrome9" testTextPalindrome9- ,TestLabel "testTextPalindrome10" testTextPalindrome10- ,TestLabel "testTextPalindrome11" testTextPalindrome11- ,TestLabel "testWordPalindrome1" testWordPalindrome1- ,TestLabel "testWordPalindrome2" testWordPalindrome2- ,TestLabel "testWordPalindrome3" testWordPalindrome3- ,TestLabel "testWordPalindrome4" testWordPalindrome4- ,TestLabel "testWordPalindrome5" testWordPalindrome5- ,TestLabel "testWordPalindrome6" testWordPalindrome6- ,TestLabel "testWordPalindrome7" testWordPalindrome7- ]+tests =+ TestList $+ testListLinearAlgorithm+ ++ testListITApproximate+ ++ testListQuadraticAlgorithm+ ++ testListApproximateAlgorithm+ ++ testListText AlgLinear+ ++ testListText AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ ++ testListText AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ ++ testListPunctuation+ ++ testListGetLeftRight+ ++ testListDNA AlgLinear+ ++ testListDNA AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ ++ testListText AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ ++ testListExtend AlgLinear+ ++ testListExtend AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ ++ testListText AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ ++ testListProcessing+ ++ testListPalEq+ ++ testListWordPalindromes AlgLinear+ ++ testListWordPalindromes AlgQuadratic{algGapSize = 0, algMaxErrors = 0}+ ++ testListText AlgApproximate{algGapSize = 0, algMaxErrors = 0}+ ++ testListFinders+ ++ testListITLinear+ ++ testListITQuadratic -main :: IO Counts-main = do - quickCheck propPalindromesAroundCentres- quickCheck propTextPalindrome- runTestTT tests+runQuickCheck :: IO ()+runQuickCheck = mapM_ quickCheck propertyList +main :: IO Counts+main = do+ runQuickCheck+ runTestTT tests {- 2nd property falsified by@@ -244,6 +68,9 @@ "\213\SI6+\ESCU:1\165\254\228\SUB9\200\231\USM,3\227\&3\176\214X\203\SOH\130UI9\154\239<w\231kPbmvY|!sc\133\b$#v\203LM\235H" +\*** Failed! Falsified (after 82 tests):+"# 7z;K\EM\996701\f\EOT\1088669\RSy\30490\EM\149585h\ENQ\r\1093014a\r6\181326\SI\DC2\b\n\61832\\\DC2+\11953\61349\\\STX>a\133690\145589W\996131\136065}-6cJI[\CAN\DC1\997287T\92545"+ -} {-@@ -256,12 +83,12 @@ import qualified Data.ByteString as B main :: IO ()-main = +main = do fnenhl <- openFile "examples/palindromes/Damnitimmad.txt" ReadMode-- "../../TestSources/Bibles/engelskingjames.txt" ReadMode- hSetEncoding fnenhl latin1 + hSetEncoding fnenhl latin1 inputenB <- B.hGetContents fnenhl -- fnnlhl <- openFile "../../TestSources/Bibles/nederlands.txt" ReadMode--- hSetEncoding fnnlhl latin1 +-- hSetEncoding fnnlhl latin1 -- inputnlB <- B.hGetContents fnnlhl defaultMain [@@ -269,7 +96,7 @@ -- bench "longestPalindrome Dutch" (nf longestPalindrome inputnlB)--, -- bench "longestPalindromeConstantArguments English" (nf CA.longestPalindrome inputenB)--, bench "longestPalindrome English" (nf longestPalindrome inputenB)--,--,- ] + ] -} {-@@ -281,4 +108,3 @@ ] -}-
+ tests/PalindromeMethods.hs view
@@ -0,0 +1,64 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}+module PalindromeMethods+ ( longestTextPalindrome+ , longestWordPalindrome+ , longestPunctuationPalindrome+ , longestDNAPalindrome+ , extendTextPalindrome+ ) where++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ , findPalindromesFormatted+ )+import Data.Algorithms.Palindromes.PalEq+ ( PalEq+ )++{- takes a flag to edit the algorithm+to enable the usage of both algorithm types on the same unit tests -}+longestTextPalindrome :: Algorithm -> String -> String+longestTextPalindrome algorithm =+ findPalindromesFormatted VarText FormatText SelectLongest algorithm 0++longestWordPalindrome :: Algorithm -> String -> String+longestWordPalindrome t =+ findPalindromesFormatted+ VarWord+ FormatText+ SelectLongest+ t+ 0++longestPunctuationPalindrome :: String -> String+longestPunctuationPalindrome =+ findPalindromesFormatted+ VarPunctuation+ FormatText+ SelectLongest+ AlgLinear+ 0++longestDNAPalindrome :: Algorithm -> String -> String+longestDNAPalindrome algorithm =+ findPalindromesFormatted+ VarDNA+ FormatText+ SelectLongest+ algorithm+ 0++extendTextPalindrome :: Algorithm -> Int -> String -> String+extendTextPalindrome algorithm n =+ findPalindromesFormatted+ VarText+ FormatText+ (SelectAt n)+ algorithm+ 0
+ tests/QuickCheckGenerators.hs view
@@ -0,0 +1,177 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module QuickCheckGenerators+ ( generatePalindromes+ ) where++import Data.List (intercalate)+import Data.Vector (Vector (..), fromList, toList, (//))+import Test.QuickCheck+ ( Arbitrary (..)+ , Gen+ , Property+ , arbitrary+ , choose+ , chooseInt+ , forAll+ , generate+ , listOf+ , oneof+ , suchThat+ , vectorOf+ )+import Test.QuickCheck.Gen (elements, genFloat)++import Data.Algorithms.Palindromes.DNA (DNA (..), dnaToChar)+import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFormat (..)+ , Variant (VarDNA, VarPlain, VarText, VarWord)+ )+import Data.Algorithms.Palindromes.PalEq (PalEq (..))+import Data.Algorithms.Palindromes.Settings (Settings (..))++maxPalInPalGeneration, minWordLength, maxWordLength :: Int+-- the maximum amount of palInPal depth the generated palindrome will have+-- a Depth of 1 gives a palindrome with one level of palindrome (pallap)+-- a Depth of 2 gives a palindrome with two levels of palindromes (pallappallap) etc+maxPalInPalGeneration = 2+-- The minimum and maximum length of the generated words+minWordLength = 1+maxWordLength = 7++-- | Constructs a Gen String for palindromes, based on the algorithm settings being used+generatePalindromes :: Settings -> Gen String+generatePalindromes settings = case variant settings of+ VarPlain -> generatePalindromeString id plainCharGenerator settings+ VarDNA -> map dnaToChar <$> generatePalindromeString compDNA dnaCharGenerator settings+ VarWord -> wordToString $ generatePalindromeString id wordGenerator settings+ _ -> generatePalindromeString id puncCharGenerator settings++-- | Converts the DNA datatype to it's complement+compDNA :: DNA -> DNA+compDNA A = T+compDNA T = A+compDNA C = G+compDNA G = C+compDNA N = N++-- | Converts a Gen [String] to a Gen String by concatenating the strings in the list with a space+wordToString :: Gen [[Char]] -> Gen String+wordToString gen = do unwords <$> gen++-- | Generates random strings for punctuation palindromes, these can be anything+puncCharGenerator :: Gen Char+puncCharGenerator = choose (' ', '~') `suchThat` (`notElem` ['\\', '"', ' ', '\n'])++-- | Generates random strings for plain palindromes+alphabetPlain = ['a' .. 'z'] ++ ['A' .. 'Z']++plainCharGenerator :: Gen Char+plainCharGenerator = elements alphabetPlain++-- makes DNA an instance of Arbitrary, so random DNA strings can be generated+instance Arbitrary DNA where+ arbitrary = elements [A, T, C, G]++-- | Simple Gen [DNA]+dnaCharGenerator :: Gen DNA+dnaCharGenerator = arbitrary :: Gen DNA++-- | Randomly generates one word with length between 2 and 7+wordGenerator :: Gen [Char]+wordGenerator = do+ randomWordLength <- chooseInt (minWordLength, maxWordLength)+ vectorOf randomWordLength $+ choose (' ', '~') `suchThat` (`notElem` ['\\', '"', ' ', '\n'])++{- | Generates either a string, palindrome or palInPal palindrome with random characters+around them. The function passes a function palComp all the way down to palInPal. This is+a bit weird, but defining a complement function in the PalEq datatype means that the (=:=)+function must be injective, which is an unnecessary restriction otherwise.+-}+generatePalindromeString+ :: (Arbitrary a, PalEq a) => (a -> a) -> Gen a -> Settings -> Gen [a]+generatePalindromeString palComp charGenerator settings = do+ -- get the gapSize and maxErrors settings from the algorithm settings+ let (gapSize, maxErrors) = case algorithm settings of+ AlgQuadratic{algGapSize = gapSize, algMaxErrors = maxErrors} -> (gapSize, maxErrors)+ _ -> (0, 0)++ -- generate random string to add noise in front of the palindrome+ randomStart <- listOf charGenerator+ -- generate the palindrome+ palGenerator <-+ oneof+ [ listOf charGenerator+ , addErrors maxErrors charGenerator $ generatePalindrome palComp charGenerator gapSize+ , addErrors maxErrors charGenerator $ multiPalInPal palComp charGenerator gapSize+ ]+ -- generate random string to add noise behind the palindrome+ randomEnd <- listOf charGenerator+ return $ randomStart ++ palGenerator ++ randomEnd++-- | Generates a palindrome+generatePalindrome :: (Arbitrary a, PalEq a) => (a -> a) -> Gen a -> Int -> Gen [a]+generatePalindrome palComp charGenerator gapSize = do+ randomString <- listOf charGenerator+ palInPal palComp charGenerator gapSize 1 randomString++-- | generates a palindrome with a random amount of palInPal depth, note that a non palindrome can be generated if the random number is 0+multiPalInPal :: (Arbitrary a, PalEq a) => (a -> a) -> Gen a -> Int -> Gen [a]+multiPalInPal palComp charGenerator gapSize = do+ randomString <- listOf charGenerator+ palInPalDepth <- choose (0, maxPalInPalGeneration) -- generate a random int between 0 and maxDepth+ palInPal palComp charGenerator gapSize palInPalDepth randomString++{- | Generate a palindrome from string with Int amount of palindromes -+a depth of 0 gives the input back, (pal) -+a depth of 1 gives a palindrome with one level of palindrome (pallap) -+a depth of 2 gives a palindrome with two levels of palindrome (pallappallap)+-}+palInPal :: (Arbitrary a, PalEq a) => (a -> a) -> Gen a -> Int -> Int -> [a] -> Gen [a]+palInPal palComp charGenerator gapSize depth string = do+ case depth of+ 0 -> return string+ 1 -> do+ unevenOrGap <- generateGap charGenerator gapSize -- allows for uneven palindromes and gaps+ return $ string ++ unevenOrGap ++ reversePal palComp string+ _ -> do+ uneven <- generateGap charGenerator 1 -- allows for uneven palInPals+ palInPal palComp charGenerator gapSize (depth - 1) $+ string ++ uneven ++ reversePal palComp string++reversePal :: (PalEq a) => (a -> a) -> [a] -> [a]+reversePal palComp = reverse . map palComp++{- | generates a string with a max length of 'maxGapSize' -+the string will be used to make gapped palindromes or uneven palindrome -+even pals are reprented by this string being empty+-}+generateGap :: (Arbitrary a) => Gen a -> Int -> Gen [a]+generateGap charGenerator maxGapSize = do+ let maxGapSize' = fromIntegral $ max maxGapSize 1 -- the maxGapSize' is always set to at least 1 to account for uneven palindromes+ randomGapSize <- choose (0, maxGapSize')+ vectorOf randomGapSize charGenerator -- generates a string of length 'randomGapSize'++-- | Generate x amount of errors in a string+addErrors :: Int -> Gen a -> Gen [a] -> Gen [a]+addErrors maxErrors charGenerator palGenerator = case maxErrors of+ 0 -> palGenerator+ _ -> do+ randomErrorCount <- choose (0, maxErrors)+ _palGenerator <- palGenerator+ -- generate x indices on which the errors will be applied+ errorIndices <- vectorOf randomErrorCount $ choose (0, max 0 $ -1 + length _palGenerator)+ -- generate x random characters to replace the characters at the error indices+ replacementChars <- vectorOf randomErrorCount charGenerator+ let -- replace the characters at the error indices with the replacement characters+ -- we do this by converting into and from a vector+ errorZip = zip errorIndices replacementChars+ replaceErrors = toList $ replaceErrors' errorZip $ fromList _palGenerator+ replaceErrors' :: [(Int, a)] -> Vector a -> Vector a+ replaceErrors' zip _palGenerator = _palGenerator // zip+ if null _palGenerator || randomErrorCount == 0 then palGenerator else return replaceErrors
+ tests/QuickCheckProperties.hs view
@@ -0,0 +1,287 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module QuickCheckProperties (propertyList) where++import Data.Char (isAlphaNum, isSpace, readLitChar, toLower)+import Data.Foldable.Levenshtein (levenshtein', levenshteinDistance')+import Data.Maybe (fromJust)+import Test.QuickCheck+ ( Arbitrary+ , Gen+ , Property+ , arbitrary+ , choose+ , counterexample+ , elements+ , forAll+ , ioProperty+ , label+ , listOf+ , suchThat+ )++import Data.Algorithms.Palindromes.DNA (DNA (A, C, G, T), charToDNA, dnaToChar)+import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , Variant (VarDNA, VarPlain, VarPunctuation, VarText, VarWord)+ , findPalindromeRanges+ , findPalindromes+ )+import Data.Algorithms.Palindromes.PalEq (PalEq (..))+import Data.Algorithms.Palindromes.Palindrome (Palindrome (..), getLength)+import Data.Algorithms.Palindromes.RangeFunctions (Range, rangeToLength)+import Data.Algorithms.Palindromes.Settings+ ( Settings (..)+ )+import Data.Algorithms.Palindromes.Streaming (findPalindromesVisualised)+import QuickCheckGenerators (generatePalindromes)+import QuickCheckSettings (settingsList)++-- List of to-be-tested properties, where each property is connected to all the settings+propertyList :: [Property]+propertyList =+ -- Property 1+ map propValidPalindromeRangeAndText settingsList+ -- Property 2+ ++ map propValidPalindromeReverse settingsList+ -- Property 3+ ++ map propValidPalLength settingsList+ -- Property 4+ ++ map propValidBoundaries settingsList+ -- Property 5+ ++ map propValidPalRange settingsList+ -- Property 6+ ++ map propAllowedPalLength settingsList+ -- Property 7+ ++ map propStreamSameResult settingsList++-- | Makes a Gen String based on the variant that is being used+stringGenerator :: Settings -> Gen String+stringGenerator = generatePalindromes++-- | Filters the non-alphabetic characters from the input, before converting everything to lowercase+cleanOriginalString :: String -> String+cleanOriginalString string = map toLower (filter (\a -> isAlphaNum a || isSpace a) string)++-- Property 1 ---------------------------------------------------------++-- | Test if all the generated Palindrome objects have a valid text related to the range property.+propValidPalindromeRangeAndText :: Settings -> Property+propValidPalindromeRangeAndText settings = counterexample (show settings ++ " property 1") $ forAll (stringGenerator settings) $ \originalString ->+ all+ (`checkPalRangeAndText` originalString)+ ( findPalindromes+ (variant settings)+ (algorithm settings)+ (minLength settings)+ originalString+ )++{- | Check that taking the substring of the original text described by the start and end of the palRange+property is equal to the palText property+-}+checkPalRangeAndText :: Palindrome -> String -> Bool+checkPalRangeAndText (Palindrome _ "" (x, y)) _ = x == y+checkPalRangeAndText (Palindrome _ palText (start, end)) originalString = palText == substringFromRange+ where+ substringFromRange = take (end - start) (drop start originalString)++-- Property 2 ---------------------------------------------------------++-- | Check that a found character palindrome is actually a palindrome+propValidPalindromeReverse :: Settings -> Property+propValidPalindromeReverse settings = counterexample (show settings ++ " property 2") $ forAll (stringGenerator settings) $ \originalString ->+ all+ (extractPalEq settings)+ ( findPalindromes+ (variant settings)+ (algorithm settings)+ (minLength settings)+ originalString+ )++extractPalEq :: Settings -> Palindrome -> Bool+extractPalEq settings pal = case algorithm settings of+ AlgApproximate _ _ -> case variant settings of+ VarWord -> isApproximatePalindrome $ words (cleanOriginalString (palText pal))+ VarPlain -> isApproximatePalindrome $ palText pal+ VarDNA -> isApproximatePalindrome $ map (fromJust . charToDNA) (palText pal)+ _ -> isApproximatePalindrome $ cleanOriginalString (palText pal)+ _ -> case variant settings of+ VarWord -> isPalindrome $ words (cleanOriginalString (palText pal))+ VarPlain -> isPalindrome $ palText pal+ VarDNA -> isPalindrome $ map (fromJust . charToDNA) (palText pal)+ _ -> isPalindrome $ cleanOriginalString (palText pal)+ where+ (gapSize, maxErrors) = case algorithm settings of+ AlgQuadratic gap err -> (gap, err)+ AlgApproximate gap err -> (gap, err)+ AlgLinear -> (0, 0)++ {- if any of the possible removed gaps has levenshteinDistance with its reverse is+ less than 2 * maxErrors we have an a valid approximate palindromes. This is because+ 2 * maxErrors is equivalent to the levenshteinDistance -}+ isApproximatePalindrome :: (PalEq a) => [a] -> Bool+ isApproximatePalindrome input =+ any+ (<= 2 * maxErrors)+ ( zipWith+ (levenshteinDistance' (=:=))+ (allPossibleGapless gapSize maxErrors input)+ (map reverse (allPossibleGapless gapSize maxErrors input))+ )+ isPalindrome :: (PalEq a) => [a] -> Bool+ isPalindrome input = checkMismatches maxErrors $ removeGap 0 gapSize input++-- | for approximate palindromes the gap can be shifted due to insertions, so we need all.+allPossibleGapless :: (PalEq a) => Int -> Int -> [a] -> [[a]]+allPossibleGapless 0 _ palindrome = [palindrome]+allPossibleGapless gapSize 0 palindrome = [removeGap 0 gapSize palindrome]+allPossibleGapless gapSize maxErrors palindrome =+ map (\e -> removeGap e gapSize palindrome) [-maxErrors .. maxErrors]++-- | Checks if the character string is a palindrome, taking gapSize and maxErrors into account+checkMismatches :: (PalEq a) => Int -> [a] -> Bool+checkMismatches maxErrors pal' = mismatches <= maxErrors+ where+ mismatches =+ length+ [ ()+ | i <- [0 .. (length pal' `div` 2) - 1]+ , not $ (pal' !! i) =:= (pal' !! (length pal' - 1 - i))+ ]++-- | Removes gap from palindrome+removeGap :: Int -> Int -> [a] -> [a]+removeGap offset gapSize palindrome = take start palindrome ++ drop end palindrome+ where+ start = (length palindrome - adjustedGap + offset) `div` 2+ end = start + adjustedGap+ adjustGap = if even offset then not adjustWhenOddOffset else adjustWhenOddOffset+ adjustWhenOddOffset = even (length palindrome) == even gapSize || gapSize == 0+ adjustedGap =+ if adjustGap+ then gapSize - 1+ else gapSize++-- Property 3 ---------------------------------------------------------++-- | Tests if the palLength of a character palindrome corresponds to the palText+propValidPalLength :: Settings -> Property+propValidPalLength settings = counterexample (show settings ++ " property 3") $ forAll (stringGenerator settings) $ \originalString ->+ all+ (validPalLength settings)+ ( findPalindromes+ (variant settings)+ (algorithm settings)+ (minLength settings)+ originalString+ )++-- | Checks for every palindrome variant if the palLength corresponds to the length of palText+validPalLength :: Settings -> Palindrome -> Bool+validPalLength settings pal = case variant settings of+ VarWord ->+ length (words (cleanOriginalString (palText pal))) == getLength pal+ VarPlain -> length (palText pal) == getLength pal+ VarDNA -> length (palText pal) == getLength pal+ _ -> length (cleanOriginalString $ palText pal) == getLength pal++-- Property 4 ---------------------------------------------------------++-- | Property for testing if the palindrome range of a character palindrome corresponds to the palindrome length+propValidBoundaries :: Settings -> Property+propValidBoundaries settings = counterexample (show settings ++ " property 4") $ forAll (stringGenerator settings) $ \originalString ->+ all+ (checkValidBoundaries settings originalString)+ ( findPalindromes+ (variant settings)+ (algorithm settings)+ (minLength settings)+ originalString+ )++-- | Tests if the palindrome range of a palindrome corresponds to the palindrome length+checkValidBoundaries :: Settings -> String -> Palindrome -> Bool+checkValidBoundaries settings inputString pal = case variant settings of+ VarWord -> countWordsInRange (palRangeInText pal) inputString == getLength pal+ VarText ->+ let (s, e) = palRangeInText pal+ in e - s - amountOfNonAlpha 0 (palText pal) == getLength pal+ VarPunctuation ->+ let (s, e) = palRangeInText pal+ in e - s - amountOfNonAlpha 0 (palText pal) == getLength pal+ _ -> let (s, e) = palRangeInText pal in e - s == getLength pal++-- | Counts the amount of words that are in the substring of the input string corresponding with the given range+countWordsInRange :: Range -> String -> Int+countWordsInRange (s, e) inputString = length . words $ cleanOriginalString $ take (e - s) (drop s inputString)++-- | Counts the amount of non-alphabetic characters in the string+amountOfNonAlpha :: Int -> String -> Int+amountOfNonAlpha acc [] = acc+amountOfNonAlpha acc (x : xs)+ | not (isAlphaNum x) = amountOfNonAlpha (acc + 1) xs+ | otherwise = amountOfNonAlpha acc xs++-- Property 5 ---------------------------------------------------------++-- | Tests if the range boundaries of a character palindrome are not outside the bounds of the string+propValidPalRange :: Settings -> Property+propValidPalRange settings = counterexample (show settings ++ " property 5") $ forAll (stringGenerator settings) $ \originalString ->+ all+ (\pal -> fst (palRangeInText pal) >= 0 && snd (palRangeInText pal) <= length originalString)+ ( findPalindromes+ (variant settings)+ (algorithm settings)+ (minLength settings)+ originalString+ )++-- Property 6 ---------------------------------------------------------++-- | Property for testing if the length of a character palindrome is allowed by the specified minimum length+propAllowedPalLength :: Settings -> Property+propAllowedPalLength settings = counterexample (show settings ++ " property 6") $ forAll (stringGenerator settings) $ \originalString ->+ all+ (isAllowedPalLength settings)+ ( findPalindromes+ (variant settings)+ (algorithm settings)+ (minLength settings)+ originalString+ )++-- | Checks if the length of a palindrome is greater than the minimum length+isAllowedPalLength :: Settings -> Palindrome -> Bool+isAllowedPalLength settings pal = case minLength settings of+ l ->+ getLength pal >= l+ || palText pal == ""++-- Property 7 ---------------------------------------------------------++{- | Check that finding palindromes with intermediate visualisation+returns the same as the normal findPalindromes+-}+propStreamSameResult :: Settings -> Property+propStreamSameResult settings = counterexample (show settings ++ " property 7") $ forAll (stringGenerator settings) $ \originalString ->+ ioProperty $ do+ let pure =+ findPalindromes+ (variant settings)+ (algorithm settings)+ (minLength settings)+ originalString+ streamed <-+ findPalindromesVisualised+ (variant settings)+ (algorithm settings)+ (minLength settings)+ False+ originalString+ (const $ return ()) -- Don't do anything in the visualisation step+ return (pure == streamed)
+ tests/QuickCheckSettings.hs view
@@ -0,0 +1,363 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module QuickCheckSettings+ ( settingsList+ ) where++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (..)+ , OutputFilter (..)+ , OutputFormat (..)+ , Variant (..)+ )+import Data.Algorithms.Palindromes.Settings (Settings (..))++-- | Settings where the palindrome type works with Char+settingsList :: [Settings]+settingsList =+ [ setting1+ , setting2+ , setting3+ , setting4+ , setting5+ , setting6+ , setting7+ , setting8+ , setting9+ , setting10+ , setting11+ , setting12+ , setting13+ , setting14+ , setting15+ , setting16+ , setting17+ , setting18+ , setting19+ , setting20+ , setting21+ , setting22+ , setting23+ , setting24+ , setting25+ , setting26+ , setting27+ , setting28+ , setting29+ , setting30+ , setting31+ , setting32+ , setting33+ , setting34+ , setting35+ , setting36+ , setting37+ , setting38+ ]++setting1 :: Settings+setting1 =+ Settings+ AlgLinear+ VarWord+ FormatLength+ SelectLongest+ 10+setting2 :: Settings+setting2 =+ Settings+ (AlgQuadratic 10 5)+ VarPunctuation+ FormatLength+ SelectLongest+ 3+setting3 :: Settings+setting3 =+ Settings+ (AlgQuadratic 3 1)+ VarPlain+ FormatLength+ SelectLongest+ 0+setting4 :: Settings+setting4 =+ Settings+ (AlgQuadratic 3 5)+ VarText+ FormatLength+ SelectLongest+ 10+setting5 :: Settings+setting5 =+ Settings+ (AlgQuadratic 10 0)+ VarPlain+ FormatLength+ SelectLongest+ 0+setting6 :: Settings+setting6 =+ Settings+ (AlgQuadratic 0 1)+ VarWord+ FormatLength+ SelectLongest+ 3+setting7 :: Settings+setting7 =+ Settings+ (AlgQuadratic 10 5)+ VarWord+ FormatLength+ SelectLongest+ 0+setting8 :: Settings+setting8 =+ Settings+ (AlgQuadratic 10 0)+ VarText+ FormatLength+ SelectLongest+ 3+setting9 :: Settings+setting9 =+ Settings+ (AlgQuadratic 3 0)+ VarWord+ FormatLength+ SelectLongest+ 3+setting10 :: Settings+setting10 =+ Settings+ (AlgQuadratic 0 1)+ VarPunctuation+ FormatLength+ SelectLongest+ 0+setting11 :: Settings+setting11 =+ Settings+ (AlgQuadratic 0 5)+ VarPlain+ FormatLength+ SelectLongest+ 3+setting12 :: Settings+setting12 =+ Settings+ (AlgQuadratic 10 1)+ VarDNA+ FormatLength+ SelectLongest+ 10+setting13 :: Settings+setting13 =+ Settings+ (AlgQuadratic 3 0)+ VarDNA+ FormatLength+ SelectLongest+ 3+setting14 :: Settings+setting14 =+ Settings+ (AlgQuadratic 0 5)+ VarDNA+ FormatLength+ SelectLongest+ 0+setting15 :: Settings+setting15 =+ Settings+ AlgLinear+ VarPunctuation+ FormatLength+ SelectLongest+ 3+setting16 :: Settings+setting16 =+ Settings+ AlgLinear+ VarDNA+ FormatLength+ SelectLongest+ 0+setting17 :: Settings+setting17 =+ Settings+ (AlgQuadratic 3 1)+ VarPunctuation+ FormatLength+ SelectLongest+ 10+setting18 :: Settings+setting18 =+ Settings+ (AlgQuadratic 0 1)+ VarText+ FormatLength+ SelectLongest+ 0+setting19 :: Settings+setting19 =+ Settings+ AlgLinear+ VarPlain+ FormatLength+ SelectLongest+ 10+setting20 :: Settings+setting20 =+ Settings+ (AlgQuadratic 0 5)+ VarPlain+ FormatLength+ SelectLongest+ 3+setting21 :: Settings+setting21 =+ Settings+ AlgLinear+ VarText+ FormatLength+ SelectLongest+ 10+setting22 =+ Settings+ (AlgApproximate 10 5)+ VarPunctuation+ FormatLength+ SelectLongest+ 3+setting23 :: Settings+setting23 =+ Settings+ (AlgApproximate 3 1)+ VarPlain+ FormatLength+ SelectLongest+ 0+setting24 :: Settings+setting24 =+ Settings+ (AlgApproximate 3 5)+ VarText+ FormatLength+ SelectLongest+ 10+setting25 :: Settings+setting25 =+ Settings+ (AlgApproximate 10 0)+ VarPlain+ FormatLength+ SelectLongest+ 0+setting26 :: Settings+setting26 =+ Settings+ (AlgApproximate 0 1)+ VarWord+ FormatLength+ SelectLongest+ 3+setting27 :: Settings+setting27 =+ Settings+ (AlgApproximate 10 5)+ VarWord+ FormatLength+ SelectLongest+ 0+setting28 :: Settings+setting28 =+ Settings+ (AlgApproximate 10 0)+ VarText+ FormatLength+ SelectLongest+ 3+setting29 :: Settings+setting29 =+ Settings+ (AlgApproximate 3 0)+ VarWord+ FormatLength+ SelectLongest+ 3+setting30 :: Settings+setting30 =+ Settings+ (AlgApproximate 0 1)+ VarPunctuation+ FormatLength+ SelectLongest+ 0+setting31 :: Settings+setting31 =+ Settings+ (AlgApproximate 0 5)+ VarPlain+ FormatLength+ SelectLongest+ 3+setting32 :: Settings+setting32 =+ Settings+ (AlgApproximate 10 1)+ VarDNA+ FormatLength+ SelectLongest+ 10+setting33 :: Settings+setting33 =+ Settings+ (AlgApproximate 3 0)+ VarDNA+ FormatLength+ SelectLongest+ 3+setting34 :: Settings+setting34 =+ Settings+ (AlgApproximate 0 5)+ VarDNA+ FormatLength+ SelectLongest+ 0+setting35 :: Settings+setting35 =+ Settings+ (AlgApproximate 3 1)+ VarPunctuation+ FormatLength+ SelectLongest+ 10+setting36 :: Settings+setting36 =+ Settings+ (AlgApproximate 0 1)+ VarText+ FormatLength+ SelectLongest+ 0+setting37 :: Settings+setting37 =+ Settings+ (AlgApproximate 0 5)+ VarPlain+ FormatLength+ SelectLongest+ 3+setting38 :: Settings+setting38 =+ Settings+ (AlgApproximate 2 3)+ VarDNA+ FormatLength+ SelectLongest+ 0
+ tests/UTApproximateAlgorithm.hs view
@@ -0,0 +1,595 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTApproximateAlgorithm (testListApproximateAlgorithm) where++import Data.List (sort)+import Test.HUnit (Test (..), assertEqual)++import Data.Algorithms.Palindromes.ApproximateAlgorithm+ ( Cell (..)+ , approximateAlgorithm+ , sparsify+ )+import Data.Algorithms.Palindromes.DNA (DNA (..))++import qualified Data.Vector.Unboxed as U++testListApproximateAlgorithm =+ [ testSparsifySimple+ , testSparsifyNegativeSingleton+ , testSparsifyComplex+ , testSparsifyLeadingNegative+ , testSparsifyOnSparsifiedRow+ , testSparsifyOnPartiallySparsifiedRow+ , testTeesZeroErrors+ , testTeesOneError+ , testMississippiZeroErrors+ , testMississippiOneError+ , testMississippiTwoErrors+ , testMississippiThreeErrors+ , testMississippiFourErrors+ , testTextEvenGapSizeZeroErrors+ , testTextEvenGapSizeOneError+ , testTextEvenGapSizeTwoErrors+ , testTextEvenGapSizeTwoErrorsBiggerInput+ , testTextEvenGapSizeThreeErrorsBiggerInput+ , testTextOddGapSizeZeroErrors+ , testTextOddGapSizeOneError+ , testTextOddGapSizeTwoErrors+ , testSmallDNAZeroErrors+ , testSmallDNAOneError+ , testDNAAsZeroErrors+ , testDNAAsOneError+ , testBigDNAZeroErrors+ , testBigDNAOneError+ , testBigDNATwoErrors+ , testBigDNAThreeErrors+ , testBigDNAFourErrors+ , testBigDNAFiveErrors+ , testDNAGapSizeOneZeroErrors+ , testDNAGapSizeOneOneError+ , testDNAGapSizeOneTwoErrors+ , testDNAGapSizeOneThreeErrors+ , testDNAGapSizeTwoZeroErrors+ , testDNAGapSizeTwoOneError+ , testDNAGapSizeTwoTwoErrors+ , testDNAGapSizeThreeZeroErrors+ , testDNAGapSizeThreeOneError+ , testDNAGapSizeThreeFourErrors+ ]++{- | Test sparsify using a simple example with a single sequence of cells with negative+budgets.+-}+testSparsifySimple :: Test+testSparsifySimple =+ TestCase $+ assertEqual+ "testSparsifySimple"+ [ Cell 0 1+ , Cell 1 0+ , Cell 2 (-1)+ , Cell 5 (-1)+ , Cell 6 0+ , -- sparsify always adds one cell with (-1) budget to the end of the row.+ Cell 7 (-1)+ ]+ ( sparsify+ [ Cell 0 1+ , Cell 1 0+ , Cell 2 (-1)+ , Cell 3 (-1)+ , Cell 4 (-1)+ , Cell 5 (-1)+ , Cell 6 0+ ]+ )++-- | Test sparsify with a sequence of cells with negative budgets of length 1.+testSparsifyNegativeSingleton :: Test+testSparsifyNegativeSingleton =+ TestCase $+ assertEqual+ "testSparsifyNegativeSingleton"+ [Cell 0 1, Cell 1 0, Cell 2 (-1), Cell 3 0, Cell 4 (-1)]+ (sparsify [Cell 0 1, Cell 1 0, Cell 2 (-1), Cell 3 0, Cell 4 (-1)])++-- | Test sparsify with a larger input and different sequences of cells with negative budgets.+testSparsifyComplex :: Test+testSparsifyComplex =+ TestCase $+ assertEqual+ "testSparsifyComplex"+ [ Cell 0 1+ , Cell 1 0+ , Cell 2 (-1)+ , Cell 5 (-1)+ , Cell 6 0+ , Cell 7 1+ , Cell 8 0+ , Cell 9 (-1)+ , Cell 10 0+ , Cell 11 0+ , Cell 12 0+ , Cell 13 (-1)+ ]+ ( sparsify+ [ Cell 0 1+ , Cell 1 0+ , Cell 2 (-1)+ , Cell 3 (-1)+ , Cell 4 (-1)+ , Cell 5 (-1)+ , Cell 6 0+ , Cell 7 1+ , Cell 8 0+ , Cell 9 (-1)+ , Cell 10 0+ , Cell 11 0+ , Cell 12 0+ , Cell 13 (-1)+ , Cell 14 (-2)+ , Cell 15 (-3)+ , Cell 16 (-4)+ ]+ )++-- | Test whether sparsify deletes the first cell if it is negative.+testSparsifyLeadingNegative :: Test+testSparsifyLeadingNegative =+ TestCase $+ assertEqual+ "testSparsifyLeadingNegative"+ [ Cell 1 0+ , Cell 2 0+ , Cell 3 (-1)+ ]+ ( sparsify+ [ Cell 0 (-1)+ , Cell 1 0+ , Cell 2 0+ , Cell 3 (-1)+ ]+ )++-- | Test whether sparsify does not change an already fully sparsified row.+testSparsifyOnSparsifiedRow :: Test+testSparsifyOnSparsifiedRow =+ TestCase $+ assertEqual+ "testSparsifyOnSparsifiedRow"+ [ Cell 0 0+ , Cell 1 (-1)+ , Cell 10 (-1)+ , Cell 11 0+ , Cell 12 (-1)+ ]+ ( sparsify+ [ Cell 0 0+ , Cell 1 (-1)+ , Cell 10 (-1)+ , Cell 11 0+ , Cell 12 (-1)+ ]+ )++-- | Test sparsify on a row which has previously already been partially sparsified.+testSparsifyOnPartiallySparsifiedRow :: Test+testSparsifyOnPartiallySparsifiedRow =+ TestCase $+ assertEqual+ "testSparsifyOnPartiallySparsifiedRow"+ [ Cell 0 0+ , Cell 1 (-1)+ , Cell 5 (-1)+ , Cell 6 0+ , Cell 7 (-1)+ , Cell 9 (-1)+ , Cell 10 0+ , Cell 11 (-1)+ ]+ ( sparsify+ [ Cell 0 0+ , Cell 1 (-1)+ , Cell 5 (-1)+ , Cell 6 0+ , Cell 7 (-1)+ , Cell 8 (-1)+ , Cell 9 (-1)+ , Cell 10 0+ , Cell 11 (-1)+ ]+ )++{- | This tests the input string "tees" with zero errors. Output order does not matter, so+it is sorted to check for equality. Output represents the strings "t", "ee" and "s".+-}+testTeesZeroErrors :: Test+testTeesZeroErrors =+ TestCase $+ assertEqual+ "testTeesZeroErrors"+ [(0, 1), (1, 3), (3, 4)]+ (sort $ approximateAlgorithm 0 0 (U.fromList "tees"))++{- | This tests the input string "tees" with one error. The entire string is then one+maximal approximate palindrome.+-}+testTeesOneError :: Test+testTeesOneError =+ TestCase $+ assertEqual+ "testTeesOneError"+ [(0, 4)]+ (sort $ approximateAlgorithm 0 1 (U.fromList "tees"))++-- | Test the string "mississippi" with zero errors.+testMississippiZeroErrors :: Test+testMississippiZeroErrors =+ TestCase $+ assertEqual+ "testMississippiZeroErrors"+ [ (0, 1) -- "m"+ , (1, 2) -- "i"+ , (1, 5) -- "issi"+ , (1, 8) -- "ississi"+ , (4, 8) -- "issi"+ , (7, 8) -- "i"+ , (7, 11) -- "ippi"+ , (10, 11) -- "i"+ ]+ (sort $ approximateAlgorithm 0 0 (U.fromList "mississippi"))++-- | Test the string "mississippi" with one error.+testMississippiOneError :: Test+testMississippiOneError =+ TestCase $+ assertEqual+ "testMississippiOneError"+ [ (0, 3) -- "mis"+ , (0, 6) -- "missis"+ , (0, 9) -- "mississip"+ , (3, 9) -- "sissip"+ , (6, 9) -- "sip"+ , (6, 11) -- "sippi"+ ]+ (sort $ approximateAlgorithm 0 1 (U.fromList "mississippi"))++-- | Test the string "mississippi" with two errors.+testMississippiTwoErrors :: Test+testMississippiTwoErrors =+ TestCase $+ assertEqual+ "testMississippiTwoErrors"+ [ (0, 10) -- "mississipp"+ , (1, 11) -- "ississippi"+ , (4, 11) -- "issippi"+ ]+ (sort $ approximateAlgorithm 0 2 (U.fromList "mississippi"))++-- | Test the string "mississippi" with three errors.+testMississippiThreeErrors :: Test+testMississippiThreeErrors =+ TestCase $+ assertEqual+ "testMississippiThreeErrors"+ -- The whole string is an approximate palindrome with three errors+ [(0, 11)]+ (sort $ approximateAlgorithm 0 3 (U.fromList "mississippi"))++-- | Test the string "mississippi" with four errors.+testMississippiFourErrors :: Test+testMississippiFourErrors =+ TestCase $+ assertEqual+ "testMississippiFourErrors"+ -- The whole string is an approximate palindrome with three errors+ [(0, 11)]+ (sort $ approximateAlgorithm 0 4 (U.fromList "mississippi"))++-- | Test text input with a non-zero even gapSize and no errors.+testTextEvenGapSizeZeroErrors :: Test+testTextEvenGapSizeZeroErrors =+ TestCase $+ assertEqual+ "testTextEvenGapSizeZeroErrors"+ [(0, 2), (0, 6), (1, 3), (3, 5), (3, 7), (5, 7)]+ (sort $ approximateAlgorithm 2 0 (U.fromList "dabcadc"))++-- | Test text input with a non-zero even gapSize and one error.+testTextEvenGapSizeOneError :: Test+testTextEvenGapSizeOneError =+ TestCase $+ assertEqual+ "testTextEvenGapSizeOneError"+ [(0, 7), (2, 7)]+ (sort $ approximateAlgorithm 2 1 (U.fromList "dabcadc"))++{- | Test text input with a non-zero even gapSize and two errors. The whole string is an+approximate palindrome with one error and there are no substrings which are gapped+maximal palindromes with 2 errors, so this should return the whole string.+-}+testTextEvenGapSizeTwoErrors :: Test+testTextEvenGapSizeTwoErrors =+ TestCase $+ assertEqual+ "testTextEvenGapSizeTwoErrors"+ [(0, 7)]+ (sort $ approximateAlgorithm 2 2 (U.fromList "dabcadc"))++{- | Test again with an even gapSize, but with bigger input with more interesting output when+searching with a maximum of 2 errors.+-}+testTextEvenGapSizeTwoErrorsBiggerInput :: Test+testTextEvenGapSizeTwoErrorsBiggerInput =+ TestCase $+ assertEqual+ "testTextEvenGapSizeTwoErrorsBiggerInput"+ [(0, 9), (2, 10)]+ (sort $ approximateAlgorithm 2 2 (U.fromList "cbadcabede"))++{- | Use the same gapSize and input as "testTextEvenGapSizeTwoErrorsBiggerInput", but search for+maximum three errors. Should return the whole string.+-}+testTextEvenGapSizeThreeErrorsBiggerInput :: Test+testTextEvenGapSizeThreeErrorsBiggerInput =+ TestCase $+ assertEqual+ "testTextEvenGapSizeThreeErrorsBiggerInput"+ [(0, 10)]+ (sort $ approximateAlgorithm 2 3 (U.fromList "cbadcabede"))++{- | Test with an odd gapSize and zero errors. The gapSize is 3 and not 1, because 1 character+is always a palindrome because of reflexitivity, so a gapSize of size 1 does not change the+results.+-}+testTextOddGapSizeZeroErrors :: Test+testTextOddGapSizeZeroErrors =+ TestCase $+ assertEqual+ "testTextOddGapSizeZeroErrors"+ [(0, 3), (1, 5), (1, 7), (3, 8), (5, 8), (6, 9), (7, 10)]+ (sort $ approximateAlgorithm 3 0 (U.fromList "cbdabdbacc"))++-- | Test with an odd gapSize and one error.+testTextOddGapSizeOneError :: Test+testTextOddGapSizeOneError =+ TestCase $+ assertEqual+ "testTextOddGapSizeOneError"+ [(0, 9), (2, 9), (5, 10)]+ (sort $ approximateAlgorithm 3 1 (U.fromList "cbdabdbacc"))++{- | Test with an odd gapSize and two errors. The only maximal gapped approximate palindrome+satisfying these constraints is the whole string.+-}+testTextOddGapSizeTwoErrors :: Test+testTextOddGapSizeTwoErrors =+ TestCase $+ assertEqual+ "testTextOddGapSizeTwoErrors"+ [(0, 10)]+ (sort $ approximateAlgorithm 3 2 (U.fromList "cbdabdbacc"))++{- | Test a small DNA sequence with zero errors. Note that for an empty maximal+approximate palindrome, the start character index is the same as the end character index.+Both are the index of the character directly following the empty string in question.+-}+testSmallDNAZeroErrors :: Test+testSmallDNAZeroErrors =+ TestCase $+ assertEqual+ "testSmallDNAZeroErrors"+ [(0, 2), (2, 2), (3, 3), (4, 4)]+ (sort $ approximateAlgorithm 0 0 (U.fromList [A, T, G, G]))++{- | Test the small DNA sequence with one error. The output represents strings [A, T, G]+and [G, G].+-}+testSmallDNAOneError :: Test+testSmallDNAOneError =+ TestCase $+ assertEqual+ "testSmallDNAOneError"+ [(0, 3), (2, 4)]+ (sort $ approximateAlgorithm 0 1 (U.fromList [A, T, G, G]))++-- | test AAAAAAAAA with no errors+testDNAAsZeroErrors :: Test+testDNAAsZeroErrors =+ TestCase $+ assertEqual+ "testDNAAsZeroErrors"+ [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]+ (sort $ approximateAlgorithm 0 0 (U.fromList [A, A, A, A, A, A, A, A, A]))++-- | test AAAAAAAAA with one errors+testDNAAsOneError :: Test+testDNAAsOneError =+ TestCase $+ assertEqual+ "testDNAAsOneError"+ [(0, 2), (1, 3), (2, 4), (3, 5), (4, 6), (5, 7), (6, 8), (7, 9)]+ (sort $ approximateAlgorithm 0 1 (U.fromList [A, A, A, A, A, A, A, A, A]))++{- | Test a big (at least bigger than the small DNA sequence) DNA sequence with zero+errors.+-}+testBigDNAZeroErrors :: Test+testBigDNAZeroErrors =+ TestCase $+ assertEqual+ "testBigDNAZeroErrors"+ [(1, 1), (1, 3), (3, 3), (4, 4), (5, 5), (6, 6), (6, 8), (8, 8), (9, 9), (10, 10)]+ (sort $ approximateAlgorithm 0 0 (U.fromList [A, G, C, A, A, G, T, A, A, C]))++{- | Test a big (at least bigger than the small DNA sequence) DNA sequence with one+error.+-}+testBigDNAOneError :: Test+testBigDNAOneError =+ TestCase $+ assertEqual+ "testBigDNAOneError"+ [(0, 4), (2, 6), (3, 7), (5, 10), (8, 10)]+ (sort $ approximateAlgorithm 0 1 (U.fromList [A, G, C, A, A, G, T, A, A, C]))++{- | Test a big (at least bigger than the small DNA sequence) DNA sequence with two+errors.+-}+testBigDNATwoErrors :: Test+testBigDNATwoErrors =+ TestCase $+ assertEqual+ "testBigDNATwoErrors"+ [(0, 5), (0, 7), (2, 8), (4, 10)]+ (sort $ approximateAlgorithm 0 2 (U.fromList [A, G, C, A, A, G, T, A, A, C]))++{- | Test a big (at least bigger than the small DNA sequence) DNA sequence with three+errors.+-}+testBigDNAThreeErrors :: Test+testBigDNAThreeErrors =+ TestCase $+ assertEqual+ "testBigDNAThreeErrors"+ [(0, 8), (1, 10), (3, 10)]+ (sort $ approximateAlgorithm 0 3 (U.fromList [A, G, C, A, A, G, T, A, A, C]))++{- | Test a big (at least bigger than the small DNA sequence) DNA sequence with four+errors. The whole string is then an approximate palindrome.+-}+testBigDNAFourErrors :: Test+testBigDNAFourErrors =+ TestCase $+ assertEqual+ "testBigDNAFourErrors"+ [(0, 10)]+ (sort $ approximateAlgorithm 0 4 (U.fromList [A, G, C, A, A, G, T, A, A, C]))++{- | Test a big (at least bigger than the small DNA sequence) DNA sequence with five+errors. The whole string is then an approximate palindrome. This is tested in addition to+testing with four errors to assert that maximal approximate palindromes with strictly+fewer errors than the maximum are also found.+-}+testBigDNAFiveErrors :: Test+testBigDNAFiveErrors =+ TestCase $+ assertEqual+ "testBigDNAFiveErrors"+ [(0, 10)]+ (sort $ approximateAlgorithm 0 5 (U.fromList [A, G, C, A, A, G, T, A, A, C]))++{- | Test some DNA string input with a gapSize of 1 and 0 errors. This is the first+test for a non-zero gapSize.+-}+testDNAGapSizeOneZeroErrors :: Test+testDNAGapSizeOneZeroErrors =+ TestCase $+ assertEqual+ "testDNAGapSizeOneZeroErrors"+ [(0, 1), (0, 3), (1, 4), (3, 6), (5, 6), (6, 7)]+ (sort $ approximateAlgorithm 1 0 (U.fromList [A, C, T, G, C, C, T]))++{- | Test some DNA string input with a gapSize of 1 and 1 error. This tests the+combination of gapSize and errors.+-}+testDNAGapSizeOneOneError :: Test+testDNAGapSizeOneOneError =+ TestCase $+ assertEqual+ "testDNAGapSizeOneOneError"+ [(0, 5), (2, 7)]+ (sort $ approximateAlgorithm 1 1 (U.fromList [A, C, T, G, C, C, T]))++{- | Test some DNA string input with a gapSize of 1 and 2 errors. The output should be+the indices for the whole string.+-}+testDNAGapSizeOneTwoErrors :: Test+testDNAGapSizeOneTwoErrors =+ TestCase $+ assertEqual+ "testDNAGapSizeOneTwoErrors"+ [(0, 7)]+ (sort $ approximateAlgorithm 1 2 (U.fromList [A, C, T, G, C, C, T]))++{- | Test some DNA string input with a gapSize of 1 and 3 errors. The output should be+the indices for the whole string. This tests whether gapped approximate strings with less errors+than the maximum are found correctly.+-}+testDNAGapSizeOneThreeErrors :: Test+testDNAGapSizeOneThreeErrors =+ TestCase $+ assertEqual+ "testDNAGapSizeOneThreeErrors"+ [(0, 7)]+ (sort $ approximateAlgorithm 1 3 (U.fromList [A, C, T, G, C, C, T]))++{- | Test some DNA string input with a gapSize of 2 and 0 errors. This tests the+algorithm using an even gap.+-}+testDNAGapSizeTwoZeroErrors :: Test+testDNAGapSizeTwoZeroErrors =+ TestCase $+ assertEqual+ "testDNAGapSizeTwoZeroErrors"+ [(0, 2), (0, 4), (1, 6), (4, 7), (6, 8)]+ (sort $ approximateAlgorithm 2 0 (U.fromList [A, G, G, T, C, C, G, T]))++-- | Test some DNA string input with a gapSize of 2 and 1 error. Tests even gapSize with an error.+testDNAGapSizeTwoOneError :: Test+testDNAGapSizeTwoOneError =+ TestCase $+ assertEqual+ "testDNAGapSizeTwoZeroErrors"+ [(0, 8), (3, 8)]+ (sort $ approximateAlgorithm 2 1 (U.fromList [A, G, G, T, C, C, G, T]))++{- | Test some DNA string input with a gapSize of 2 and 2 errors. Tests even gapSize with an+error and tests whether the algorithm makes a jump from having two errors to having one+error again by adding a single character.+-}+testDNAGapSizeTwoTwoErrors :: Test+testDNAGapSizeTwoTwoErrors =+ TestCase $+ assertEqual+ "testDNAGapSizeTwoTwoErrors"+ [(0, 8)]+ (sort $ approximateAlgorithm 2 2 (U.fromList [A, G, G, T, C, C, G, T]))++{- | Test some DNA string input with a gapSize of 3 and 0 errors. Tests an odd gapSize which+is bigger than 1.+-}+testDNAGapSizeThreeZeroErrors :: Test+testDNAGapSizeThreeZeroErrors =+ TestCase $+ assertEqual+ "testDNAGapSizeThreeZeroErrors"+ [(0, 3), (1, 4), (1, 6), (1, 8), (5, 8)]+ (sort $ approximateAlgorithm 3 0 (U.fromList [C, C, T, T, A, G, A, G]))++{- | Test some DNA string input with a gapSize of 3 and 1 error. Tests an odd gapSize which+is bigger than 1 in combination with an error.+-}+testDNAGapSizeThreeOneError :: Test+testDNAGapSizeThreeOneError =+ TestCase $+ assertEqual+ "testDNAGapSizeThreeOneError"+ [(0, 8)]+ (sort $ approximateAlgorithm 3 1 (U.fromList [C, C, T, T, A, G, A, G]))++{- | Test some DNA string input with a gapSize of 3 and 4 errors. Tests an odd gapSize which+is bigger than 1 in combination with an error and tests whether the algorithm finds that+the whole string is an approximate palindrome with less than 4 errors.+-}+testDNAGapSizeThreeFourErrors :: Test+testDNAGapSizeThreeFourErrors =+ TestCase $+ assertEqual+ "testDNAGapSizeThreeFourErrors"+ [(0, 8)]+ (sort $ approximateAlgorithm 3 4 (U.fromList [C, C, T, T, A, G, A, G]))
+ tests/UTDNAPals.hs view
@@ -0,0 +1,25 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTDNAPals (testListDNA) where++import Test.HUnit (Test (..), assertEqual)++import PalindromeMethods (longestDNAPalindrome)++testListDNA t =+ [ TestLabel "testDNAPalindrome1" $ testDNAPalindrome1 t+ , TestLabel "testDNAPalindrome2" $ testDNAPalindrome2 t+ ]++testDNAPalindrome1 t =+ TestCase $+ assertEqual "palindrome1" "\"gcgcgcatatatatgcgcgc\"" $+ longestDNAPalindrome t "gcgcgcatatatatgcgcgc"++testDNAPalindrome2 t =+ TestCase $+ assertEqual "palindrome1" "\"tatata\"" $+ longestDNAPalindrome t "tatata"
+ tests/UTExtendPals.hs view
@@ -0,0 +1,72 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTExtendPals (testListExtend) where++import Test.HUnit (Test (..), assertEqual)++import Data.Algorithms.Palindromes.Finders (Algorithm)+import PalindromeMethods (extendTextPalindrome)++testExtendPalindrome1+ , testExtendPalindrome2+ , testExtendPalindrome3+ , testExtendPalindrome4+ , testExtendPalindrome5+ , testExtendPalindrome6+ , testExtendPalindrome7+ , testExtendPalindrome8+ :: Algorithm -> Test++testListExtend t =+ [ TestLabel "testExtendPalindrome1" $ testExtendPalindrome1 t+ , TestLabel "testExtendPalindrome2" $ testExtendPalindrome2 t+ , TestLabel "testExtendPalindrome3" $ testExtendPalindrome3 t+ , TestLabel "testExtendPalindrome4" $ testExtendPalindrome4 t+ , TestLabel "testExtendPalindrome5" $ testExtendPalindrome5 t+ , TestLabel "testExtendPalindrome6" $ testExtendPalindrome6 t+ , TestLabel "testExtendPalindrome7" $ testExtendPalindrome7 t+ , TestLabel "testExtendPalindrome8" $ testExtendPalindrome8 t+ ]++testExtendPalindrome1 t =+ TestCase $+ assertEqual "extendPalindrome1" "\"e fe\"" $+ extendTextPalindrome t 39 "the cat jumped over the fence"++testExtendPalindrome2 t =+ TestCase $+ assertEqual "extendPalindrome2" "\"evil live\"" $+ extendTextPalindrome t 30 "They found an evil live broadcast"++testExtendPalindrome3 t =+ TestCase $+ assertEqual "extendPalindrome3" "\"o ho\"" $+ extendTextPalindrome t 31 "The coffee was too hot to drink"++testExtendPalindrome4 t =+ TestCase $+ assertEqual "extendPalindrome4" "\"d\"" $+ extendTextPalindrome t 3 "A dog barked in the distance"++testExtendPalindrome5 t =+ TestCase $+ assertEqual "extendPalindrome5" "\"oo\"" $+ extendTextPalindrome t 10 "The book fell off the shelf"++testExtendPalindrome6 t =+ TestCase $+ assertEqual "extendPalindrome6" "\"\"" $+ extendTextPalindrome t 0 "the cat jumped over the fence"++testExtendPalindrome7 t =+ TestCase $+ assertEqual "extendPalindrome7" "\"s s\"" $+ extendTextPalindrome t 10 "Birds sang outside my window"++testExtendPalindrome8 t =+ TestCase $+ assertEqual "extendPalindrome8" "\"racecar\"" $+ extendTextPalindrome t 13 "The racecar zoomed past us"
+ tests/UTFinders.hs view
@@ -0,0 +1,111 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTFinders (testListFinders) where++import Test.HUnit (Test (..), (~:), (~?=))++import Data.Algorithms.Palindromes.Finders+ ( Algorithm (AlgQuadratic)+ , Variant (VarDNA, VarPlain, VarText, VarWord)+ , findPalindromes+ )+import Data.Algorithms.Palindromes.Palindrome+ ( Palindrome (..)+ )++testListFinders =+ [ testFinderPlain+ , testFinderText+ , testFinderWord+ , testFinderDNA+ , testFinderDNA+ ]++testFinderPlain =+ "testFinderPlain"+ ~: findPalindromes VarPlain (AlgQuadratic 0 0) 1 "aba"+ ~?= [ ( Palindrome+ { palRange = (0, 1)+ , palText = "a"+ , palRangeInText = (0, 1)+ }+ )+ , ( Palindrome+ { palRange = (0, 3)+ , palText = "aba"+ , palRangeInText = (0, 3)+ }+ )+ , ( Palindrome+ { palRange = (2, 3)+ , palText = "a"+ , palRangeInText = (2, 3)+ }+ )+ ]++testFinderText =+ "testFinderText"+ ~: findPalindromes VarText (AlgQuadratic 0 0) 1 "ab'A"+ ~?= [ ( Palindrome+ { palRange = (0, 1)+ , palText = "a"+ , palRangeInText = (0, 1)+ }+ )+ , ( Palindrome+ { palRange = (0, 3)+ , palText = "ab'A"+ , palRangeInText = (0, 4)+ }+ )+ , ( Palindrome+ { palRange = (2, 3)+ , palText = "A"+ , palRangeInText = (3, 4)+ }+ )+ ]++testFinderWord =+ "testFinderWord"+ ~: findPalindromes VarWord (AlgQuadratic 0 0) 1 "aba' bbb\n aba"+ ~?= [ ( Palindrome+ { palRange = (0, 1)+ , palText = "aba"+ , palRangeInText = (0, 3)+ }+ )+ , ( Palindrome+ { palRange = (0, 3)+ , palText = "aba' bbb\n aba"+ , palRangeInText = (0, 13)+ }+ )+ , ( Palindrome+ { palRange = (2, 3)+ , palText = "aba"+ , palRangeInText = (10, 13)+ }+ )+ ]++testFinderDNA =+ "testFinderDNA"+ ~: findPalindromes VarDNA (AlgQuadratic 0 0) 1 "ATA"+ ~?= [ ( Palindrome+ { palRange = (0, 2)+ , palText = "AT"+ , palRangeInText = (0, 2)+ }+ )+ , ( Palindrome+ { palRange = (1, 3)+ , palText = "TA"+ , palRangeInText = (1, 3)+ }+ )+ ]
+ tests/UTGetLeftRight.hs view
@@ -0,0 +1,194 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTGetLeftRight (testListGetLeftRight) where++import Test.HUnit (Test (..), assertEqual)++import Data.Algorithms.Palindromes.QuadraticAlgorithm+ ( getLeftRightCenterBetweenElems+ , getLeftRightCenterOnElem+ )++testListGetLeftRight =+ [ testCenterBetweenElems+ , testCenterBetweenElemsOddGap+ , testCenterBetweenElemsOutOfBoundsLeft+ , testCenterBetweenElemsOutOfBoundsRight+ , testCenterBetweenElemsZeroGap+ , testCenterBetweenElemsGapLargerThanInput+ , testCenterBetweenElemsGapLargerThanInputCenterRightToMiddle+ , testCenterOnElem+ , testCenterOnElemEvenGap+ , testCenterOnElemOutOfBoundsLeft+ , testCenterOnElemOutOfBoundsRight1+ , testCenterOnElemOutOfBoundsRight2+ , testCenterOnElemZeroGap+ , testCenterOnElemGapLargerThanInput+ , testCenterOnElemGapLargerThanInputCenterRightToMiddle+ ]++{-+---------------------------------------------------+Tests for center between elements+---------------------------------------------------+-}++-- | Test normal input with even gap and center between two elements.+testCenterBetweenElems =+ TestCase $+ assertEqual+ "testCenterBetweenElems"+ (2, 5)+ (getLeftRightCenterBetweenElems 2 4 7)++{- | Test whether inputting an odd gap in getLeftRightCenterBetweenElems behaves as+ expected.+-}+testCenterBetweenElemsOddGap =+ TestCase $+ assertEqual+ "testCenterBetweenElemsOddGap"+ (2, 5)+ (getLeftRightCenterBetweenElems 3 4 7)++{- | Test input with even gap and center between two elements where gap+goes out of bounds to the left.+-}+testCenterBetweenElemsOutOfBoundsLeft =+ TestCase $+ assertEqual+ "testCenterBetweenElemsOutOfBoundsLeft"+ (-1, 2)+ (getLeftRightCenterBetweenElems 4 1 7)++{- | Test input with even gap and center between two elements where gap+goes out of bounds to the right.+-}+testCenterBetweenElemsOutOfBoundsRight =+ TestCase $+ assertEqual+ "testCenterBetweenElemsOutOfBoundsRight"+ (4, 7)+ (getLeftRightCenterBetweenElems 8 6 7)++-- | Test input with gap size of zero and center between two elements.+testCenterBetweenElemsZeroGap =+ TestCase $+ assertEqual+ "testCenterBetweenElemsZeroGap"+ (3, 4)+ (getLeftRightCenterBetweenElems 0 4 7)++{- | Test whether the out of bounds indices are returned if the gap is+ larger than the input and the center is between two elements.+-}+testCenterBetweenElemsGapLargerThanInput =+ TestCase $+ assertEqual+ "testCenterBetweenElemsGapLargerThanInput"+ (-1, 6)+ (getLeftRightCenterBetweenElems 9 3 7)++{- | Test whether getLeftRightCenterBetweenElems works as intended with a large gap that+goes out of bounds to the left and to the right, where (elemIndex > lengthInput `div` 2).+This test case makes sure that the gap does not go outside of the left bound and not+outside of the right bound. In previous implementations, if the gap would go outside of+the left bound it would be cut off, but it would not be checked whether the new gap length+goes outside of the right bound after that, resulting in some gaps going far outside the+right bounds.+-}+testCenterBetweenElemsGapLargerThanInputCenterRightToMiddle =+ TestCase $+ assertEqual+ "testCenterBetweenElemsGapLargerThanInputCenterRightToMiddle"+ (6, 7)+ (getLeftRightCenterBetweenElems 20 7 7)++{-+---------------------------------------------------+Tests for center on element+---------------------------------------------------+-}++-- | Test normal input with odd gap and center on element.+testCenterOnElem =+ TestCase $+ assertEqual+ "testCenterOnElem"+ (1, 5)+ (getLeftRightCenterOnElem 3 3 7)++-- | Test whether inputting an even gap in getLeftRightCenterOnElem behaves as expected.+testCenterOnElemEvenGap =+ TestCase $+ assertEqual+ "testCenterOnElemEvenGap"+ (1, 5)+ (getLeftRightCenterOnElem 4 3 7)++{- | Test input with odd gap and center on element where gap+goes out of bounds to the left.+-}+testCenterOnElemOutOfBoundsLeft =+ TestCase $+ assertEqual+ "testCenterOnElemOutOfBoundsLeft"+ (-1, 3)+ (getLeftRightCenterOnElem 5 1 7)++{- | Test input with odd gap and center on element where gap+goes out of bounds to the right.+-}+testCenterOnElemOutOfBoundsRight1 =+ TestCase $+ assertEqual+ "testCenterOnElemOutOfBoundsRight1"+ (5, 7)+ (getLeftRightCenterOnElem 5 6 7)++{- | Test input with odd gap and center on element where gap+goes out of bounds to the right. This tests the same thing as the previous test,+because there were some subtle errors in the code, so we want to be+extra sure this works.+-}+testCenterOnElemOutOfBoundsRight2 =+ TestCase $+ assertEqual+ "testCenterOnElemOutOfBoundsRight2"+ (3, 7)+ (getLeftRightCenterOnElem 9 5 7)++{- | Test input with gapsize of zero and center on element. The output must have left+and right equal to the element index so the not anti-reflexive function can check+whether the element on the index is PalEq to itself.+-}+testCenterOnElemZeroGap =+ TestCase $+ assertEqual+ "testCenterOnElemZeroGap"+ (4, 4)+ (getLeftRightCenterOnElem 0 4 7)++{- | Test whether the out of bounds indices are returned if the gap is+ larger than the input and the center is on an element.+-}+testCenterOnElemGapLargerThanInput =+ TestCase $+ assertEqual+ "testCenterOnElemGapLargerThanInput"+ (-1, 7)+ (getLeftRightCenterOnElem 9 3 7)++{- Test whether getLeftRightCenterOnElem works as intended with a large gap that goes+outside of the left and right bounds, where (elemIndex > lengthInput `div` 2). See comment+on 'testCenterBetweenElemsGapMuchLargerThanInput' for why this must be checked.+-}+testCenterOnElemGapLargerThanInputCenterRightToMiddle =+ TestCase $+ assertEqual+ "testCenterOnElemGapLargerThanInputCenterRightToMiddle"+ (5, 7)+ (getLeftRightCenterOnElem 20 6 7)
+ tests/UTLinearAlgorithm.hs view
@@ -0,0 +1,368 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTLinearAlgorithm (testListLinearAlgorithm) where++import Test.HUnit (Test (..), assertEqual)++import Data.Algorithms.Palindromes.DNA (DNA (..), toDNA)++import qualified Data.Vector.Unboxed as U++import qualified Data.Algorithms.Palindromes.LinearAlgorithm as P++testListLinearAlgorithm =+ [ testExtendPalindromeSSimple+ , testExtendPalindromeSWhole+ , testExtendPalindromeSIntertwined+ , testExtendPalindromeSNothing+ , testExtendPalindromeSEmpty+ , testExtendPalindromeSDNA+ , testExtendPalindromeSDNAAllCenters+ , testMoveCenterSSimple+ , testMoveCenterSGuard1+ , testMoveCenterSGuard2+ , testMoveCenterSGuard3+ , testMoveCenterSDNA+ , testMoveCenterSDNAAllCenters+ , testFinalPalindromesSSimple+ , testFinalPalindromesSCutOff+ , testFinalPalindromesNrOfCentersZero+ , testFinalPalindromesSDNA+ , testFinalPalindromesSDNACutOff+ ]++{-+----------------------------------------------------------+ Begin tests for extendPalindromeS+----------------------------------------------------------+-}+{- Test a simple small string with extendPalindromeS -}+testExtendPalindromeSSimple =+ TestCase $+ assertEqual+ "testExtendPalindromeSSimple"+ [0, 1, 0, 3, 0, 1, 0, 1, 2, 1, 0]+ ( P.extendPalindromeS+ False+ (U.fromList "nnaba")+ 0+ []+ 0+ )++{- Test a string on extendPalindromeS consisting of one big palindrome. The output list should be symmetrical -}+testExtendPalindromeSWhole =+ TestCase $+ assertEqual+ "testExtendPalindromeSWhole"+ [0, 1, 0, 1, 2, 1, 0, 1, 0, 1, 0, 11, 0, 1, 0, 1, 0, 1, 2, 1, 0, 1, 0]+ ( P.extendPalindromeS+ False+ (U.fromList "meetsysteem")+ 0+ []+ 0+ )++{- Test a string on extendPalindromeS where two of the oalindromes overlap with each other, in this case "leepeel"+and "peeleep" -}+testExtendPalindromeSIntertwined =+ TestCase $+ assertEqual+ "testExtendPalindromeSIntertwined"+ [0, 1, 0, 1, 2, 1, 0, 7, 0, 1, 2, 1, 0, 7, 0, 1, 2, 1, 0, 1, 0]+ ( P.extendPalindromeS+ False+ (U.fromList "leepeeleep")+ 0+ []+ 0+ )++{- Test a string on extendPalindromeS not containing any palindromes -}+testExtendPalindromeSNothing =+ TestCase $+ assertEqual+ "testExtendPalindromeSNothing"+ [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]+ ( P.extendPalindromeS+ False+ (U.fromList "abcdefgh")+ 0+ []+ 0+ )++{- Test an empty string on extendPalindromeS -}+testExtendPalindromeSEmpty =+ TestCase $+ assertEqual+ "testExtendPalindromeSEmpty"+ [0]+ ( P.extendPalindromeS+ False+ (U.fromList "")+ 0+ []+ 0+ )++-- Test a DNA string on extendPalindromeS+testExtendPalindromeSDNA =+ TestCase $+ assertEqual+ "testExtendPalindromeSDNA"+ [0, 2, 0, 6, 0, 2, 0]+ ( P.extendPalindromeS+ True+ (U.fromList [A, T, G, C, A, T])+ 0+ []+ 0+ )++{- Test a DNA string on extendPalindromeS without skipping the centers on elements. If+this works, non-reflexive, non-anti-reflexive datatypes will likely also work -}+testExtendPalindromeSDNAAllCenters =+ TestCase $+ assertEqual+ "testExtendPalindromeSDNAAllCenters"+ [0, 0, 2, 0, 4, 0, 2, 0, 0, 0, 2, 0, 0]+ ( P.extendPalindromeS+ False+ (U.fromList [A, T, G, C, G, C])+ 0+ []+ 0+ )++{-+----------------------------------------------------------+ End tests for extendPalindromeS+----------------------------------------------------------+-}++{-+----------------------------------------------------------+ Begin tests for moveCenterS+----------------------------------------------------------+-}++{- Test moveCenterS on a simple string -}+testMoveCenterSSimple =+ TestCase $+ assertEqual+ "testMoveCenterSSimple"+ [0, 1, 0, 1, 4, 1, 0, 1, 4, 1, 0, 3, 0, 1, 0]+ ( P.moveCenterS+ False+ (U.fromList "abaabba")+ 5+ [4, 1, 0, 3, 0, 1, 0]+ [1, 0, 3, 0, 1, 0]+ 4+ )++{- Tests moveCenterS on a string, ensuring it passes through+the first guard of moveCenterS by making rightmost = 0 -}+testMoveCenterSGuard1 =+ TestCase $+ assertEqual+ "testMoveCenterSGuard1"+ [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]+ ( P.moveCenterS+ False+ (U.fromList "abcdefgh")+ 4+ [0, 1, 0, 1, 0, 1, 0, 1, 0]+ [1, 0, 1, 0, 1, 0, 1, 0]+ 0+ )++{- Tests moveCenterS on a string, ensuring it passes through+the second guard of moveCenterS by ensuring+head maximalPalindromesIn' == nrOfCenters - centerfactor -}+testMoveCenterSGuard2 =+ TestCase $+ assertEqual+ "testMoveCenterSGuard2"+ [0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 0, 1, 0, 1, 0]+ ( P.moveCenterS+ False+ (U.fromList "abcaaaaxyz")+ 7+ [4, 3, 2, 1, 0, 1, 0, 1, 0, 1, 0]+ [3, 2, 1, 0, 1, 0, 1, 0, 1, 0]+ 4+ )++{- Tests moveCenterS on a string, ensuring it passes through+the third guard of moveCenterS by ensuring neither+rightmost = 0 and head maximalPalindromesIn' == nrOfCenters - centerfactor -}+testMoveCenterSGuard3 =+ TestCase $+ assertEqual+ "testMoveCenterSGuard3"+ [0, 1, 0, 1, 2, 1, 0, 1, 0, 1, 0, 11, 0, 1, 0, 1, 0, 1, 2, 1, 0, 1, 0]+ ( P.moveCenterS+ False+ (U.fromList "meetsysteem")+ 11+ [11, 0, 1, 0, 1, 0, 1, 2, 1, 0, 1, 0]+ [0, 1, 0, 1, 0, 1, 2, 1, 0, 1, 0]+ 11+ )++{- Tests moveCenterS on a DNA string -}+testMoveCenterSDNA =+ TestCase $+ assertEqual+ "testMoveCenterSDNA"+ [0, 2, 0, 0, 0, 6, 0, 0, 0, 2, 0]+ ( P.moveCenterS+ True+ (U.fromList [A, T, G, A, C, G, T, C, C, G])+ 8+ [6, 0, 0, 0, 2, 0]+ [0, 0, 0, 2, 0]+ 6+ )++{- Tests moveCenterS on a DNA string, not skipping any centers -}+testMoveCenterSDNAAllCenters =+ TestCase $+ assertEqual+ "testMoveCenterSDNAAllCenters"+ [0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]+ ( P.moveCenterS+ False+ (U.fromList [A, T, G, A, C, G, T, C, C, G])+ 8+ [6, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]+ [0, 0, 0, 0, 0, 0, 0, 2, 0, 0]+ 6+ )++{-+----------------------------------------------------------+ End tests for moveCenterS+----------------------------------------------------------+-}++{-+----------------------------------------------------------+ Begin tests for finalPalindromeS+----------------------------------------------------------+-}++{- Test a simple case for finalPalindromesS, where no palindrome needs to be truncated.+This test is based on input string "leepeel" -}+testFinalPalindromesSSimple =+ TestCase $+ assertEqual+ "testFinalPalindromesSSimple"+ [0, 1, 0, 1, 2, 1, 0, 7, 0, 1, 2, 1, 0, 1, 0]+ ( P.finalPalindromesS+ False+ 7+ [0, 1, 2, 1, 0, 1, 0]+ [7, 0, 1, 2, 1, 0, 1, 0]+ )++{- Test a case where some palindromes need to be truncated. This test is based on input+string "aaaaaaaaabaaaaaa", so 9x 'a', 1x 'b' and 6x 'a'. -}+testFinalPalindromesSCutOff =+ TestCase $+ assertEqual+ "testFinalPalindromesSCutOff"+ [ 0+ , 1+ , 2+ , 3+ , 4+ , 5+ , 6+ , 5+ , 4+ , 3+ , 2+ , 1+ , 0+ , 13+ , 0+ , 1+ , 2+ , 3+ , 4+ , 5+ , 6+ , 7+ , 8+ , 9+ , 8+ , 7+ , 6+ , 5+ , 4+ , 3+ , 2+ , 1+ , 0+ ]+ ( P.finalPalindromesS+ False+ 13+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]+ [13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]+ )++{- Test a case where the palindrome initiating finalPalindromesS does not contain another+palindrome. This test is based on input string "abcd". -}+testFinalPalindromesNrOfCentersZero =+ TestCase $+ assertEqual+ "testFinalPalindromesNrOfCentersZero"+ [0, 1, 0, 1, 0, 1, 0, 1, 0]+ ( P.finalPalindromesS+ False+ 0+ [1, 0, 1, 0, 1, 0, 1, 0]+ [0, 1, 0, 1, 0, 1, 0, 1, 0]+ )++{- Test a DNA case with a palindrome in the palindrome which initiates finalPalindromeS.+This test is based on input string "TGCATG" -}+testFinalPalindromesSDNA =+ TestCase $+ assertEqual+ "testFinalPalindromesSDNA"+ [0, 0, 4, 0, 4, 0, 0]+ ( P.finalPalindromesS+ True+ 4+ [0, 4, 0, 0]+ [4, 0, 4, 0, 0]+ )++{- Test a DNA case, where some palindrome needs to be truncated to a non-zero value.+This test is based on input string "TGCATGC" -}+testFinalPalindromesSDNACutOff =+ TestCase $+ assertEqual+ "testFinalPalindromesSDNACutOff"+ [0, 2, 0, 6, 0, 4, 0, 0]+ ( P.finalPalindromesS+ True+ 6+ [0, 4, 0, 0]+ [6, 0, 4, 0, 0]+ )++{-+----------------------------------------------------------+ End tests for finalPalindromeS+----------------------------------------------------------+-}
+ tests/UTPalEq.hs view
@@ -0,0 +1,104 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTPalEq (testListPalEq) where++import Data.Maybe (fromJust)+import Test.HUnit (Test (..), (~:), (~?=))++import Data.Algorithms.Palindromes.DNA+ ( DNA (A, C, G, T)+ , toDNA+ )+import Data.Algorithms.Palindromes.PalEq+ ( PalEq ((=:=))+ , palEqToItselfAtIndex+ )++import qualified Data.Vector.Unboxed as U++testListPalEq :: [Test]+testListPalEq =+ testsPalEq+ ++ [ testPalEqToItselfTrue+ , testPalEqToItselfFalse+ , testPalEqToItselfAtIndexReflexive+ , testPalEqToItselfAtIndexAntiReflexive+ , testPalEqToItselfAtIndexOutOfLowerBound+ , testPalEqToItselfAtIndexOutOfUpperBound+ ]++{-+--------------------------------------+ Begin tests for PalEq definition & DNA definition and functions+--------------------------------------+-}+testsPalEq =+ [ "testIntegerPalEq" ~: (5 :: Int) =:= 5 ~?= True+ , "testIntegerInPalEq" ~: (5 :: Int) =:= 3 ~?= False+ , "testCharPalEq" ~: 'a' =:= 'a' ~?= True+ , "testCharInPalEq" ~: 'a' =:= 'b' ~?= False+ , "testDNAPalEq" ~: A =:= T ~?= True+ , "testDNAPalEq2" ~: T =:= A ~?= True+ , "testDNAInPalEq1" ~: A =:= C ~?= False+ , "testDNAInPalEq2" ~: A =:= A ~?= False+ , "testCharToDNA" ~: (U.toList . fromJust . toDNA . U.fromList) "aA" ~?= [A, A]+ ]++{-+--------------------------------------+ End tests for DNA definition and functions+--------------------------------------+-}++{-+----------------------------------------------------------------------+Begin tests for (=:=) and PalEqToItselfAtIndex+----------------------------------------------------------------------+-}++-- | Test with an element that is PalEq with itself.+testPalEqToItselfTrue =+ "testPalEqToItselfTrue"+ ~: 'b'+ =:= 'b'+ ~?= True++-- | Test with an element that is not PalEq to itself.+testPalEqToItselfFalse =+ "testPalEqToItselfFalse"+ ~: A+ =:= A+ ~?= False++-- | Test with a reflexive datatype and index in range.+testPalEqToItselfAtIndexReflexive =+ "testPalEqToItselfAtIndex"+ ~: palEqToItselfAtIndex (U.fromList "abc") 2+ ~?= True++-- | Test with an anti-reflexive datatype and index in range.+testPalEqToItselfAtIndexAntiReflexive =+ "testPalEqToItselfAtIndex"+ ~: palEqToItselfAtIndex (U.fromList [A, T, C]) 2+ ~?= False++-- | Test with an out of range index that is too small.+testPalEqToItselfAtIndexOutOfLowerBound =+ "testPalEqToItselfAtIndexOutOfLowerBound"+ ~: palEqToItselfAtIndex (U.fromList "abc") (-1)+ ~?= False++-- | Test with an out of range index that is too big.+testPalEqToItselfAtIndexOutOfUpperBound =+ "testPalEqToItselfAtIndexOutOfUpperBound"+ ~: palEqToItselfAtIndex (U.fromList "abc") 3+ ~?= False++{-+----------------------------------------------------------------------+End tests for palEqToItself and palEqToItselfAtIndex+----------------------------------------------------------------------+-}
+ tests/UTProcessing.hs view
@@ -0,0 +1,96 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTProcessing (testListProcessing) where++import Test.HUnit (Test (..), assertEqual)++import qualified Data.Vector as V (fromList)+import qualified Data.Vector.Unboxed as U++import qualified Data.Algorithms.Palindromes.PostProcessing as Post+import qualified Data.Algorithms.Palindromes.PreProcessing as Pre++testListProcessing =+ [ testFilterLetters+ , testTextToWord+ , testFilterPunctuationOnlySpace+ , testFilterPunctuationStaysSame+ , testFilterPunctuationPunctuationAndSpaces+ ]++-- Preprocessing functions+testFilterLetters =+ TestCase $+ assertEqual+ "testFilterLetters"+ (U.fromList [0, 2, 3, 5])+ (Pre.filterLetters' (U.fromList "a'ba a"))++-- ToDNA test al geschreven in UTPalindromeUtils. Moet verplaatst hiernaartoe++testTextToWord =+ TestCase $+ assertEqual+ "testTextToWord"+ (V.fromList ["this", "is", "a", "list", "of", "words"])+ (Pre.textToWords (U.fromList "This is a list of words. "))++-- Postprocessing functions+testFilterPunctuationOnlySpace =+ TestCase $+ assertEqual+ "testFilterPunctuationOnlySpace"+ [(0, 0), (0, 0), (1, 1), (1, 1), (2, 2), (2, 2), (3, 3), (3, 4), (4, 4)]+ ( Post.filterPunctuation+ (U.fromList "aab a")+ [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (1, 4), (3, 3), (3, 4), (4, 4)]+ )++testFilterPunctuationStaysSame =+ TestCase $+ assertEqual+ "testFilterPunctuationStaysSame"+ [(0, 0), (0, 1), (1, 1), (0, 3), (2, 2), (2, 3), (3, 3)]+ ( Post.filterPunctuation+ (U.fromList "a b a")+ [(0, 0), (0, 1), (1, 1), (0, 3), (2, 2), (2, 3), (3, 3)]+ )++testFilterPunctuationPunctuationAndSpaces =+ TestCase $+ assertEqual+ "testFilterPunctuationPunctuationAndSpace"+ [ (0, 0)+ , (0, 1)+ , (1, 1)+ , (1, 2)+ , (2, 2)+ , (2, 2)+ , (0, 6)+ , (3, 3)+ , (4, 4)+ , (4, 4)+ , (5, 5)+ , (5, 6)+ , (6, 6)+ ]+ ( Post.filterPunctuation+ (U.fromList "a.b,aab a ")+ [ (0, 0)+ , (0, 1)+ , (1, 1)+ , (0, 3)+ , (2, 2)+ , (2, 3)+ , (0, 6)+ , (3, 4)+ , (4, 4)+ , (3, 6)+ , (5, 5)+ , (5, 6)+ , (6, 6)+ ]+ )
+ tests/UTPunctuationPals.hs view
@@ -0,0 +1,50 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTPunctuationPals (testListPunctuation) where++import Test.HUnit (Test (..), (~:), (~?=))++import PalindromeMethods (longestPunctuationPalindrome)++testListPunctuation :: [Test]+testListPunctuation =+ [ testPunctuationPalindrome1+ , testPunctuationPalindrome2+ , testPunctuationPalindrome3+ , testPunctuationPalindrome4+ , testPunctuationPalindrome5+ , testPunctuationPalindrome6+ , testPunctuationPalindrome7+ ]++testPunctuationPalindrome1 =+ "testPunctuationPalindrome1"+ ~: longestPunctuationPalindrome "what is non si, not?"+ ~?= "\"is non si\""+testPunctuationPalindrome2 =+ "testPunctuationPalindrome2"+ ~: longestPunctuationPalindrome "what is non si"+ ~?= "\"is non si\""+testPunctuationPalindrome3 =+ "testPunctuationPalindrome3"+ ~: longestPunctuationPalindrome "is non si, not?"+ ~?= "\"is non si\""+testPunctuationPalindrome4 =+ "testPunctuationPalindrome4"+ ~: longestPunctuationPalindrome "aaaaba"+ ~?= "\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\"\n\"\""+testPunctuationPalindrome5 =+ "testPunctuationPalindrome5"+ ~: longestPunctuationPalindrome "aaaab a"+ ~?= "\"a\""+testPunctuationPalindrome6 =+ "testPunctuationPalindrome6"+ ~: longestPunctuationPalindrome "w waaw wo waw"+ ~?= "\"waaw\""+testPunctuationPalindrome7 =+ "testPunctuationPalindrome7"+ ~: longestPunctuationPalindrome "vwaawvxy v waaw v"+ ~?= "\"v waaw v\""
+ tests/UTQuadraticAlgorithm.hs view
@@ -0,0 +1,316 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTQuadraticAlgorithm (testListQuadraticAlgorithm) where++import Test.HUnit (Test (..), assertEqual)++import Data.Algorithms.Palindromes.DNA+ ( DNA (..)+ )++import qualified Data.Vector.Unboxed as U++import qualified Data.Algorithms.Palindromes.QuadraticAlgorithm as Q++testListQuadraticAlgorithm =+ [ testGappedApproximatePalindromesAroundCentresDNA+ , testGappedApproximatePalindromesAroundCentresText+ , testLengthPalAtCenterReflexiveEven+ , testLengthGappedPalAtCenterReflexiveEven+ , testLengthPalWithErrorsAtCenterReflexiveEven+ , testLengthGappedPalWithErrorsAtCenterReflexiveEven+ , testLengthPalAtCenterReflexiveOdd+ , testLengthGappedPalAtCenterReflexiveOdd+ , testLengthPalWithErrorsAtCenterReflexiveOdd+ , testLengthGappedPalWithErrorsAtCenterReflexiveOdd+ , testGetLeftRightReflexiveEven+ , testGetLeftRightReflexiveOdd+ , testLengthPalAtCenterAntiReflexive+ , testLengthGappedPalAtCenterAntiReflexive+ , testLengthPalWithErrorsAtCenterAntiReflexive+ , testLengthGappedPalWithErrorsAtCenterAntiReflexive+ , testLeftOutOfBoundsLengthApproximatePalindrome+ , testRightOutOfBoundsLengthApproximatePalindrome+ , testNoErrorLengthApproximatePalindrome+ , testErrorLengthApproximatePalindrome+ ]++{-+----------------------------------------------------------+ Begin tests for gappedApproximatePalindromesAroundCentres+----------------------------------------------------------+-}++-- | Test gappedApproximatePalindromesAroundCentres on some small DNA input+testGappedApproximatePalindromesAroundCentresDNA =+ TestCase $+ assertEqual+ "testGappedApproximatePalindromesAroundCentresDNA"+ [0, 2, 0, 2, 0]+ ( Q.gappedApproximatePalindromesAroundCentres+ True+ 0+ 0+ (U.fromList [A, T, C, G])+ )++-- | Test gappedApproximatePalindromesAroundCentres on some small text input+testGappedApproximatePalindromesAroundCentresText =+ TestCase $+ assertEqual+ "testGappedApproximatePalindromesAroundCentresText"+ [0, 1, 0, 1, 4, 1, 0, 3, 0, 1, 0]+ ( Q.gappedApproximatePalindromesAroundCentres+ False+ 0+ 0+ (U.fromList "abbab")+ )++{-+----------------------------------------------------------+ End tests for gappedApproximatePalindromesAroundCentres+----------------------------------------------------------+-}++{-+-------------------------------------------------+ Begin tests for lengthPalAtCenterReflexive+-------------------------------------------------+-}++-- | Test lengthPalAtCenterReflexive with even center index, no gap and no errors+testLengthPalAtCenterReflexiveEven =+ TestCase $+ assertEqual+ "testLengthPalAtCenterReflexiveEven"+ 2+ (Q.lengthPalAtCenterReflexive (U.fromList "yabadabadoo") 0 0 20)++-- | Test lengthPalAtCenterReflexive with even center index, a gap and no errors+testLengthGappedPalAtCenterReflexiveEven =+ TestCase $+ assertEqual+ "testLengthGappedPalAtCenterReflexiveEven"+ 6+ -- gap: |--|+ (Q.lengthPalAtCenterReflexive (U.fromList "yabaddabadoo") 4 0 14)++-- | Test lengthPalAtCenterReflexive with even center index, no gap and with errors+testLengthPalWithErrorsAtCenterReflexiveEven =+ TestCase $+ assertEqual+ "testLengthGappedPalAtCenterReflexiveEven"+ 6+ (Q.lengthPalAtCenterReflexive (U.fromList "yabaoabadoo") 0 2 14)++-- | Test lengthPalAtCenterReflexive with even center index, a gap and with errors+testLengthGappedPalWithErrorsAtCenterReflexiveEven =+ TestCase $+ assertEqual+ "testLengthGappedPalWithErrorsAtCenterReflexiveEven"+ 10+ -- gap: |--|+ (Q.lengthPalAtCenterReflexive (U.fromList "yabaddabadoo") 4 3 14)++-- | Test lengthPalAtCenterReflexive with odd center index, no gap and no errors+testLengthPalAtCenterReflexiveOdd =+ TestCase $+ assertEqual+ "testLengthPalAtCenterReflexiveEven"+ 7+ (Q.lengthPalAtCenterReflexive (U.fromList "yabadabadoo") 0 0 9)++-- | Test lengthPalAtCenterReflexive with odd center index, a gap and no errors+testLengthGappedPalAtCenterReflexiveOdd =+ TestCase $+ assertEqual+ "testLengthGappedPalAtCenterReflexiveOdd"+ 7+ -- gap: |-|+ (Q.lengthPalAtCenterReflexive (U.fromList "yabbagapabadoo") 3 0 13)++-- | Test lengthPalAtCenterReflexive with odd center index, no gap and with errors+testLengthPalWithErrorsAtCenterReflexiveOdd =+ TestCase $+ assertEqual+ "testLengthPalWithErrorsAtCenterReflexiveOdd"+ 9+ (Q.lengthPalAtCenterReflexive (U.fromList "yabadabadoo") 0 2 13)++-- | Test lengthPalAtCenterReflexive with odd center index, a gap and with errors+testLengthGappedPalWithErrorsAtCenterReflexiveOdd =+ TestCase $+ assertEqual+ "testLengthGappedPalWithErrorsAtCenterReflexiveOdd"+ 11+ -- gap: |-|+ (Q.lengthPalAtCenterReflexive (U.fromList "yabbagapabadoo") 3 2 13)++{-+-------------------------------------------------+ End tests for lengthPalAtCenterReflexive+-------------------------------------------------+-}++{-+---------------------------------------------+ Begin tests for getLeftRightReflexive reflexive+---------------------------------------------+-}++-- | Test getLeftRightReflexive with an even center index+testGetLeftRightReflexiveEven =+ TestCase $+ assertEqual+ "testGetLeftRightReflexiveEven"+ (0, 3)+ (Q.getLeftRightReflexive 2 4 7)++-- | Test getLeftRightReflexive with an odd center index+testGetLeftRightReflexiveOdd =+ TestCase $+ assertEqual+ "testGetLeftRightReflexiveOdd"+ (1, 5)+ (Q.getLeftRightReflexive 3 7 7)++{-+---------------------------------------------+ End tests for getLeftRightReflexive reflexive+---------------------------------------------+-}++{-+--------------------------------------------------------+ Begin tests for anti-reflexive length pal at center+--------------------------------------------------------+-}++{- | Test whether the observed length of the palindrome with (anti reflexive) DNA+is correct for palindrome without gaps and without errors.+-}+testLengthPalAtCenterAntiReflexive =+ TestCase $+ assertEqual+ "testLengthPalAtCenterAntiReflexive"+ 4+ ( Q.lengthPalAtCenterAntiReflexive+ (U.fromList [A, A, T {-center-}, A, T, G] :: U.Vector DNA)+ 0+ 0+ 3+ )++{- | Test whether the observed length of the palindrome with (anti reflexive) DNA+is correct for palindrome with a gap and without errors.+-}+testLengthGappedPalAtCenterAntiReflexive =+ TestCase $+ assertEqual+ "testLengthGappedPalAtCenterAntiReflexive"+ 8+ ( Q.lengthPalAtCenterAntiReflexive+ -- gap: |-------------------|+ (U.fromList [A, A, T, G, T, G {-center-}, A, A, C, A, A, T, C] :: U.Vector DNA)+ 4+ 0+ 6+ )++{- | Test whether the observed length of the palindrome with (anti reflexive) DNA+is correct for palindrome without a gap and with errors.+-}+testLengthPalWithErrorsAtCenterAntiReflexive =+ TestCase $+ assertEqual+ "testLengthPalWithErrorsAtCenterAntiReflexive"+ 10+ ( Q.lengthPalAtCenterAntiReflexive+ (U.fromList [A, A, A, T, G, T, G {-center-}, A, A, C, A, A, G, C] :: U.Vector DNA)+ 0+ 2+ 7+ )++{- | Test whether the observed length of the palindrome with (anti reflexive) DNA+is correct for palindrome with gap and with errors.+-}+testLengthGappedPalWithErrorsAtCenterAntiReflexive =+ TestCase $+ assertEqual+ "testLengthGappedPalWithErrorsAtCenterAntiReflexive"+ 8+ ( Q.lengthPalAtCenterAntiReflexive+ (U.fromList [A, A, A, T {-center-}, G, T, G, A, A, C, A, A, G, C] :: U.Vector DNA)+ 2+ 2+ 4+ )++{-+--------------------------------------------------------+ Begin tests for length approximate palindrome+--------------------------------------------------------+-}++-- | Tests the case where the a negative index is given to the function+testLeftOutOfBoundsLengthApproximatePalindrome =+ TestCase $+ assertEqual+ "testLeftOutOfBoundsLengthApproximatePalindrome"+ 2+ ( Q.lengthApproximatePalindrome+ (U.fromList "yay")+ 0+ (-1)+ 2+ )++-- | Tests the case where the a index is given which is larger then the vector size+testRightOutOfBoundsLengthApproximatePalindrome =+ TestCase $+ assertEqual+ "testRightOutOfBoundsLengthApproximatePalindrome"+ 2+ ( Q.lengthApproximatePalindrome+ (U.fromList "yay")+ 0+ 0+ 3+ )++-- | Tests the case where a palindrome is given without allowing any errors+testNoErrorLengthApproximatePalindrome =+ TestCase $+ assertEqual+ "testNoErrorLengthApproximatePalindrome"+ 9+ ( Q.lengthApproximatePalindrome+ (U.fromList "hallollah")+ 0+ 4+ 4+ )++-- | Tests the case where a palindrome is given with errors+testErrorLengthApproximatePalindrome =+ TestCase $+ assertEqual+ "testErrorLengthApproximatePalindrome"+ 9+ ( Q.lengthApproximatePalindrome+ (U.fromList "hellollah")+ 1+ 4+ 4+ )++{-+------------------------------------------------------+ End tests for length approximate palindrome+--------------------------------------------------------+-}
+ tests/UTTextPals.hs view
@@ -0,0 +1,52 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTTextPals (testListText) where++import Test.HUnit (Test (..), assertEqual, (~:), (~?=))++import Data.Algorithms.Palindromes.Finders (Algorithm)+import PalindromeMethods (longestTextPalindrome)++testListText :: Algorithm -> [Test]+testListText t =+ [ testTextPalindrome10 t+ , testTextPalindrome11 t+ , testTextPalindrome1 t+ , testTextPalindrome2 t+ , testTextPalindrome3 t+ , testTextPalindrome4 t+ , testTextPalindrome5 t+ , testTextPalindrome6 t+ , testTextPalindrome7 t+ , testTextPalindrome8 t+ , testTextPalindrome9 t+ ]++testTextPalindrome1 t = "testTextPalindrome1" ~: longestTextPalindrome t "abcdea,ba." ~?= "\"a,ba\""+testTextPalindrome2 t = "testTextPalindrome2" ~: longestTextPalindrome t "abcdea,ba" ~?= "\"a,ba\""+testTextPalindrome3 t = "testTextPalindrome3" ~: longestTextPalindrome t "abcde.a,ba" ~?= "\"a,ba\""+testTextPalindrome4 t = "testTextPalindrome4" ~: longestTextPalindrome t "abcde.a,baf" ~?= "\"a,ba\""+testTextPalindrome5 t = "testTextPalindrome5" ~: longestTextPalindrome t ".ab,acdef" ~?= "\"ab,a\""+testTextPalindrome6 t = "testTextPalindrome6" ~: longestTextPalindrome t "ab,acdef" ~?= "\"ab,a\""+testTextPalindrome7 t = "testTextPalindrome7" ~: longestTextPalindrome t "ab,a.cdef" ~?= "\"ab,a\""+testTextPalindrome8 t = "testTextPalindrome8" ~: longestTextPalindrome t "g.ab,a.cdef" ~?= "\"ab,a\""+testTextPalindrome9 t = "testTextPalindrome9" ~: longestTextPalindrome t "" ~?= "\"\""++testTextPalindrome10 t =+ TestCase $ do+ string <- readFile "./examples/palindromes/Damnitimmad.txt"+ assertEqual+ "testTextPalindrome10"+ ("\"" ++ init string ++ "\"")+ $ longestTextPalindrome t string++testTextPalindrome11 t =+ TestCase $ do+ string <- readFile "./examples/palindromes/pal17.txt"+ assertEqual+ "testTextPalindrome11"+ ("\"" ++ init string ++ "\"")+ $ longestTextPalindrome t string
+ tests/UTWordPals.hs view
@@ -0,0 +1,108 @@+{- This program has been developed by students from the bachelor Computer Science at Utrecht+University within the Software Project course.++© Copyright Utrecht University (Department of Information and Computing Sciences) and Johan Jeuring -}++module UTWordPals (testListWordPalindromes) where++import Test.HUnit (Test (..), (~:), (~?=))++import PalindromeMethods (longestWordPalindrome)++testListWordPalindromes t =+ [ testWord1 t+ , testWord2 t+ , testWord3 t+ , testWord4 t+ , testWord5 t+ , testWord6 t+ , testWord7 t+ , testWord8 t+ , testWord9 t+ , testWord10 t+ , testWord11 t+ , testWord12 t+ ]++testWord1 t =+ "testWord1"+ ~: longestWordPalindrome+ t+ "abc def def abc"+ ~?= "\"abc def def abc\""++testWord2 t =+ "testWord2"+ ~: longestWordPalindrome+ t+ "abc abc def abcdefghi"+ ~?= "\"abc abc\""++testWord3 t =+ "testWord3"+ ~: longestWordPalindrome+ t+ "AbC aBb a bb Abc aBC"+ ~?= "\"Abc aBC\""++testWord4 t =+ "testWord4"+ ~: longestWordPalindrome+ t+ "abc def abc"+ ~?= "\"abc def abc\""++testWord5 t =+ "testWord5"+ ~: longestWordPalindrome+ t+ "abc., abc"+ ~?= "\"abc., abc\""++testWord6 t =+ "testWord6"+ ~: longestWordPalindrome+ t+ "abc.d abcd .. . a"+ ~?= "\"abc.d abcd\""++testWord7 t =+ "testWord7"+ ~: longestWordPalindrome+ t+ "a a"+ ~?= "\"a a\""++testWord8 t =+ "testWord8"+ ~: longestWordPalindrome+ t+ ""+ ~?= "\"\""+testWord9 t =+ "testWord9"+ ~: longestWordPalindrome+ t+ " leading spaces"+ ~?= "\"leading\"\n\"spaces\""++testWord10 t =+ "testWord10"+ ~: longestWordPalindrome+ t+ "/.;/;,';,.,,leading garbage"+ ~?= "\"leading\"\n\"garbage\""++testWord11 t =+ "testWord11"+ ~: longestWordPalindrome+ t+ "several; different,.; characters .char-acter[s"+ ~?= "\"characters .char-acter[s\""++testWord12 t =+ "testWord12"+ ~: longestWordPalindrome+ t+ "."+ ~?= "\"\""