slynx 0.5.0.1 → 0.5.0.2
raw patch · 5 files changed
+133/−121 lines, 5 filesdep −asyncdep ~attoparsecdep ~bytestringdep ~containersPVP ok
version bump matches the API change (PVP)
Dependencies removed: async
Dependency ranges changed: attoparsec, bytestring, containers, elynx-markov, elynx-seq, elynx-tools, elynx-tree, hmatrix, monad-logger, mwc-random, optparse-applicative, statistics, text, transformers, vector
API changes (from Hackage documentation)
Files
- ChangeLog.md +4/−0
- README.md +29/−29
- slynx.cabal +16/−17
- src/SLynx/Simulate/PhyloModel.hs +3/−3
- src/SLynx/Simulate/Simulate.hs +81/−72
ChangeLog.md view
@@ -4,6 +4,10 @@ ## Unreleased changes ++## Version 0.5.0.2++- Speed up mixture model simulation. - Improve rooting functions. - Improve `Topology` data type (but still a lot to do). - Various additions to the documentation.
README.md view
@@ -2,7 +2,7 @@ # The ELynx Suite -Version: 0.5.0.1.+Version: 0.5.0.2. Reproducible evolution made easy. <p align="center"><img src="https://travis-ci.org/dschrempf/elynx.svg?branch=master"/></p>@@ -73,9 +73,9 @@ slynx --help | head -n -16 - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] [-f|--force] [--no-elynx-file] COMMAND@@ -90,7 +90,7 @@ Specify base name of output file -f,--force Ignore previous analysis and overwrite existing output files.- --no-elynx-file Do not write files for needed for reproducibility.+ --no-elynx-file Do not write data required to reproduce an analysis. Available commands: concatenate Concatenate sequences found in input files.@@ -120,9 +120,9 @@ slynx concatenate --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: slynx concatenate (-a|--alphabet NAME) INPUT-FILE Concatenate sequences found in input files.@@ -141,9 +141,9 @@ slynx examine --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: slynx examine (-a|--alphabet NAME) INPUT-FILE [--per-site] Examine sequences. If data is a multi sequence alignment, additionally analyze columns.@@ -163,9 +163,9 @@ slynx filter-rows --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: slynx filter-rows (-a|--alphabet NAME) INPUT-FILE [--longer-than LENGTH] [--shorter-than LENGTH] [--standard-characters]@@ -186,9 +186,9 @@ slynx filter-columns --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: slynx filter-columns (-a|--alphabet NAME) INPUT-FILE [--standard-chars DOUBLE]@@ -210,9 +210,9 @@ slynx simulate --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: slynx simulate (-t|--tree-file Name) [-s|--substitution-model MODEL] [-m|--mixture-model MODEL] [-e|--edm-file NAME] @@ -289,9 +289,9 @@ slynx sub-sample --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: slynx sub-sample (-a|--alphabet NAME) INPUT-FILE (-n|--number-of-sites INT)@@ -319,9 +319,9 @@ slynx translate --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: slynx translate (-a|--alphabet NAME) INPUT-FILE (-r|--reading-frame INT) (-u|--universal-code CODE)@@ -344,9 +344,9 @@ tlynx --help | head -n -16 - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: tlynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] [-f|--force] [--no-elynx-file] COMMAND@@ -361,7 +361,7 @@ Specify base name of output file -f,--force Ignore previous analysis and overwrite existing output files.- --no-elynx-file Do not write files for needed for reproducibility.+ --no-elynx-file Do not write data required to reproduce an analysis. Available commands: compare Compare two phylogenetic trees (compute distances and branch-wise differences).@@ -384,9 +384,9 @@ tlynx compare --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: tlynx compare [-n|--normalize] [-b|--bipartitions] [-t|--intersect] [-f|--newick-format FORMAT] NAMES@@ -413,9 +413,9 @@ tlynx examine --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: tlynx examine INPUT-FILE [-f|--newick-format FORMAT] Compute summary statistics of phylogenetic trees.@@ -437,9 +437,9 @@ tlynx simulate --help - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: tlynx simulate (-t|--nTrees INT) (-n|--nLeaves INT) PROCESS [-u|--sub-sample DOUBLE] [-s|--summary-statistics] @@ -474,9 +474,9 @@ elynx --help | head -n -16 - ELynx Suite version 0.5.0.1.+ ELynx Suite version 0.5.0.2. Developed by Dominik Schrempf.- Compiled on December 18, 2020, at 10:14 am, UTC.+ Compiled on February 19, 2021, at 13:42 pm, UTC. Usage: elynx COMMAND Validate and redo past ELynx analyses
slynx.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: slynx-version: 0.5.0.1+version: 0.5.0.2 license: GPL-3.0-or-later license-file: LICENSE copyright: Dominik Schrempf (2020)@@ -47,23 +47,22 @@ default-language: Haskell2010 ghc-options: -Wall -Wunused-packages build-depends:- async >=2.2.2 && <2.3,- attoparsec >=0.13.2.4 && <0.14,+ attoparsec >=0.13.2.5, base >=4.7 && <5,- bytestring >=0.10.10.0 && <0.11,- containers >=0.6.2.1 && <0.7,- elynx-markov >=0.5.0.1 && <0.6,- elynx-seq >=0.5.0.1 && <0.6,- elynx-tools >=0.5.0.1 && <0.6,- elynx-tree >=0.5.0.1 && <0.6,- hmatrix >=0.20.0.0 && <0.21,- monad-logger >=0.3.35 && <0.4,- mwc-random >=0.14.0.0 && <0.15,- optparse-applicative >=0.15.1.0 && <0.16,- statistics >=0.15.2.0 && <0.16,- text >=1.2.3.2 && <1.3,- transformers >=0.5.6.2 && <0.6,- vector >=0.12.1.2 && <0.13+ bytestring >=0.10.12.0,+ containers >=0.6.2.1,+ elynx-markov >=0.5.0.2,+ elynx-seq >=0.5.0.2,+ elynx-tools >=0.5.0.2,+ elynx-tree >=0.5.0.2,+ hmatrix >=0.20.1,+ monad-logger >=0.3.36,+ mwc-random >=0.14.0.0,+ optparse-applicative >=0.15.1.0,+ statistics >=0.15.2.0,+ text >=1.2.4.1,+ transformers >=0.5.6.2,+ vector >=0.12.2.0 executable slynx main-is: Main.hs
src/SLynx/Simulate/PhyloModel.hs view
@@ -21,8 +21,8 @@ import Data.Attoparsec.ByteString.Char8 import qualified Data.ByteString.Char8 as BS import Data.Either (rights)-import Data.List.NonEmpty (fromList) import Data.Maybe+import qualified Data.Vector as V import ELynx.Data.MarkovProcess.AminoAcid import ELynx.Data.MarkovProcess.CXXModels import qualified ELynx.Data.MarkovProcess.MixtureModel as M@@ -170,7 +170,7 @@ then fail $ head errs else return $- M.fromSubstitutionModels edmName (fromList ws) (fromList $ rights sms)+ M.fromSubstitutionModels edmName (V.fromList ws) (V.fromList $ rights sms) cxxModel :: Maybe [M.Weight] -> Parser M.MixtureModel cxxModel mws = do@@ -185,7 +185,7 @@ sms <- parseSubstitutionModel `sepBy1` char separator _ <- char mmEnd -- XXX: The use of `Data.List.NonEmpty.fromList` leads to uninformative error messages.- return $ M.fromSubstitutionModels "MIXTURE" (fromList ws) (fromList sms)+ return $ M.fromSubstitutionModels "MIXTURE" (V.fromList ws) (V.fromList sms) mixtureModel :: Maybe [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel
src/SLynx/Simulate/Simulate.hs view
@@ -18,8 +18,6 @@ where import Control.Applicative ((<|>))-import Control.Concurrent-import Control.Concurrent.Async import Control.Monad import Control.Monad.IO.Class import Control.Monad.Logger@@ -27,19 +25,22 @@ import Control.Monad.Trans.Reader (ask) import qualified Data.ByteString.Builder as BB import qualified Data.ByteString.Lazy.Char8 as BL-import Data.List.NonEmpty (toList)+import Data.List import Data.Maybe import qualified Data.Set as Set import qualified Data.Text as T import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.Encoding as LT-import qualified Data.Vector.Unboxed as V+import qualified Data.Vector as V+import qualified Data.Vector.Storable as VS+import qualified Data.Vector.Unboxed as U import ELynx.Data.Alphabet.Alphabet as A+import qualified ELynx.Data.MarkovProcess.AminoAcid as MA import ELynx.Data.MarkovProcess.GammaRateHeterogeneity-import qualified ELynx.Data.MarkovProcess.MixtureModel as M-import qualified ELynx.Data.MarkovProcess.PhyloModel as P-import qualified ELynx.Data.MarkovProcess.SubstitutionModel as SM-import qualified ELynx.Data.Sequence.Alignment as A+import qualified ELynx.Data.MarkovProcess.MixtureModel as MM+import qualified ELynx.Data.MarkovProcess.PhyloModel as MP+import qualified ELynx.Data.MarkovProcess.RateMatrix as MR+import qualified ELynx.Data.MarkovProcess.SubstitutionModel as MS import qualified ELynx.Data.Sequence.Sequence as Seq hiding ( name, )@@ -49,60 +50,68 @@ import ELynx.Simulate.MarkovProcessAlongTree import ELynx.Tools import ELynx.Tree-import Numeric.LinearAlgebra hiding- ( toList,- (<>),- ) import SLynx.Simulate.Options import SLynx.Simulate.PhyloModel import System.Random.MWC import Text.Printf +getDistLine :: Int -> MR.StationaryDistribution -> BB.Builder+getDistLine i d =+ BB.intDec i+ <> BB.char8 ' '+ <> s+ where+ s = mconcat $ intersperse (BB.char8 ' ') $ map BB.doubleDec $ VS.toList d++writeSiteDists :: [Int] -> V.Vector MR.StationaryDistribution -> ELynx SimulateArguments ()+-- writeSiteDists is ds = out "site distributions of distribution mixture model" output ".sitedists"+writeSiteDists componentIs ds = do+ mbn <- outFileBaseName . global <$> ask+ case mbn of+ Nothing -> return ()+ Just bn -> liftIO $ BL.writeFile (bn <> ".sitedists") output+ where+ dsPaml = V.map MA.alphaToPamlVec ds+ lns = [getDistLine i d | (i, c) <- zip [1 ..] componentIs, let d = dsPaml V.! c]+ output = BB.toLazyByteString $ mconcat $ intersperse (BB.char8 '\n') lns+ -- Simulate a 'Alignment' for a given phylogenetic model, -- phylogenetic tree, and alignment length. simulateAlignment :: (HasLength e, HasName a) =>- P.PhyloModel ->+ MP.PhyloModel -> Tree e a -> Int -> GenIO ->- IO A.Alignment+ ELynx SimulateArguments () simulateAlignment pm t' n g = do let t = fromLength . getLen <$> toTreeBranchLabels t'- c <- getNumCapabilities- gs <- splitGen c g- let chunks = getChunks c n- leafStatesS <- case pm of- -- TODO @performace: This parallelization is not very intelligent, because- -- the matrix exponentiation is done in all threads. So ten threads will- -- exponentiate the same matrix ten times.- P.SubstitutionModel sm ->- mapConcurrently- (\(num, gen) -> simulateAndFlatten num d e t gen)- (zip chunks gs)+ leafStates <- case pm of+ MP.SubstitutionModel sm -> liftIO $ simulateAndFlattenPar n d e t g where- d = SM.stationaryDistribution sm- e = SM.exchangeabilityMatrix sm- -- P.MixtureModel mm -> mapConcurrently- -- (\(num, gen) -> simulateAndFlattenNSitesAlongTreeMixtureModel num ws ds es t gen) (zip chunks gs)- P.MixtureModel mm -> simulateAndFlattenMixtureModelPar n ws ds es t g+ d = MS.stationaryDistribution sm+ e = MS.exchangeabilityMatrix sm+ MP.MixtureModel mm -> do+ (cs, ss) <- liftIO $ simulateAndFlattenMixtureModelPar n ws ds es t g+ -- TODO: Writing site distributions only makes sense for EDM models.+ -- Remove this if not needed or improve to be helpful in general.+ writeSiteDists cs ds+ return ss where- ws = vector . toList $ M.getWeights mm- ds = map SM.stationaryDistribution $ toList $ M.getSubstitutionModels mm- es = map SM.exchangeabilityMatrix $ toList $ M.getSubstitutionModels mm- -- XXX @performace. The horizontal concatenation might be slow. If so,- -- 'concatenateSeqs' or 'concatenateAlignments' can be used, which directly- -- appends vectors.- let leafStates = horizontalConcat leafStatesS- leafNames = map getName $ leaves t'- code = P.getAlphabet pm+ ws = MM.getWeights mm+ ds = V.map MS.stationaryDistribution $ MM.getSubstitutionModels mm+ es = V.map MS.exchangeabilityMatrix $ MM.getSubstitutionModels mm+ let leafNames = map getName $ leaves t'+ code = MP.getAlphabet pm -- XXX: Probably use type safe stuff here? alph = A.all $ alphabetSpec code sequences =- [ Seq.Sequence (fromName sName) "" code (V.fromList $ map (`Set.elemAt` alph) ss)+ [ Seq.Sequence (fromName sName) "" code (U.fromList $ map (`Set.elemAt` alph) ss) | (sName, ss) <- zip leafNames leafStates ]- return $ either error id $ A.fromSequences sequences+ output = sequencesToFasta sequences+ $(logInfo) ""+ out "simulated multi sequence alignment" output ".fasta" -- Summarize EDM components; line to be printed to screen or log. summarizeEDMComponents :: [EDMComponent] -> BL.ByteString@@ -112,17 +121,20 @@ ++ show (length cs) ++ " components." -reportModel :: P.PhyloModel -> ELynx SimulateArguments ()+reportModel :: MP.PhyloModel -> ELynx SimulateArguments () reportModel m = do as <- global <$> ask if writeElynxFile as- then (do let bn = outFileBaseName as- case bn of- Nothing ->- $(logInfo)- "No output file provided; omit writing machine-readable phylogenetic model."- Just _ ->- out "model definition (machine readable)" (BL.pack (show m) <> "\n") ".model.gz")+ then+ ( do+ let bn = outFileBaseName as+ case bn of+ Nothing ->+ $(logInfo)+ "No output file provided; omit writing machine-readable phylogenetic model."+ Just _ ->+ out "model definition (machine readable)" (BL.pack (show m) <> "\n") ".model.gz"+ ) else $(logInfo) "No elynx file required; omit writing machine-readable phylogenetic model." pretty :: Length -> String@@ -150,60 +162,60 @@ b = totalBranchLength t -- Summarize a substitution model; lines to be printed to screen or log.-summarizeSM :: SM.SubstitutionModel -> [BL.ByteString]+summarizeSM :: MS.SubstitutionModel -> [BL.ByteString] summarizeSM sm = map BL.pack $- (show (SM.alphabet sm) ++ " substitution model: " ++ SM.name sm ++ ".") :- ["Parameters: " ++ show (SM.params sm) ++ "." | not (null (SM.params sm))]- ++ case SM.alphabet sm of+ (show (MS.alphabet sm) ++ " substitution model: " ++ MS.name sm ++ ".") :+ ["Parameters: " ++ show (MS.params sm) ++ "." | not (null (MS.params sm))]+ ++ case MS.alphabet sm of DNA -> [ "Stationary distribution: "- ++ dispv precision (SM.stationaryDistribution sm)+ ++ dispv precision (MS.stationaryDistribution sm) ++ ".", "Exchangeability matrix:\n"- ++ dispmi 2 precision (SM.exchangeabilityMatrix sm)+ ++ dispmi 2 precision (MS.exchangeabilityMatrix sm) ++ ".",- "Scale: " ++ show (roundN precision $ SM.totalRate sm) ++ "."+ "Scale: " ++ show (roundN precision $ MS.totalRate sm) ++ "." ] Protein -> [ "Stationary distribution: "- ++ dispv precision (SM.stationaryDistribution sm)+ ++ dispv precision (MS.stationaryDistribution sm) ++ ".",- "Scale: " ++ show (roundN precision $ SM.totalRate sm) ++ "."+ "Scale: " ++ show (roundN precision $ MS.totalRate sm) ++ "." ] _ -> error "Extended character sets are not supported with substitution models." -- Summarize a mixture model component; lines to be printed to screen or log.-summarizeMMComponent :: M.Component -> [BL.ByteString]+summarizeMMComponent :: MM.Component -> [BL.ByteString] summarizeMMComponent c = BL.pack "Weight: "- <> (BB.toLazyByteString . BB.doubleDec $ M.weight c) :- summarizeSM (M.substModel c)+ <> (BB.toLazyByteString . BB.doubleDec $ MM.weight c) :+ summarizeSM (MM.substModel c) -- Summarize a mixture model; lines to be printed to screen or log.-summarizeMM :: M.MixtureModel -> [BL.ByteString]+summarizeMM :: MM.MixtureModel -> [BL.ByteString] summarizeMM m =- [ BL.pack $ "Mixture model: " ++ M.name m ++ ".",+ [ BL.pack $ "Mixture model: " ++ MM.name m ++ ".", BL.pack $ "Number of components: " ++ show n ++ "." ] ++ detail where- n = length $ M.components m+ n = length $ MM.components m detail = if n <= 100 then concat [ BL.pack ("Component " ++ show i ++ ":") : summarizeMMComponent c- | (i, c) <- zip [1 :: Int ..] (toList $ M.components m)+ | (i, c) <- zip [1 :: Int ..] (V.toList $ MM.components m) ] else [] -- Summarize a phylogenetic model; lines to be printed to screen or log.-summarizePM :: P.PhyloModel -> [BL.ByteString]-summarizePM (P.MixtureModel mm) = summarizeMM mm-summarizePM (P.SubstitutionModel sm) = summarizeSM sm+summarizePM :: MP.PhyloModel -> [BL.ByteString]+summarizePM (MP.MixtureModel mm) = summarizeMM mm+summarizePM (MP.SubstitutionModel sm) = summarizeSM sm -- | Simulate sequences. simulateCmd :: ELynx SimulateArguments ()@@ -286,7 +298,4 @@ Random -> error "simulateCmd: seed not available; please contact maintainer." Fixed s -> liftIO $ initialize s- alignment <- liftIO $ simulateAlignment phyloModel t' alignmentLength gen- let output = (sequencesToFasta . A.toSequences) alignment- $(logInfo) ""- out "simulated multi sequence alignment" output ".fasta"+ simulateAlignment phyloModel t' alignmentLength gen