slynx 0.7.1.0 → 0.7.2.0
raw patch · 6 files changed
+102/−75 lines, 6 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ SLynx.Simulate.Options: GlobalNormalization :: MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: LocalNormalization :: MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: [argsMixtureModelGlobalNormalization] :: SimulateArguments -> MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: data MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: instance Data.Aeson.Types.FromJSON.FromJSON SLynx.Simulate.Options.MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: instance Data.Aeson.Types.ToJSON.ToJSON SLynx.Simulate.Options.MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: instance GHC.Classes.Eq SLynx.Simulate.Options.MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: instance GHC.Generics.Generic SLynx.Simulate.Options.MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: instance GHC.Read.Read SLynx.Simulate.Options.MixtureModelGlobalNormalization
+ SLynx.Simulate.Options: instance GHC.Show.Show SLynx.Simulate.Options.MixtureModelGlobalNormalization
- SLynx.Simulate.Options: SimulateArguments :: FilePath -> Maybe String -> Maybe String -> Maybe FilePath -> Maybe [FilePath] -> Maybe [Double] -> Maybe GammaRateHeterogeneityParams -> Int -> SeedOpt -> SimulateArguments
+ SLynx.Simulate.Options: SimulateArguments :: FilePath -> Maybe String -> Maybe String -> MixtureModelGlobalNormalization -> Maybe FilePath -> Maybe [FilePath] -> Maybe [Double] -> Maybe GammaRateHeterogeneityParams -> Int -> SeedOpt -> SimulateArguments
- SLynx.Simulate.PhyloModel: getPhyloModel :: Maybe String -> Maybe String -> Maybe [Weight] -> Maybe [EDMComponent] -> Either String PhyloModel
+ SLynx.Simulate.PhyloModel: getPhyloModel :: Maybe String -> Maybe String -> MixtureModelGlobalNormalization -> Maybe [Weight] -> Maybe [EDMComponent] -> Either String PhyloModel
Files
- ChangeLog.md +5/−0
- README.md +4/−4
- slynx.cabal +1/−1
- src/SLynx/Simulate/Options.hs +20/−0
- src/SLynx/Simulate/PhyloModel.hs +62/−62
- src/SLynx/Simulate/Simulate.hs +10/−8
ChangeLog.md view
@@ -5,6 +5,11 @@ ## Unreleased changes +## Version 0.7.2.0++- `slynx`: Allow global normalization of mixture models.++ ## Version 0.7.1.0 - Be less strict with quoted identifiers/names in phylogenetic trees.
README.md view
@@ -2,7 +2,7 @@ # The ELynx Suite -Version: 0.7.0.0.+Version: 0.7.2.0. Reproducible evolution made easy. <p align="center"><img src="https://travis-ci.org/dschrempf/elynx.svg?branch=master"/></p>@@ -73,13 +73,13 @@ # OR: stack exec slynx -- --help # OR: slynx --help - Up to date- ELynx Suite version 0.7.0.0.+ ELynx Suite version 0.7.2.0. Developed by Dominik Schrempf.- Compiled on July 10, 2022, at 08:48 am, UTC.+ Compiled on May 3, 2023, at 13:18 pm, UTC. Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] [-f|--force] [--no-elynx-file] COMMAND+ Analyze, and simulate multi sequence alignments. Available options:
slynx.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: slynx-version: 0.7.1.0+version: 0.7.2.0 synopsis: Handle molecular sequences description: Examine, modify, and simulate molecular sequences in a reproducible way. Please see the README on GitHub at <https://github.com/dschrempf/elynx>.
src/SLynx/Simulate/Options.hs view
@@ -34,6 +34,7 @@ -- -o,--output-file NAME Specify output file NAME module SLynx.Simulate.Options ( GammaRateHeterogeneityParams,+ MixtureModelGlobalNormalization (..), SimulateArguments (..), simulateArguments, simulateFooter,@@ -53,11 +54,19 @@ -- | Number of gamma rate categories and alpha parameter. type GammaRateHeterogeneityParams = (Int, Double) +data MixtureModelGlobalNormalization = GlobalNormalization | LocalNormalization+ deriving (Show, Read, Eq, Generic)++instance FromJSON MixtureModelGlobalNormalization++instance ToJSON MixtureModelGlobalNormalization+ -- | Arguments needed to simulate sequences. data SimulateArguments = SimulateArguments { argsTreeFile :: FilePath, argsSubstitutionModelString :: Maybe String, argsMixtureModelString :: Maybe String,+ argsMixtureModelGlobalNormalization :: MixtureModelGlobalNormalization, argsEDMFile :: Maybe FilePath, argsSiteprofilesFiles :: Maybe [FilePath], argsMixtureWeights :: Maybe [Double],@@ -90,6 +99,7 @@ <$> treeFileOpt <*> phyloSubstitutionModelOpt <*> phyloMixtureModelOpt+ <*> globalNormalizationFlag <*> maybeEDMFileOpt <*> maybeSiteprofilesFilesOpt <*> maybeMixtureWeights@@ -126,6 +136,16 @@ <> help "Set the phylogenetic mixture model; available models are shown below (mutually exclusive with -s option)" )++globalNormalizationFlag :: Parser MixtureModelGlobalNormalization+globalNormalizationFlag =+ flag+ LocalNormalization+ GlobalNormalization+ ( long "global-normalization"+ <> short 'n'+ <> help "Normalize mixture model globally (one normalization constant for all components)"+ ) maybeEDMFileOpt :: Parser (Maybe FilePath) maybeEDMFileOpt =
src/SLynx/Simulate/PhyloModel.hs view
@@ -35,11 +35,8 @@ import qualified ELynx.MarkovProcess.SubstitutionModel as S import ELynx.Tools.Equality import ELynx.Tools.InputOutput-import Numeric.LinearAlgebra- ( norm_1,- size,- vector,- )+import Numeric.LinearAlgebra (norm_1, size, vector)+import SLynx.Simulate.Options (MixtureModelGlobalNormalization (..)) nNuc :: Int -- nNuc = length (alphabet :: [Nucleotide])@@ -109,59 +106,61 @@ -- This is the main function that connects the model string, the parameters and -- the stationary distribution. It should check that the model is valid. assembleSubstitutionModel ::+ S.Normalize -> String -> Maybe S.Params -> Maybe StationaryDistribution -> Either String S.SubstitutionModel -- DNA models.-assembleSubstitutionModel "JC" Nothing Nothing = Right jc-assembleSubstitutionModel "F81" Nothing (Just d) =- Right $ assertLength d nNuc $ f81 d-assembleSubstitutionModel "HKY" (Just [k]) (Just d) =- Right $ assertLength d nNuc $ hky k d-assembleSubstitutionModel "GTR4" (Just es) (Just d) =- Right $ assertLength d nNuc $ gtr4 es d+assembleSubstitutionModel nz "JC" Nothing Nothing = Right $ jc nz+assembleSubstitutionModel nz "F81" Nothing (Just d) =+ Right $ assertLength d nNuc $ f81 nz d+assembleSubstitutionModel nz "HKY" (Just [k]) (Just d) =+ Right $ assertLength d nNuc $ hky nz k d+assembleSubstitutionModel nz "GTR4" (Just es) (Just d) =+ Right $ assertLength d nNuc $ gtr4 nz es d -- Protein models.-assembleSubstitutionModel "Poisson" Nothing Nothing = Right poisson-assembleSubstitutionModel "Poisson-Custom" Nothing (Just d) =- Right $ assertLength d nAA $ poissonCustom Nothing d-assembleSubstitutionModel "LG" Nothing Nothing = Right lg-assembleSubstitutionModel "LG-Custom" Nothing (Just d) =- Right $ assertLength d nAA $ lgCustom Nothing d-assembleSubstitutionModel "WAG" Nothing Nothing = Right wag-assembleSubstitutionModel "WAG-Custom" Nothing (Just d) =- Right $ assertLength d nAA $ wagCustom Nothing d-assembleSubstitutionModel "GTR20" (Just es) (Just d) =- Right $ assertLength d nAA $ gtr20 es d+assembleSubstitutionModel nz "Poisson" Nothing Nothing = Right $ poisson nz+assembleSubstitutionModel nz "Poisson-Custom" Nothing (Just d) =+ Right $ assertLength d nAA $ poissonCustom Nothing nz d+assembleSubstitutionModel nz "LG" Nothing Nothing = Right $ lg nz+assembleSubstitutionModel nz "LG-Custom" Nothing (Just d) =+ Right $ assertLength d nAA $ lgCustom Nothing nz d+assembleSubstitutionModel nz "WAG" Nothing Nothing = Right $ wag nz+assembleSubstitutionModel nz "WAG-Custom" Nothing (Just d) =+ Right $ assertLength d nAA $ wagCustom Nothing nz d+assembleSubstitutionModel nz "GTR20" (Just es) (Just d) =+ Right $ assertLength d nAA $ gtr20 nz es d -- Ohterwisse, we cannot assemble the model.-assembleSubstitutionModel n mps mf =+assembleSubstitutionModel nz n mps mf = Left $ unlines [ "Cannot assemble substitution model.",+ "Normalize: " ++ show nz, "Name: " ++ show n, "Parameters: " ++ show mps, "Stationary distribution: " ++ show mf ] -parseSubstitutionModel :: Parser S.SubstitutionModel-parseSubstitutionModel = do+parseSubstitutionModel :: S.Normalize -> Parser S.SubstitutionModel+parseSubstitutionModel nz = do n <- name mps <- optional params mf <- optional stationaryDistribution- let esm = assembleSubstitutionModel n mps mf+ let esm = assembleSubstitutionModel nz n mps mf case esm of Left err -> fail err Right sm -> return sm -edmModel :: [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel-edmModel cs mws = do+edmModel :: MixtureModelGlobalNormalization -> [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel+edmModel nz cs mws = do _ <- string "EDM" _ <- char mmStart n <- name mps <- optional params _ <- char mmEnd when (null cs) $ error "edmModel: no EDM components given."- let sms = map (\c -> assembleSubstitutionModel n mps (Just $ snd c)) cs+ let sms = map (\c -> assembleSubstitutionModel subNz n mps (Just $ snd c)) cs edmName = "EDM" ++ show (length cs) ws = fromMaybe (map fst cs) mws errs = [e | (Left e) <- sms]@@ -171,30 +170,36 @@ then fail $ head errs else return $- M.fromSubstitutionModels edmName (V.fromList ws) (V.fromList $ rights sms)+ M.fromSubstitutionModels edmName mmNz (V.fromList ws) (V.fromList $ rights sms)+ where+ (subNz, mmNz) = case nz of+ GlobalNormalization -> (S.DoNotNormalize, S.DoNormalize)+ LocalNormalization -> (S.DoNormalize, S.DoNotNormalize) -cxxModel :: Maybe [M.Weight] -> Parser M.MixtureModel-cxxModel mws = do+cxxModel :: MixtureModelGlobalNormalization -> Maybe [M.Weight] -> Parser M.MixtureModel+cxxModel LocalNormalization _ = fail "Local normalization impossible with CXX models."+cxxModel _ mws = do _ <- char 'C' n <- decimal :: Parser Int return $ cxx n mws -standardMixtureModel :: [M.Weight] -> Parser M.MixtureModel-standardMixtureModel ws = do+standardMixtureModel :: MixtureModelGlobalNormalization -> [M.Weight] -> Parser M.MixtureModel+standardMixtureModel nz ws = do _ <- string "MIXTURE" _ <- char mmStart- sms <- parseSubstitutionModel `sepBy1` char separator+ sms <- parseSubstitutionModel subNz `sepBy1` char separator _ <- char mmEnd -- XXX: The use of `Data.List.NonEmpty.fromList` leads to uninformative error messages.- return $ M.fromSubstitutionModels "MIXTURE" (V.fromList ws) (V.fromList sms)+ return $ M.fromSubstitutionModels "MIXTURE" mmNz (V.fromList ws) (V.fromList sms)+ where+ (subNz, mmNz) = case nz of+ GlobalNormalization -> (S.DoNotNormalize, S.DoNormalize)+ LocalNormalization -> (S.DoNormalize, S.DoNotNormalize) -mixtureModel ::- Maybe [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel-mixtureModel Nothing Nothing =- try (cxxModel Nothing) <|> fail "No weights provided."-mixtureModel Nothing mws@(Just ws) =- try (cxxModel mws) <|> standardMixtureModel ws-mixtureModel (Just cs) mws = edmModel cs mws+mixtureModel :: MixtureModelGlobalNormalization -> Maybe [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel+mixtureModel nz Nothing Nothing = try (cxxModel nz Nothing) <|> fail "No weights provided."+mixtureModel nz Nothing mws@(Just ws) = try (cxxModel nz mws) <|> standardMixtureModel nz ws+mixtureModel nz (Just cs) mws = edmModel nz cs mws -- | Parse the phylogenetic model string. The argument list is somewhat long, -- but models can have many parameters and we have to check for redundant@@ -206,26 +211,21 @@ getPhyloModel :: Maybe String -> Maybe String ->+ MixtureModelGlobalNormalization -> Maybe [M.Weight] -> Maybe [EDMComponent] -> Either String P.PhyloModel-getPhyloModel Nothing Nothing _ _ = Left "No model was given. See help."-getPhyloModel (Just _) (Just _) _ _ =+getPhyloModel Nothing Nothing _ _ _ = Left "No model was given. See help."+getPhyloModel (Just _) (Just _) _ _ _ = Left "Both, substitution and mixture model string given; use only one."-getPhyloModel (Just s) Nothing Nothing Nothing =- Right $- P.SubstitutionModel $- parseStringWith- parseSubstitutionModel- s-getPhyloModel (Just _) Nothing (Just _) _ =+getPhyloModel (Just s) Nothing nz Nothing Nothing+ | nz == GlobalNormalization = Left "Global normalization not possible for substitution models."+ | otherwise = Right $ P.SubstitutionModel $ parseStringWith (parseSubstitutionModel S.DoNormalize) s+getPhyloModel (Just _) Nothing _ (Just _) _ = Left "Weights given; but cannot be used with substitution model."-getPhyloModel (Just _) Nothing _ (Just _) =- Left- "Empirical distribution mixture model components given; but cannot be used with substitution model."-getPhyloModel Nothing (Just m) mws mcs =- Right $- P.MixtureModel $- parseStringWith- (mixtureModel mcs mws)- m+getPhyloModel (Just _) Nothing _ _ (Just _) =+ let msg1 = "Empirical distribution mixture model components given;"+ msg2 = " but cannot be used with substitution model."+ in Left $ msg1 <> msg2+getPhyloModel Nothing (Just m) nz mws mcs =+ Right $ P.MixtureModel $ parseStringWith (mixtureModel nz mcs mws) m
src/SLynx/Simulate/Simulate.hs view
@@ -211,9 +211,10 @@ : summarizeSM (MM.substModel c) -- Summarize a mixture model; lines to be printed to screen or log.-summarizeMM :: MM.MixtureModel -> [BL.ByteString]-summarizeMM m =+summarizeMM :: MixtureModelGlobalNormalization -> MM.MixtureModel -> [BL.ByteString]+summarizeMM nz m = [ BL.pack $ "Mixture model: " ++ MM.name m ++ ".",+ BL.pack $ "Mixture model normalization: " ++ show nz ++ ".", BL.pack $ "Number of components: " ++ show n ++ "." ] ++ detail@@ -229,9 +230,9 @@ else [] -- Summarize a phylogenetic model; lines to be printed to screen or log.-summarizePM :: MP.PhyloModel -> [BL.ByteString]-summarizePM (MP.MixtureModel mm) = summarizeMM mm-summarizePM (MP.SubstitutionModel sm) = summarizeSM sm+summarizePM :: MixtureModelGlobalNormalization -> MP.PhyloModel -> [BL.ByteString]+summarizePM nz (MP.MixtureModel mm) = summarizeMM nz mm+summarizePM _ (MP.SubstitutionModel sm) = summarizeSM sm -- | Simulate sequences. simulateCmd :: ELynx SimulateArguments ()@@ -278,17 +279,18 @@ let ms = argsSubstitutionModelString l mm = argsMixtureModelString l mws = argsMixtureWeights l- eitherPhyloModel' = getPhyloModel ms mm mws edmCsOrSiteprofiles+ nz = argsMixtureModelGlobalNormalization l+ eitherPhyloModel' = getPhyloModel ms mm nz mws edmCsOrSiteprofiles phyloModel' <- case eitherPhyloModel' of Left err -> lift $ error err Right pm -> return pm let maybeGammaParams = argsGammaParams l phyloModel <- case maybeGammaParams of Nothing -> do- logInfoB $ BL.unlines $ summarizePM phyloModel'+ logInfoB $ BL.unlines $ summarizePM nz phyloModel' return phyloModel' Just (n, alpha) -> do- logInfoB $ BL.intercalate "\n" $ summarizePM phyloModel'+ logInfoB $ BL.intercalate "\n" $ summarizePM nz phyloModel' logInfoS "" logInfoB $ BL.intercalate "\n" $ summarizeGammaRateHeterogeneity n alpha return $ expand n alpha phyloModel'