tlynx-0.2.1: src/TLynx/Distance/Options.hs
{-# LANGUAGE DeriveGeneric #-}
{- |
Module : TLynx.Distance.Options
Description : Options of tree-dist
Copyright : (c) Dominik Schrempf 2020
License : GPL-3.0-or-later
Maintainer : dominik.schrempf@gmail.com
Stability : unstable
Portability : portable
Creation date: Thu Aug 29 13:02:22 2019.
-}
module TLynx.Distance.Options
( DistanceArguments(..)
, DistanceMeasure(..)
, distanceArguments
, distanceFooter
)
where
import Data.Void
import Data.Scientific ( toRealFloat )
import Options.Applicative
import Text.Megaparsec ( Parsec
, eof
, try
)
import Text.Megaparsec.Char ( char
, string
)
import Text.Megaparsec.Char.Lexer ( scientific )
import Text.Printf
import ELynx.Tools
import TLynx.Parsers
-- | Supported distance measures.
data DistanceMeasure =
Symmetric -- ^ Symmetric distance.
| IncompatibleSplit Double -- ^ Incompatible split distance; collapse nodes
-- with branch support below given value.
| BranchScore -- ^ Branch score distance.
deriving (Eq, Generic)
instance FromJSON DistanceMeasure
instance ToJSON DistanceMeasure
instance Show DistanceMeasure where
show Symmetric = "Symmetric"
show (IncompatibleSplit c) = "Incompatible Split (" ++ printf "%.2f" c ++ ")"
show BranchScore = "Branch Score"
-- | Arguments needed to compute distance measures.
data DistanceArguments = DistanceArguments
{ argsDistance :: DistanceMeasure
, argsNormalize :: Bool
, argsIntersect :: Bool
, argsSummaryStatistics :: Bool
, argsMasterTreeFile :: Maybe FilePath
, argsNewickFormat :: NewickFormat
, argsInFiles :: [FilePath]
}
deriving (Eq, Show, Generic)
instance Reproducible DistanceArguments where
inFiles a = case argsMasterTreeFile a of
Nothing -> argsInFiles a
Just f -> f : argsInFiles a
outSuffixes _ = [".out"]
getSeed _ = Nothing
setSeed = const
parser = distanceArguments
cmdName = "distance"
cmdDsc = ["Compute distances between many phylogenetic trees."]
cmdFtr = distanceFooter
instance FromJSON DistanceArguments
instance ToJSON DistanceArguments
-- | COmmand line parser.
distanceArguments :: Parser DistanceArguments
distanceArguments =
DistanceArguments
<$> distanceOpt
<*> normalizeSwitch
<*> intersectSwitch
<*> summaryStatisticsSwitch
<*> masterTreeFile
<*> newickFormat
<*> many inFilesArg
masterTreeFile :: Parser (Maybe FilePath)
masterTreeFile =
optional
$ strOption
$ long "master-tree-file"
<> short 'm'
<> metavar "MASTER-TREE-File"
<> help "Compare all trees to the tree in the master tree file."
inFilesArg :: Parser FilePath
inFilesArg =
strArgument
$ metavar "INPUT-FILES"
<> help
"Read tree(s) from INPUT-FILES; if more files are given, one tree is expected per file"
symmetric :: Parsec Void String DistanceMeasure
symmetric = do
_ <- string "symmetric"
_ <- eof
pure Symmetric
incompatibleSplit :: Parsec Void String DistanceMeasure
incompatibleSplit = do
_ <- string "incompatible-split"
_ <- char '['
f <- toRealFloat <$> scientific
_ <- char ']'
_ <- eof
if (0 <= f) && (f <= 1)
then pure $ IncompatibleSplit f
else error "Branch support has to be in [0, 1]."
branchScore :: Parsec Void String DistanceMeasure
branchScore = do
_ <- string "branch-score"
_ <- eof
pure BranchScore
distanceParser :: Parsec Void String DistanceMeasure
distanceParser =
-- Try first the normalized one, since the normal branch score
-- parser also succeeds in this case.
try symmetric <|> try incompatibleSplit <|> branchScore
distanceOpt :: Parser DistanceMeasure
distanceOpt =
option (megaReadM distanceParser)
$ long "distance"
<> short 'd'
<> metavar "MEASURE"
<> help
"Type of distance to calculate (available distance measures are listed below)"
summaryStatisticsSwitch :: Parser Bool
summaryStatisticsSwitch =
switch $ long "summary-statistics" <> short 's' <> help
"Report summary statistics only"
normalizeSwitch :: Parser Bool
normalizeSwitch =
switch
$ long "normalize"
<> short 'n'
<> help
"Normalize trees before distance calculation; only affect distances depending on branch lengths"
intersectSwitch :: Parser Bool
intersectSwitch =
switch
$ long "intersect"
<> short 't'
<> help
"Compare intersections; i.e., before comparison, drop leaves that are not present in the other tree"
-- | Information about provided distance types.
distanceFooter :: [String]
distanceFooter =
[ "Distance measures:"
, " symmetric Symmetric distance (Robinson-Foulds distance)."
, " incompatible-split[VAL] Incompatible split distance. Collapse branches"
, " with support less than VAL before distance calculation;"
, " in this way, only well supported difference contribute"
, " to the distance measure."
, " branch-score Branch score distance."
]