packages feed

elynx-tools 0.2.2 → 0.3.0

raw patch · 20 files changed

+1022/−1201 lines, 20 filesdep ~aesondep ~asyncdep ~base

Dependency ranges changed: aeson, async, base, base16-bytestring, bytestring, containers, cryptohash-sha256, deepseq, directory, fast-logger, hmatrix, matrices, megaparsec, monad-control, monad-logger, mwc-random, optparse-applicative, parallel, primitive, template-haskell, text, time, transformers, transformers-base, vector, zlib

Files

ChangeLog.md view
@@ -2,6 +2,17 @@ # Changelog for ELynx  +## Version 0.3.1; in development+++## Version 0.3.0++-   **`elynx-nexus`:** library to import and export Nexus files.+-   **`elynx-tree`:** major refactor and big cleanup; use rose trees with branch+    labels.+-   **`elynx-tree`:** provide zippers.++ ## Version 0.2.2  -   Validation and repetition of previous analyses is finally possible with the
README.md view
@@ -2,9 +2,11 @@  # The ELynx Suite -Version: 0.2.2.+Version: 0.3.0. Reproducible evolution made easy. +<p align="center"><img src="https://travis-ci.org/dschrempf/elynx.svg?branch=master"/></p>+ A Haskell library and tool set for computational biology. The goal of ELynx is reproducible research. Evolutionary sequences and phylogenetic trees can be read, viewed, modified and simulated. The command line with all arguments is@@ -12,11 +14,12 @@ sums so that validation of past analyses is possible without the need to recompute the result. -The Elynx Suite consists of four library packages and three executables providing-a range of sub commands.+The Elynx Suite consists of library packages and executables providing a range+of sub commands.  The library packages are: +-   **elynx-nexus:** Nexus file support. -   **elynx-markov:** Simulate multi sequence alignments along phylogenetic trees. -   **elynx-seq:** Handle evolutionary sequences and multi sequence alignments. -   **elynx-tools:** Tools for the provided executables.@@ -43,7 +46,7 @@  2.  Clone the ELynx repository.     -        git clone clone https://github.com/dschrempf/elynx+        git clone https://github.com/dschrempf/elynx  3.  Navigate to the newly created `elynx` folder and build the binaries.     This will take a while.@@ -62,15 +65,34 @@     [PATH](https://en.wikipedia.org/wiki/PATH_(variable)) environment variable. Then, they can be used directly.  +# Documentation++Documentation is available on [Hackage](https://hackage.haskell.org/).++Libraries:++-   [elynx-nexus](https://hackage.haskell.org/package/elynx-nexus)+-   [elynx-markov](https://hackage.haskell.org/package/elynx-markov)+-   [elynx-seq](https://hackage.haskell.org/package/elynx-seq)+-   [elynx-tools](https://hackage.haskell.org/package/elynx-tools)+-   [elynx-tree](https://hackage.haskell.org/package/elynx-tree)++Executables:++-   [elynx](https://hackage.haskell.org/package/elynx)+-   [slynx](https://hackage.haskell.org/package/slynx)+-   [tlynx](https://hackage.haskell.org/package/tlynx)++ # SLynx  Handle evolutionary sequences. -    slynx --help+    slynx --help | head -n -16 -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME]                   [-f|--force] COMMAND@@ -95,6 +117,7 @@       sub-sample               Sub-sample columns from multi sequence alignments.       translate                Translate from DNA to Protein or DNAX to ProteinX.     +         Available sequence file formats:       - FASTA     @@ -105,23 +128,6 @@       - Protein (amino acids)       - ProteinX (amino acids; including gaps)       - ProteinS (amino acids; including gaps, and translation stops)-      - ProteinI (amino acids; including gaps, translation stops, and IUPAC codes)-    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Concatenate@@ -130,9 +136,9 @@      slynx concatenate --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: slynx concatenate (-a|--alphabet NAME) INPUT-FILE       Concatenate sequences found in input files.@@ -143,23 +149,6 @@       -a,--alphabet NAME       Specify alphabet type NAME       INPUT-FILE               Read sequences from INPUT-FILE       -h,--help                Show this help text-    -    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Examine@@ -168,9 +157,9 @@      slynx examine --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: slynx examine (-a|--alphabet NAME) INPUT-FILE [--per-site]       Examine sequences. If data is a multi sequence alignment, additionally analyze columns.@@ -182,23 +171,6 @@       INPUT-FILE               Read sequences from INPUT-FILE       --per-site               Report per site summary statistics       -h,--help                Show this help text-    -    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Filter@@ -207,9 +179,9 @@      slynx filter-rows --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: slynx filter-rows (-a|--alphabet NAME) INPUT-FILE [--longer-than LENGTH]                               [--shorter-than LENGTH] [--standard-characters]@@ -225,31 +197,14 @@       --standard-characters    Only keep sequences containing at least one standard                                (i.e., non-IUPAC) character       -h,--help                Show this help text-    -    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help  Filter columns of multi sequence alignments with `filter-columns`.      slynx filter-columns --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: slynx filter-columns (-a|--alphabet NAME) INPUT-FILE                                  [--standard-chars DOUBLE]@@ -263,23 +218,6 @@       --standard-chars DOUBLE  Keep columns with a proportion standard (non-IUPAC)                                characters larger than DOUBLE in [0,1]       -h,--help                Show this help text-    -    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Simulate@@ -288,9 +226,9 @@      slynx simulate --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: slynx simulate (-t|--tree-file Name) [-s|--substitution-model MODEL]                            [-m|--mixture-model MODEL] [-e|--edm-file NAME] @@ -352,27 +290,13 @@        where XX is 10, 20, 30, 40, 50, or 60; CXX models, Quang et al., 2008.     -m "EDM(EXCHANGEABILITIES)"        Arbitrary empirical distribution mixture (EDM) models.-       Stationary distributions have to be provided with the -e option.+       Stationary distributions have to be provided with the -e or -p option.        For example,          LG exchangeabilities with stationary distributions given in FILE.          -m "EDM(LG-Custom)" -e FILE+         LG exchangeabilities with site profiles (Phylobayes) given in FILES.+         -m "EDM(LG-Custom)" -p FILES     For special mixture models, mixture weights are optional.-    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Sub-sample@@ -381,9 +305,9 @@      slynx sub-sample --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: slynx sub-sample (-a|--alphabet NAME) INPUT-FILE                             (-n|--number-of-sites INT)@@ -403,22 +327,6 @@       -h,--help                Show this help text          Create a given number of multi sequence alignments, each of which contains a given number of random sites drawn from the original multi sequence alignment.-    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Translate@@ -427,9 +335,9 @@      slynx translate --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: slynx translate (-a|--alphabet NAME) INPUT-FILE (-r|--reading-frame INT)                            (-u|--universal-code CODE)@@ -444,34 +352,17 @@       -u,--universal-code CODE universal code; one of: Standard,                                VertebrateMitochondrial.       -h,--help                Show this help text-    -    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   # TLynx  Handle phylogenetic trees in Newick format. -    tlynx --help+    tlynx --help | head -n -16 -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: tlynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME]                   [-f|--force] COMMAND@@ -496,26 +387,10 @@       shuffle                  Shuffle a phylogenetic tree (keep coalescent times, but shuffle topology and leaves).       simulate                 Simulate phylogenetic trees using birth and death processes (see also the 'coalesce' command for simulations using the coalescent process).     +         Available tree file formats:       - Newick Standard: Branch support values are stored in square brackets after branch lengths.       - Newick IqTree:   Branch support values are stored as node names after the closing bracket of forests.-      - Newick RevBayes  Key-value pairs is provided in square brackets after node names as well as branch lengths. XXX: Key value pairs are IGNORED at the moment.-    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Compare@@ -524,12 +399,12 @@      tlynx compare --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: tlynx compare [-n|--normalize] [-b|--bipartitions] [-t|--intersect] -                         [-f|--newick-format FORMAT] NAME+                         [-f|--newick-format FORMAT] NAMES       Compare two phylogenetic trees (compute distances and branch-wise differences).          Available options:@@ -540,27 +415,11 @@       -t,--intersect           Compare intersections; i.e., before comparison, drop                                leaves that are not present in the other tree       -f,--newick-format FORMAT-                               Newick tree format; see 'tlynx-                               --help' (default: Standard)-      NAME                     Tree file+                               Newick tree format: Standard, IqTree, or RevBayes;+                               default: Standard; for detailed help, see 'tlynx+                               --help'+      NAMES                    Tree files       -h,--help                Show this help text-    -    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Examine@@ -569,9 +428,9 @@      tlynx examine --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: tlynx examine INPUT-FILE [-f|--newick-format FORMAT]       Compute summary statistics of phylogenetic trees.@@ -581,26 +440,10 @@       -V,--version             Show version       INPUT-FILE               Read trees from INPUT-FILE       -f,--newick-format FORMAT-                               Newick tree format; see 'tlynx-                               --help' (default: Standard)+                               Newick tree format: Standard, IqTree, or RevBayes;+                               default: Standard; for detailed help, see 'tlynx+                               --help'       -h,--help                Show this help text-    -    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   ## Simulate@@ -609,9 +452,9 @@      tlynx simulate --help -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: tlynx simulate [-t|--nTrees INT] [-n|--nLeaves INT] [-H|--height DOUBLE]                            [-M|--condition-on-mrca] [-l|--lambda DOUBLE] @@ -640,33 +483,17 @@     Summary statistics only: only print (NumberOfExtantChildren BranchLength) pairs for each branch of each tree. The trees are separated by a newline character.     Sub-sampling: simulate one big tree with n'=round(n/rho), n'>=n, leaves, and randomly sample sub-trees with n leaves. Hence, with rho=1.0, the same tree is reported over and over again.     Gernhard, T. (2008). The conditioned reconstructed process. Journal of Theoretical Biology, 253(4), 769–778. http://doi.org/10.1016/j.jtbi.2008.04.005-    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help   # ELynx  Validate and (optionally) redo past ELynx analyses. -    elynx --help+    elynx --help | head -n -16 -    ELynx Suite version 0.2.1.+    ELynx Suite version 0.3.0.     Developed by Dominik Schrempf.-    Compiled on April 27, 2020, at 12:08 pm, UTC.+    Compiled on July 30, 2020, at 12:40 pm, UTC.          Usage: elynx COMMAND       Validate and redo past ELynx analyses@@ -678,37 +505,4 @@     Available commands:       validate                 Validate an ELynx analysis       redo                     Redo an ELynx analysis-    -    -    ELynx-    ------    A Haskell library and tool set for computational biology. The goal of ELynx is-    reproducible research. Evolutionary sequences and phylogenetic trees can be-    read, viewed, modified and simulated. The command line with all arguments is-    logged consistently, and automatically. Data integrity is verified using SHA256-    sums so that validation of past analyses is possible without the need to-    recompute the result.-    -    slynx     Analyze, modify, and simulate evolutionary sequences.-    tlynx     Analyze, modify, and simulate phylogenetic trees.-    elynx     Validate and redo past analyses.-    -    Get help for sub commands:-      slynx examine --help---# Library documentation--Documentation of the libraries can be found on [Hackage](https://hackage.haskell.org/):---   [elynx-markov](https://hackage.haskell.org/package/elynx-markov)--   [elynx-seq](https://hackage.haskell.org/package/elynx-seq)--   [elynx-tools](https://hackage.haskell.org/package/elynx-tools)--   [elynx-tree](https://hackage.haskell.org/package/elynx-tree)--Documentation of the executables is also available:---   [elynx](https://hackage.haskell.org/package/elynx)--   [slynx](https://hackage.haskell.org/package/slynx)--   [tlynx](https://hackage.haskell.org/package/tlynx) 
elynx-tools.cabal view
@@ -1,74 +1,82 @@-cabal-version: 1.12-name: elynx-tools-version: 0.2.2-license: GPL-3-license-file: LICENSE-copyright: Dominik Schrempf (2020)-maintainer: dominik.schrempf@gmail.com-author: Dominik Schrempf-homepage: https://github.com/dschrempf/elynx#readme-bug-reports: https://github.com/dschrempf/elynx/issues-synopsis: Tools for ELynx-description:-    Please see the README on GitHub at <https://github.com/dschrempf/elynx>.-category: Bioinformatics-build-type: Simple+cabal-version: 2.2++-- This file has been generated from package.yaml by hpack version 0.34.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: ce20a53fa80c7478a01a9fc6ab5b4549475e79e193a58b3e925239f9513502af++name:           elynx-tools+version:        0.3.0+synopsis:       Tools for ELynx+description:    Please see the README on GitHub at <https://github.com/dschrempf/elynx>.+category:       Bioinformatics+homepage:       https://github.com/dschrempf/elynx#readme+bug-reports:    https://github.com/dschrempf/elynx/issues+author:         Dominik Schrempf+maintainer:     dominik.schrempf@gmail.com+copyright:      Dominik Schrempf (2020)+license:        GPL-3.0-or-later+license-file:   LICENSE+build-type:     Simple extra-source-files:     README.md     ChangeLog.md  source-repository head-    type: git-    location: https://github.com/dschrempf/elynx+  type: git+  location: https://github.com/dschrempf/elynx  library-    exposed-modules:-        ELynx.Tools-    hs-source-dirs: src-    other-modules:-        ELynx.Tools.ByteString-        ELynx.Tools.Concurrent-        ELynx.Tools.Definitions-        ELynx.Tools.Equality-        ELynx.Tools.InputOutput-        ELynx.Tools.LinearAlgebra-        ELynx.Tools.List-        ELynx.Tools.Logger-        ELynx.Tools.Matrix-        ELynx.Tools.Misc-        ELynx.Tools.Numeric-        ELynx.Tools.Parallel-        ELynx.Tools.Random-        ELynx.Tools.Reproduction-        ELynx.Tools.Text-        ELynx.Tools.Vector-        Paths_elynx_tools-    default-language: Haskell2010-    ghc-options: -Wall -fllvm-    build-depends:-        aeson >=1.4.7.1 && <1.5,-        async >=2.2.2 && <2.3,-        base >=4.13.0.0 && <4.14,-        base16-bytestring >=0.1.1.6 && <0.2,-        bytestring >=0.10.10.0 && <0.11,-        containers >=0.6.2.1 && <0.7,-        cryptohash-sha256 >=0.11.101.0 && <0.12,-        deepseq >=1.4.4.0 && <1.5,-        directory >=1.3.6.0 && <1.4,-        fast-logger >=3.0.1 && <3.1,-        hmatrix >=0.20.0.0 && <0.21,-        matrices >=0.5.0 && <0.6,-        megaparsec >=8.0.0 && <8.1,-        monad-control >=1.0.2.3 && <1.1,-        monad-logger >=0.3.32 && <0.4,-        mwc-random >=0.14.0.0 && <0.15,-        optparse-applicative >=0.15.1.0 && <0.16,-        parallel >=3.2.2.0 && <3.3,-        primitive >=0.7.0.1 && <0.8,-        template-haskell >=2.15.0.0 && <2.16,-        text >=1.2.4.0 && <1.3,-        time >=1.9.3 && <1.10,-        transformers >=0.5.6.2 && <0.6,-        transformers-base >=0.4.5.2 && <0.5,-        vector >=0.12.1.2 && <0.13,-        zlib >=0.6.2.1 && <0.7+  exposed-modules:+      ELynx.Tools+  other-modules:+      ELynx.Tools.ByteString+      ELynx.Tools.Concurrent+      ELynx.Tools.Definitions+      ELynx.Tools.Equality+      ELynx.Tools.InputOutput+      ELynx.Tools.LinearAlgebra+      ELynx.Tools.List+      ELynx.Tools.Logger+      ELynx.Tools.Matrix+      ELynx.Tools.Misc+      ELynx.Tools.Numeric+      ELynx.Tools.Parallel+      ELynx.Tools.Reproduction+      ELynx.Tools.Text+      ELynx.Tools.Vector+      Paths_elynx_tools+  autogen-modules:+      Paths_elynx_tools+  hs-source-dirs:+      src+  ghc-options: -Wall -fllvm+  build-depends:+      aeson+    , async+    , base >=4.7 && <5+    , base16-bytestring+    , bytestring+    , containers+    , cryptohash-sha256+    , deepseq+    , directory+    , fast-logger+    , hmatrix+    , matrices+    , megaparsec+    , monad-control+    , monad-logger+    , mwc-random+    , optparse-applicative+    , parallel+    , primitive+    , template-haskell+    , text+    , time+    , transformers+    , transformers-base+    , vector+    , zlib+  default-language: Haskell2010
src/ELynx/Tools.hs view
@@ -1,52 +1,47 @@-{- |-Module      :  ELynx.Tools-Description :  Tools and other niceties-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Sat Mar 21 13:56:03 2020.--A large collection of tools.---}-+-- |+-- Module      :  ELynx.Tools+-- Description :  Tools and other niceties+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Sat Mar 21 13:56:03 2020.+--+-- A large collection of tools. module ELynx.Tools-  ( module ELynx.Tools.ByteString-  , module ELynx.Tools.Concurrent-  , module ELynx.Tools.Definitions-  , module ELynx.Tools.Equality-  , module ELynx.Tools.InputOutput-  , module ELynx.Tools.LinearAlgebra-  , module ELynx.Tools.List-  , module ELynx.Tools.Logger-  , module ELynx.Tools.Matrix-  , module ELynx.Tools.Misc-  , module ELynx.Tools.Numeric-  , module ELynx.Tools.Parallel-  , module ELynx.Tools.Random-  , module ELynx.Tools.Reproduction-  , module ELynx.Tools.Text-  , module ELynx.Tools.Vector+  ( module ELynx.Tools.ByteString,+    module ELynx.Tools.Concurrent,+    module ELynx.Tools.Definitions,+    module ELynx.Tools.Equality,+    module ELynx.Tools.InputOutput,+    module ELynx.Tools.LinearAlgebra,+    module ELynx.Tools.List,+    module ELynx.Tools.Logger,+    module ELynx.Tools.Matrix,+    module ELynx.Tools.Misc,+    module ELynx.Tools.Numeric,+    module ELynx.Tools.Parallel,+    module ELynx.Tools.Reproduction,+    module ELynx.Tools.Text,+    module ELynx.Tools.Vector,   ) where -import           ELynx.Tools.ByteString-import           ELynx.Tools.Concurrent-import           ELynx.Tools.Definitions-import           ELynx.Tools.Equality-import           ELynx.Tools.InputOutput-import           ELynx.Tools.LinearAlgebra-import           ELynx.Tools.List-import           ELynx.Tools.Logger-import           ELynx.Tools.Matrix-import           ELynx.Tools.Misc-import           ELynx.Tools.Numeric-import           ELynx.Tools.Parallel-import           ELynx.Tools.Random-import           ELynx.Tools.Reproduction-import           ELynx.Tools.Text-import           ELynx.Tools.Vector+import ELynx.Tools.ByteString+import ELynx.Tools.Concurrent+import ELynx.Tools.Definitions+import ELynx.Tools.Equality+import ELynx.Tools.InputOutput+import ELynx.Tools.LinearAlgebra+import ELynx.Tools.List+import ELynx.Tools.Logger+import ELynx.Tools.Matrix+import ELynx.Tools.Misc+import ELynx.Tools.Numeric+import ELynx.Tools.Parallel+import ELynx.Tools.Reproduction+import ELynx.Tools.Text+import ELynx.Tools.Vector
src/ELynx/Tools/ByteString.hs view
@@ -1,43 +1,41 @@-{- |-Module      :  ELynx.Tools.ByteString-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:24:53 2019.--indispensable tools for ByteString handling :).---}-+-- |+-- Module      :  ELynx.Tools.ByteString+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:24:53 2019.+--+-- indispensable tools for ByteString handling :). module ELynx.Tools.ByteString-  (-    -- * ByteString handling-    alignRightWith-  , alignRight-  , alignLeftWith-  , alignLeft-  , summarizeByteString-  , c2w-  , w2c-  , bShow+  ( -- * ByteString handling+    alignRightWith,+    alignRight,+    alignLeftWith,+    alignLeft,+    summarizeByteString,+    c2w,+    w2c,+    bShow,   ) where -import           Data.ByteString.Internal       ( c2w-                                                , w2c-                                                )-import qualified Data.ByteString.Lazy.Char8    as L+import Data.ByteString.Internal+  ( c2w,+    w2c,+  )+import qualified Data.ByteString.Lazy.Char8 as L  -- | For a given width, align string to the right; use given fill character; -- trim on the left if string is longer. alignRightWith :: Char -> Int -> L.ByteString -> L.ByteString alignRightWith c n s =   L.replicate (fromIntegral n - l) c <> L.take (fromIntegral n) s-  where l = L.length s+  where+    l = L.length s  -- | For a given width, align string to the right; trim on the left if string is -- longer.@@ -49,7 +47,8 @@ alignLeftWith :: Char -> Int -> L.ByteString -> L.ByteString alignLeftWith c n s =   L.take (fromIntegral n) s <> L.replicate (fromIntegral n - l) c-  where l = L.length s+  where+    l = L.length s  -- | For a given width, align string to the left; trim on the right if string is -- longer.@@ -60,7 +59,7 @@ summarizeByteString :: Int -> L.ByteString -> L.ByteString summarizeByteString l s   | L.length s >= fromIntegral l = L.take (fromIntegral l) s <> L.pack "..."-  | otherwise                    = s+  | otherwise = s  -- | Conversion to 'L.ByteString'. bShow :: Show a => a -> L.ByteString
src/ELynx/Tools/Concurrent.hs view
@@ -1,43 +1,41 @@ {-# LANGUAGE ScopedTypeVariables #-}-{- |-Module      :  ELynx.Tools.Concurrent-Description :  Tools for concurrent random calculations-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later -Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Tue May  7 10:33:24 2019.---}-+-- |+-- Module      :  ELynx.Tools.Concurrent+-- Description :  Tools for concurrent random calculations+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Tue May  7 10:33:24 2019. module ELynx.Tools.Concurrent-  (-    -- * MWC-    splitGen+  ( -- * MWC+    splitGen,+     -- * Concurrent calculations-  , parComp-  , getChunks+    parComp,+    getChunks,   ) where -import           Control.Concurrent-import           Control.Concurrent.Async-import           Control.Monad-import           Control.Monad.Primitive-import qualified Data.Vector                   as V-import           Data.Word-import           System.Random.MWC+import Control.Concurrent+import Control.Concurrent.Async+import Control.Monad+import Control.Monad.Primitive+import qualified Data.Vector as V+import Data.Word+import System.Random.MWC  -- | Split a generator. splitGen :: PrimMonad m => Int -> Gen (PrimState m) -> m [Gen (PrimState m)] splitGen n gen   | n <= 0 = return []   | otherwise = do-    seeds :: [V.Vector Word32] <- replicateM n $ uniformVector gen 256-    mapM initialize seeds+    seeds :: [V.Vector Word32] <- replicateM (n -1) $ uniformVector gen 256+    fmap (gen :) (mapM initialize seeds)  -- -- XXX: This just doesn't work... The only thing I found: -- -- https://stackoverflow.com/a/16250010.@@ -62,7 +60,7 @@ -- to the number of calculations. getChunks :: Int -> Int -> [Int] getChunks c n = ns- where-  n' = n `div` c-  r  = n `mod` c-  ns = replicate r (n' + 1) ++ replicate (c - r) n'+  where+    n' = n `div` c+    r = n `mod` c+    ns = replicate r (n' + 1) ++ replicate (c - r) n'
src/ELynx/Tools/Definitions.hs view
@@ -1,29 +1,28 @@-{- |-Module      :  ELynx.Tools.Definitions-Description :  Some global definitions-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Fri Jan 25 17:17:41 2019.---}-+-- |+-- Module      :  ELynx.Tools.Definitions+-- Description :  Some global definitions+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Fri Jan 25 17:17:41 2019. module ELynx.Tools.Definitions   ( -- * Definitions-    chunksize-  , eps-  , eps'-  , precision-  , version+    chunksize,+    eps,+    eps',+    precision,+    version,   ) where -import           Data.Version+import Data.Version +-- TODO: Move back to automatic version handling.+ -- XXX: Manually handled, because automatic handling with @Paths_...@ modules -- results in errors during source tarball creation and upload. @@ -32,7 +31,7 @@  -- | ELynx version. version :: Version-version = makeVersion [0, 2, 2]+version = makeVersion [0, 3, 0]  -- | Required precision when comparing 'Double' values. eps :: Double
src/ELynx/Tools/Equality.hs view
@@ -1,39 +1,35 @@-{- |-Module      :  ELynx.Tools.Equality-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:27:05 2019.--Equality tests.---}-+-- |+-- Module      :  ELynx.Tools.Equality+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:27:05 2019.+--+-- Equality tests. module ELynx.Tools.Equality   ( -- * Equality-    allEqual-  , allNearlyEqualWith-  , allNearlyEqual-  , nearlyEqWith-  , eps-  , nearlyEq-  , (=~=)-  , nearlyEqListWith-  , nearlyEqList-  , nearlyEqVecWith-  , nearlyEqVec-  , nearlyEqMatWith-  , nearlyEqMat+    allEqual,+    allNearlyEqualWith,+    allNearlyEqual,+    nearlyEqWith,+    eps,+    nearlyEq,+    (=~=),+    nearlyEqListWith,+    nearlyEqList,+    nearlyEqVecWith,+    nearlyEqVec,+    nearlyEqMatWith,+    nearlyEqMat,   ) where -import           Numeric.LinearAlgebra--import           ELynx.Tools.Definitions+import ELynx.Tools.Definitions+import Numeric.LinearAlgebra  -- | Test if all elements of a list are equal; returns True for empty list. allEqual :: Eq a => [a] -> Bool@@ -44,7 +40,7 @@  -- | Test if all elements of a list are nearly equal; returns True for empty list. allNearlyEqualWith :: Double -> [Double] -> Bool-allNearlyEqualWith _   [] = True+allNearlyEqualWith _ [] = True allNearlyEqualWith tol xs = all (nearlyEqWith tol $ head xs) (tail xs)  -- | Test if all elements of a list are nearly equal; returns True for empty list.
src/ELynx/Tools/InputOutput.hs view
@@ -1,73 +1,72 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} -{- |-Module      :  ELynx.Tools.InputOutput-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:30:37 2019.--Tools involving input, output, and parsing.---}-+-- |+-- Module      :  ELynx.Tools.InputOutput+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:30:37 2019.+--+-- Tools involving input, output, and parsing. module ELynx.Tools.InputOutput   ( -- * Input, output-    getOutFilePath-  , openFile'-  , readGZFile-  , writeGZFile-  , out-  , outHandle+    getOutFilePath,+    openFile',+    readGZFile,+    writeGZFile,+    out,+    outHandle,+     -- * Parsing-  , runParserOnFile-  , parseFileWith-  , parseIOWith-  , parseFileOrIOWith-  , parseStringWith-  , parseByteStringWith+    runParserOnFile,+    parseFileWith,+    parseIOWith,+    parseFileOrIOWith,+    parseStringWith,+    parseByteStringWith,   ) where -import           Codec.Compression.GZip         ( compress-                                                , decompress-                                                )-import           Control.Monad.Trans.Reader     ( ask )-import           Control.DeepSeq                ( force )-import           Control.Exception              ( evaluate )-import           Control.Monad                  ( (<=<) )-import           Control.Monad.IO.Class-import           Control.Monad.Logger-import qualified Data.ByteString.Lazy.Char8    as L-import           Data.List                      ( isSuffixOf )-import           Data.Maybe-import qualified Data.Text                     as T-import           System.IO-import           System.Directory               ( doesFileExist )-import           Text.Megaparsec--import           ELynx.Tools.Reproduction       ( ELynx-                                                , Force(..)-                                                , Arguments(..)-                                                , outFileBaseName-                                                , forceReanalysis-                                                , Reproducible(..)-                                                )+import Codec.Compression.GZip+  ( compress,+    decompress,+  )+import Control.DeepSeq (force)+import Control.Exception (evaluate)+import Control.Monad ((<=<))+import Control.Monad.IO.Class+import Control.Monad.Logger+import Control.Monad.Trans.Reader (ask)+import qualified Data.ByteString.Lazy.Char8 as L+import Data.List (isSuffixOf)+import Data.Maybe+import qualified Data.Text as T+import ELynx.Tools.Reproduction+  ( Arguments (..),+    ELynx,+    Force (..),+    Reproducible (..),+    forceReanalysis,+    outFileBaseName,+  )+import System.Directory (doesFileExist)+import System.IO+import Text.Megaparsec  -- | Get out file path with extension.-getOutFilePath-  :: forall a . Reproducible a => String -> ELynx a (Maybe FilePath)+getOutFilePath ::+  forall a. Reproducible a => String -> ELynx a (Maybe FilePath) getOutFilePath ext = do   a <- ask-  let bn   = outFileBaseName . global $ a+  let bn = outFileBaseName . global $ a       sfxs = outSuffixes a   if ext `elem` sfxs     then return $ (++ ext) <$> bn@@ -76,14 +75,15 @@         "getOutFilePath: out file suffix not registered. Please contact maintainer."  checkFile :: Force -> FilePath -> IO ()-checkFile (Force True ) _  = return ()-checkFile (Force False) fp = doesFileExist fp >>= \case-  True ->-    error-      $  "File exists: "-      <> fp-      <> ". Please use the --force option to repeat an analysis."-  False -> return ()+checkFile (Force True) _ = return ()+checkFile (Force False) fp =+  doesFileExist fp >>= \case+    True ->+      error $+        "File exists: "+          <> fp+          <> ". Please use the --force option to repeat an analysis."+    False -> return ()  -- | Open existing files only if 'Force' is true. openFile' :: Force -> FilePath -> IOMode -> IO Handle@@ -97,66 +97,77 @@ -- | Read file. If file path ends with ".gz", assume gzipped file and decompress -- before read. readGZFile :: FilePath -> IO L.ByteString-readGZFile f | ".gz" `isSuffixOf` f = decompress <$> readFile' f-             | otherwise            = readFile' f+readGZFile f+  | ".gz" `isSuffixOf` f = decompress <$> readFile' f+  | otherwise = readFile' f  -- | Write file. If file path ends with ".gz", assume gzipped file and compress -- before write. writeGZFile :: Force -> FilePath -> L.ByteString -> IO () writeGZFile frc f r   | ".gz" `isSuffixOf` f = checkFile frc f >> L.writeFile f (compress r)-  | otherwise            = checkFile frc f >> L.writeFile f r+  | otherwise = checkFile frc f >> L.writeFile f r  -- | Parse a possibly gzipped file.-runParserOnFile-  :: Parsec e L.ByteString a-  -> FilePath-  -> IO (Either (ParseErrorBundle L.ByteString e) a)+runParserOnFile ::+  Parsec e L.ByteString a ->+  FilePath ->+  IO (Either (ParseErrorBundle L.ByteString e) a) runParserOnFile p f = parse p f <$> readGZFile f  -- | Parse a possibly gzipped file and extract the result.-parseFileWith-  :: (ShowErrorComponent e)-  => Parsec e L.ByteString a -- ^ The parser.-  -> FilePath-  -> IO a+parseFileWith ::+  (ShowErrorComponent e) =>+  -- | The parser.+  Parsec e L.ByteString a ->+  FilePath ->+  IO a parseFileWith p f = parseFileOrIOWith p (Just f)  -- | Parse standard input.-parseIOWith-  :: (ShowErrorComponent e)-  => Parsec e L.ByteString a -- ^ The parser.-  -> IO a+parseIOWith ::+  (ShowErrorComponent e) =>+  -- | The parser.+  Parsec e L.ByteString a ->+  IO a parseIOWith p = parseByteStringWith "Standard input" p <$> L.getContents  -- | Parse a possibly gzipped file, or standard input, and extract the result.-parseFileOrIOWith-  :: (ShowErrorComponent e)-  => Parsec e L.ByteString a -- ^ The parser.-  -> Maybe FilePath          -- ^ If no file path is given, standard input is used.-  -> IO a+parseFileOrIOWith ::+  (ShowErrorComponent e) =>+  -- | The parser.+  Parsec e L.ByteString a ->+  -- | If no file path is given, standard input is used.+  Maybe FilePath ->+  IO a parseFileOrIOWith p mf = do   contents <- maybe L.getContents readGZFile mf   return $ parseByteStringWith (fromMaybe "Standard input" mf) p contents  -- | Parse a 'String' and extract the result.-parseStringWith-  :: (ShowErrorComponent e)-  => String                  -- ^ Name of string.-  -> Parsec e L.ByteString a -- ^ Parser.-  -> String                  -- ^ Input.-  -> a+parseStringWith ::+  (ShowErrorComponent e) =>+  -- | Name of string.+  String ->+  -- | Parser.+  Parsec e L.ByteString a ->+  -- | Input.+  String ->+  a parseStringWith s p l = parseByteStringWith s p (L.pack l)  -- | Parse a 'L.ByteString' and extract the result.-parseByteStringWith-  :: (ShowErrorComponent e)-  => String                  -- ^ Name of byte string.-  -> Parsec e L.ByteString a -- ^ Parser.-  -> L.ByteString            -- ^ Input.-  -> a+parseByteStringWith ::+  (ShowErrorComponent e) =>+  -- | Name of byte string.+  String ->+  -- | Parser.+  Parsec e L.ByteString a ->+  -- | Input.+  L.ByteString ->+  a parseByteStringWith s p l = case parse p s l of-  Left  err -> error $ errorBundlePretty err+  Left err -> error $ errorBundlePretty err   Right val -> val  -- | Write a result with a given name to file with given extension or standard
src/ELynx/Tools/LinearAlgebra.hs view
@@ -1,40 +1,35 @@-{- |-Module      :  ELynx.Tools.LinearAlgebra-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:33:13 2019.--Tools for matrices from 'Numeric.LinearAlgebra'.---}-+-- |+-- Module      :  ELynx.Tools.LinearAlgebra+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:33:13 2019.+--+-- Tools for matrices from 'Numeric.LinearAlgebra'. module ELynx.Tools.LinearAlgebra-  (-    -- * Linear Algebra-    matrixSeparateSymSkew-  , matrixSetDiagToZero-  , dispv-  , dispm-  , dispmi+  ( -- * Linear Algebra+    matrixSeparateSymSkew,+    matrixSetDiagToZero,+    dispv,+    dispm,+    dispmi,   ) where -import           Data.List--import           Numeric.LinearAlgebra+import Data.List+import Numeric.LinearAlgebra  -- | Separate a square matrix into a symmetric and a skew-symmetric matrix. matrixSeparateSymSkew :: Matrix R -> (Matrix R, Matrix R) matrixSeparateSymSkew m = (mSym, mSkew)- where-  trM   = tr m-  mSym  = scale 0.5 $ m + trM-  mSkew = scale 0.5 $ m - trM+  where+    trM = tr m+    mSym = scale 0.5 $ m + trM+    mSkew = scale 0.5 $ m - trM  -- | Set the diagonal entries of a matrix to zero. matrixSetDiagToZero :: Matrix R -> Matrix R
src/ELynx/Tools/List.hs view
@@ -1,28 +1,33 @@-{- |-Module      :  ELynx.Tools.List-Description :  Additional tools for lists-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu May  2 18:57:39 2019.---}-+-- |+-- Module      :  ELynx.Tools.List+-- Description :  Additional tools for lists+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu May  2 18:57:39 2019. module ELynx.Tools.List   ( -- * Lists-    sortListWithIndices-  , randomInsertList+    sortListWithIndices,+    randomInsertList,+    shuffle,+    shuffleN,+    grabble,   ) where -import           Control.Monad.Primitive-import           Data.Function-import           Data.List-import           System.Random.MWC+import Control.Monad+import Control.Monad.Primitive+import Control.Monad.ST+import Data.Function+import Data.List+import Data.Vector (Vector)+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as M+import System.Random.MWC  -- | Sort a list and also return original indices. sortListWithIndices :: Ord a => [a] -> [(a, Int)]@@ -34,3 +39,29 @@   let l = length v   i <- uniformR (0, l) g   return $ take i v ++ [e] ++ drop i v++-- | Shuffle a list.+shuffle :: PrimMonad m => [a] -> Gen (PrimState m) -> m [a]+shuffle xs g = head <$> grabble xs 1 (length xs) g++-- | Shuffle a list @n@ times.+shuffleN :: [a] -> Int -> GenIO -> IO [[a]]+shuffleN xs n = grabble xs n (length xs)++-- | @grabble xs m n@ is /O(m*n')/, where @n' = min n (length xs)@. Choose @n'@+-- elements from @xs@, without replacement, and that @m@ times.+grabble :: PrimMonad m => [a] -> Int -> Int -> Gen (PrimState m) -> m [[a]]+grabble xs m n gen = do+  swapss <- replicateM m $+    forM [0 .. min (l - 1) n] $ \i -> do+      j <- uniformR (i, l) gen+      return (i, j)+  return $ map (V.toList . V.take n . swapElems (V.fromList xs)) swapss+  where+    l = length xs - 1++swapElems :: Vector a -> [(Int, Int)] -> Vector a+swapElems xs swaps = runST $ do+  mxs <- V.unsafeThaw xs+  mapM_ (uncurry $ M.unsafeSwap mxs) swaps+  V.unsafeFreeze mxs
src/ELynx/Tools/Logger.hs view
@@ -1,77 +1,80 @@-{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell   #-}-{-# LANGUAGE TypeApplications #-} {-# LANGUAGE ScopedTypeVariables #-}--{- |-Module      :  ELynx.Tools.Logger-Description :  Monad logger utility functions-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Fri Sep  6 14:43:19 2019.---}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-} +-- |+-- Module      :  ELynx.Tools.Logger+-- Description :  Monad logger utility functions+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Fri Sep  6 14:43:19 2019. module ELynx.Tools.Logger   ( -- * Logger-    logNewSection-  , eLynxWrapper+    logNewSection,+    eLynxWrapper,   ) where -import           Control.Monad.Base             ( liftBase )-import           Control.Monad.IO.Class         ( MonadIO-                                                , liftIO-                                                )-import           Control.Monad.Logger           ( Loc-                                                , LogLevel-                                                , LogSource-                                                , LoggingT-                                                , MonadLogger-                                                , filterLogger-                                                , logInfo-                                                , runLoggingT-                                                )-import           Control.Monad.Trans.Control    ( MonadBaseControl )-import           Control.Monad.Trans.Reader     ( ReaderT(runReaderT) )-import qualified Data.ByteString.Char8         as B-import           Data.Text                      ( Text-                                                , pack-                                                )-import           System.IO                      ( BufferMode(LineBuffering)-                                                , Handle-                                                , IOMode(WriteMode)-                                                , hClose-                                                , hSetBuffering-                                                , stderr-                                                )-import           System.Log.FastLogger          ( LogStr-                                                , fromLogStr-                                                )-import           System.Random.MWC              ( createSystemRandom-                                                , save-                                                , fromSeed-                                                )--import           ELynx.Tools.Reproduction       ( Reproducible(..)-                                                , writeReproduction-                                                , ToJSON-                                                , toLogLevel-                                                , ELynx-                                                , Arguments(..)-                                                , Force-                                                , GlobalArguments(..)-                                                , Seed(..)-                                                , logHeader-                                                , logFooter-                                                )-import           ELynx.Tools.InputOutput        ( openFile' )+import Control.Monad.Base (liftBase)+import Control.Monad.IO.Class+  ( MonadIO,+    liftIO,+  )+import Control.Monad.Logger+  ( Loc,+    LogLevel,+    LogSource,+    LoggingT,+    MonadLogger,+    filterLogger,+    logInfo,+    runLoggingT,+  )+import Control.Monad.Trans.Control (MonadBaseControl)+import Control.Monad.Trans.Reader (ReaderT (runReaderT))+import qualified Data.ByteString.Char8 as B+import Data.Text+  ( Text,+    pack,+  )+import ELynx.Tools.InputOutput (openFile')+import ELynx.Tools.Reproduction+  ( Arguments (..),+    ELynx,+    Force,+    GlobalArguments (..),+    Reproducible (..),+    Seed (..),+    ToJSON,+    logFooter,+    logHeader,+    toLogLevel,+    writeReproduction,+  )+import System.IO+  ( BufferMode (LineBuffering),+    Handle,+    IOMode (WriteMode),+    hClose,+    hSetBuffering,+    stderr,+  )+import System.Log.FastLogger+  ( LogStr,+    fromLogStr,+  )+import System.Random.MWC+  ( createSystemRandom,+    fromSeed,+    save,+  )  -- | Unified way of creating a new section in the log. logNewSection :: MonadLogger m => Text -> m ()@@ -80,20 +83,20 @@ -- | The 'ReaderT' and 'LoggingT' wrapper for ELynx. Prints a header and a -- footer, logs to 'stderr' if no file is provided. Initializes the seed if none -- is provided. If a log file is provided, log to the file and to 'stderr'.-eLynxWrapper-  :: forall a b-   . (Eq a, Show a, Reproducible a, ToJSON a)-  => Arguments a-  -> (Arguments a -> Arguments b)-  -> ELynx b ()-  -> IO ()+eLynxWrapper ::+  forall a b.+  (Eq a, Show a, Reproducible a, ToJSON a) =>+  Arguments a ->+  (Arguments a -> Arguments b) ->+  ELynx b () ->+  IO () eLynxWrapper args f worker = do   -- Arguments.   let gArgs = global args       lArgs = local args-  let lvl     = toLogLevel $ verbosity gArgs-      rd      = forceReanalysis gArgs-      outBn   = outFileBaseName gArgs+  let lvl = toLogLevel $ verbosity gArgs+      rd = forceReanalysis gArgs+      outBn = outFileBaseName gArgs       logFile = (++ ".log") <$> outBn   runELynxLoggingT lvl rd logFile $ do     -- Header.@@ -101,7 +104,7 @@     $(logInfo) $ pack $ h ++ "\n"     -- Fix seed.     lArgs' <- case getSeed lArgs of-      Nothing     -> return lArgs+      Nothing -> return lArgs       Just Random -> do         -- XXX: Have to go via a generator here, since creation of seed is not         -- supported.@@ -127,20 +130,20 @@     ftr <- liftIO logFooter     $(logInfo) $ pack ftr -runELynxLoggingT-  :: (MonadBaseControl IO m, MonadIO m)-  => LogLevel-  -> Force-  -> Maybe FilePath-  -> LoggingT m a-  -> m a+runELynxLoggingT ::+  (MonadBaseControl IO m, MonadIO m) =>+  LogLevel ->+  Force ->+  Maybe FilePath ->+  LoggingT m a ->+  m a runELynxLoggingT lvl _ Nothing =   runELynxStderrLoggingT . filterLogger (\_ l -> l >= lvl) runELynxLoggingT lvl frc (Just fn) =   runELynxFileLoggingT frc fn . filterLogger (\_ l -> l >= lvl) -runELynxFileLoggingT-  :: MonadBaseControl IO m => Force -> FilePath -> LoggingT m a -> m a+runELynxFileLoggingT ::+  MonadBaseControl IO m => Force -> FilePath -> LoggingT m a -> m a runELynxFileLoggingT frc fp logger = do   h <- liftBase $ openFile' frc fp WriteMode   liftBase (hSetBuffering h LineBuffering)@@ -158,4 +161,5 @@ output2H h1 h2 _ _ _ msg = do   B.hPutStrLn h1 ls   B.hPutStrLn h2 ls-  where ls = fromLogStr msg+  where+    ls = fromLogStr msg
src/ELynx/Tools/Matrix.hs view
@@ -1,102 +1,99 @@-{- |-Module      :  ELynx.Tools.Matrix-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:33:13 2019.--Tools for matrices from 'Numeric.LinearAlgebra'.---}-+-- |+-- Module      :  ELynx.Tools.Matrix+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:33:13 2019.+--+-- Tools for matrices from 'Numeric.LinearAlgebra'. module ELynx.Tools.Matrix   ( -- * Matrices-    fMapRowSeq-  , fMapRowPar-  , fMapRowParChunk-  , fMapColSeq-  , fMapColPar-  , fMapColParChunk-  , (|||)-  , (===)-  , subSampleMatrix+    fMapRowSeq,+    fMapRowPar,+    fMapRowParChunk,+    fMapColSeq,+    fMapColPar,+    fMapColParChunk,+    (|||),+    (===),+    subSampleMatrix,   ) where -import           Control.Parallel.Strategies-import           Data.List-import qualified Data.Matrix.Generic           as M-import qualified Data.Vector.Generic           as V+import Control.Parallel.Strategies+import Data.List+import qualified Data.Matrix.Generic as M+import qualified Data.Vector.Generic as V  -- | Map a function on each row of a DIM2 array; sequential version.-fMapRowSeq-  :: (V.Vector v a, V.Vector v b)-  => (v a -> v b)-  -> M.Matrix v a-  -> M.Matrix v b+fMapRowSeq ::+  (V.Vector v a, V.Vector v b) =>+  (v a -> v b) ->+  M.Matrix v a ->+  M.Matrix v b fMapRowSeq f m = M.fromRows $ map f (M.toRows m)  -- | Map a function on each row of a DIM2 array; parallel version.-fMapRowPar-  :: (V.Vector v a, V.Vector v b)-  => (v a -> v b)-  -> M.Matrix v a-  -> M.Matrix v b+fMapRowPar ::+  (V.Vector v a, V.Vector v b) =>+  (v a -> v b) ->+  M.Matrix v a ->+  M.Matrix v b fMapRowPar f m = M.fromRows $ parMap rseq f (M.toRows m)  -- | Map a function on each row of a DIM2 array; parallel version with given chunk size.-fMapRowParChunk-  :: (V.Vector v a, V.Vector v b)-  => Int-  -> (v a -> v b)-  -> M.Matrix v a-  -> M.Matrix v b+fMapRowParChunk ::+  (V.Vector v a, V.Vector v b) =>+  Int ->+  (v a -> v b) ->+  M.Matrix v a ->+  M.Matrix v b fMapRowParChunk n f m =   M.fromRows (map f (M.toRows m) `using` parListChunk n rseq)  -- | Map a function on each row of a DIM2 array; sequential version.-fMapColSeq-  :: (V.Vector v a, V.Vector v b)-  => (v a -> v b)-  -> M.Matrix v a-  -> M.Matrix v b+fMapColSeq ::+  (V.Vector v a, V.Vector v b) =>+  (v a -> v b) ->+  M.Matrix v a ->+  M.Matrix v b fMapColSeq f m = M.fromColumns $ map f (M.toColumns m)  -- | Map a function on each row of a DIM2 array; parallel version.-fMapColPar-  :: (V.Vector v a, V.Vector v b)-  => (v a -> v b)-  -> M.Matrix v a-  -> M.Matrix v b+fMapColPar ::+  (V.Vector v a, V.Vector v b) =>+  (v a -> v b) ->+  M.Matrix v a ->+  M.Matrix v b fMapColPar f m = M.fromColumns $ parMap rseq f (M.toColumns m)  -- | Map a function on each row of a DIM2 array; parallel version with given chunk size.-fMapColParChunk-  :: (V.Vector v a, V.Vector v b)-  => Int-  -> (v a -> v b)-  -> M.Matrix v a-  -> M.Matrix v b+fMapColParChunk ::+  (V.Vector v a, V.Vector v b) =>+  Int ->+  (v a -> v b) ->+  M.Matrix v a ->+  M.Matrix v b fMapColParChunk n f m =   M.fromColumns (map f (M.toColumns m) `using` parListChunk n rseq)  -- | Horizontal concatenation. (|||) :: (V.Vector v a) => M.Matrix v a -> M.Matrix v a -> M.Matrix v a (|||) l r = M.fromColumns $ lCs ++ rCs- where-  lCs = M.toColumns l-  rCs = M.toColumns r+  where+    lCs = M.toColumns l+    rCs = M.toColumns r  -- | Vertical concatenation. (===) :: (V.Vector v a) => M.Matrix v a -> M.Matrix v a -> M.Matrix v a (===) l r = M.fromRows $ lRs ++ rRs- where-  lRs = M.toRows l-  rRs = M.toRows r+  where+    lRs = M.toRows l+    rRs = M.toRows r  -- | Sample the given sites from a matrix. subSampleMatrix :: (V.Vector v a) => [Int] -> M.Matrix v a -> M.Matrix v a
src/ELynx/Tools/Misc.hs view
@@ -1,30 +1,27 @@-{- |-Module      :  ELynx.Tools.Misc-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:32:19 2019.--Miscellaneous tools that do not have their own category (yet).---}-+-- |+-- Module      :  ELynx.Tools.Misc+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:32:19 2019.+--+-- Miscellaneous tools that do not have their own category (yet). module ELynx.Tools.Misc-  (-    -- * Not yet classified stuff-    ensure+  ( -- * Not yet classified stuff+    ensure,+     -- * Weird stuff-  , compose-  , allValues-  , horizontalConcat+    compose,+    allValues,+    horizontalConcat,   ) where -import           Data.List+import Data.List  -- | Chain a list of functions together. See https://wiki.haskell.org/Compose. compose :: [a -> a] -> a -> a@@ -40,9 +37,10 @@ -- checks are performed! horizontalConcat :: [[[a]]] -> [[a]] horizontalConcat [xs] = xs-horizontalConcat xss  = foldl' (zipWith (++)) (head xss) (tail xss)+horizontalConcat xss = foldl' (zipWith (++)) (head xss) (tail xss)  -- | Ensure that a value satisfies a given predicate. ensure :: (a -> Bool) -> a -> Maybe a-ensure p v | p v       = Just v-           | otherwise = Nothing+ensure p v+  | p v = Just v+  | otherwise = Nothing
src/ELynx/Tools/Numeric.hs view
@@ -1,27 +1,24 @@-{- |-Module      :  ELynx.Tools.Numeric-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:28:37 2019.--Numerical functions.---}-+-- |+-- Module      :  ELynx.Tools.Numeric+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:28:37 2019.+--+-- Numerical functions. module ELynx.Tools.Numeric   ( -- * Numeric-    harmonic-  , xLogX-  , roundN+    harmonic,+    xLogX,+    roundN,   ) where -import           ELynx.Tools.Equality+import ELynx.Tools.Equality  -- | Calculate the nth harmonic number. harmonic :: Int -> Double@@ -30,9 +27,10 @@  -- | Calculate x*log(x) but set to 0.0 when x is smaller than 'eps'. xLogX :: Double -> Double-xLogX x | x < 0.0          = error "Argument lower than zero."-        | x `nearlyEq` 0.0 = 0.0-        | otherwise        = x * log x+xLogX x+  | x < 0.0 = error "Argument lower than zero."+  | x `nearlyEq` 0.0 = 0.0+  | otherwise = x * log x  -- | Round double to a given precision. roundN :: Int -> Double -> Double
src/ELynx/Tools/Parallel.hs view
@@ -1,23 +1,20 @@-{- |-Module      :  ELynx.Tools.Parallel-Description :  Utility functions for parallel calculations-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Tue Apr 21 15:19:44 2020.---}-+-- |+-- Module      :  ELynx.Tools.Parallel+-- Description :  Utility functions for parallel calculations+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Tue Apr 21 15:19:44 2020. module ELynx.Tools.Parallel-  ( parMapChunk+  ( parMapChunk,   ) where -import           Control.Parallel.Strategies+import Control.Parallel.Strategies  -- | Parallel map with given chunk size. parMapChunk :: Int -> (a -> b) -> [a] -> [b]
− src/ELynx/Tools/Random.hs
@@ -1,40 +0,0 @@-{-# LANGUAGE BangPatterns #-}--{- |-Module      :  ELynx.Tools.Random-Description :  Tools for random sampling-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Tue May  7 11:22:12 2019.---}--module ELynx.Tools.Random-  ( -- * Random-    sample-  )-where--import           Control.Monad.Primitive-import           Data.Foldable                  ( toList )-import qualified Data.Sequence                 as Seq-import           System.Random.MWC---- | From a given sequence, randomly sample without replacement a number of elements.-sample :: PrimMonad m => Seq.Seq a -> Int -> Gen (PrimState m) -> m [a]-sample ys size = go 0 (l - 1) ys where-  l = Seq.length ys-  go !n !i xs g-    | n >= size = return $! (toList . Seq.drop (l - size)) xs-    | otherwise = do-      j <- uniformR (0, i) g-      let toI  = xs `Seq.index` j-          toJ  = xs `Seq.index` i-          next = (Seq.update i toI . Seq.update j toJ) xs-      go (n + 1) (i - 1) next g-{-# INLINE sample #-}
src/ELynx/Tools/Reproduction.hs view
@@ -1,94 +1,99 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE DeriveGeneric       #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} -{- |-Module      :  ELynx.Tools.Reproduction-Description :  Functions to ease reproduction of analyses-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable+-- |+-- Module      :  ELynx.Tools.Reproduction+-- Description :  Functions to ease reproduction of analyses+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Tue Nov 19 15:07:09 2019.+--+-- Use of standard input is not supported.+module ELynx.Tools.Reproduction+  ( -- * Log file+    logHeader,+    logFooter, -Creation date: Tue Nov 19 15:07:09 2019.+    -- * Options+    Verbosity (..),+    toLogLevel,+    Force (..),+    forceOpt,+    GlobalArguments (..),+    globalArguments,+    Seed (..),+    seedOpt,+    Arguments (..),+    parseArguments, -Use of standard input is not supported.+    -- * Reproduction+    ELynx,+    Reproducible (..),+    getReproductionHash,+    Reproduction (..),+    writeReproduction,+    hashFile, --}+    -- * Misc+    createCommandReproducible,+    createCommand,+    elynxParserInfo,+    megaReadM, -module ELynx.Tools.Reproduction-  ( -- * Log file-    logHeader-  , logFooter-    -- * Options-  , Verbosity(..)-  , toLogLevel-  , Force(..)-  , forceOpt-  , GlobalArguments(..)-  , globalArguments-  , Seed(..)-  , seedOpt-  , Arguments(..)-  , parseArguments-  -- * Reproduction-  , ELynx-  , Reproducible(..)-  , getReproductionHash-  , Reproduction(..)-  , writeReproduction-  , hashFile-  -- * Misc-  , createCommandReproducible-  , createCommand-  , elynxParserInfo-  , megaReadM-  -- * Re-exports-  , Generic-  , FromJSON-  , ToJSON+    -- * Re-exports+    Generic,+    FromJSON,+    ToJSON,   ) where -import           Data.Aeson                     ( FromJSON-                                                , ToJSON-                                                , encodeFile-                                                )-import           Control.Monad                  ( void )-import           Crypto.Hash.SHA256             ( hash )-import           Data.ByteString.Base16         ( encode )-import qualified Data.ByteString.Char8         as B-import           Data.Word-import           Data.Vector.Unboxed            ( Vector )-import           GHC.Generics                   ( Generic )-import           System.Environment             ( getArgs-                                                , getProgName-                                                )-import           Control.Monad.Logger           ( LoggingT-                                                , LogLevel(..)-                                                )-import           Control.Monad.Trans.Reader     ( ReaderT )-import           Data.List               hiding ( group )-import           Data.Time-import           Data.Version                   ( Version-                                                , showVersion-                                                )-import           Data.Void-import           Language.Haskell.TH-import           Options.Applicative     hiding ( empty )-import           Options.Applicative.Help.Pretty-import           Text.Megaparsec                ( Parsec-                                                , errorBundlePretty-                                                , runParser-                                                )--import           ELynx.Tools.Definitions        ( version )-import           ELynx.Tools.Misc               ( allValues )+import Control.Monad (void)+import Control.Monad.Logger+  ( LogLevel (..),+    LoggingT,+  )+import Control.Monad.Trans.Reader (ReaderT)+import Crypto.Hash.SHA256 (hash)+import Data.Aeson+  ( FromJSON,+    ToJSON,+    encodeFile,+  )+import Data.ByteString.Base16 (encode)+import qualified Data.ByteString.Char8 as B+import Data.List hiding (group)+import Data.Time+import Data.Vector.Unboxed (Vector)+import Data.Version+  ( Version,+    showVersion,+  )+import Data.Void+import Data.Word+import ELynx.Tools.Definitions (version)+import ELynx.Tools.Misc (allValues)+import GHC.Generics (Generic)+import Language.Haskell.TH+import Options.Applicative hiding (empty)+import Options.Applicative.Help.Pretty+import System.Environment+  ( getArgs,+    getProgName,+  )+import Text.Megaparsec+  ( Parsec,+    errorBundlePretty,+    runParser,+  )  -- Be careful; it is necessary to synchronize the version numbers across packages. versionString :: String@@ -98,10 +103,14 @@ copyrightString = "Developed by Dominik Schrempf."  compilationString :: String-compilationString = "Compiled on "-                    ++ $(stringE =<< runIO-                          ( formatTime defaultTimeLocale "%B %-e, %Y, at %H:%M %P, %Z."-                            `fmap` Data.Time.getCurrentTime ))+compilationString =+  "Compiled on "+    ++ $( stringE+            =<< runIO+              ( formatTime defaultTimeLocale "%B %-e, %Y, at %H:%M %P, %Z."+                  `fmap` Data.Time.getCurrentTime+              )+        )  -- A short header to be used in executables. 'unlines' doesn't work here because -- it adds an additional newline at the end.@@ -116,15 +125,15 @@ -- | Short, globally usable string preceding all logs with obligatory description. logHeader :: String -> [String] -> IO String logHeader h dsc = do-  t  <- time-  p  <- getProgName+  t <- time+  p <- getProgName   as <- getArgs-  return-    $  intercalate "\n"-    $  ("=== " <> h)-    :  dsc-    ++ hdr-    ++ ["Start time: " ++ t, "Command line: " ++ p ++ " " ++ unwords as]+  return $+    intercalate "\n" $+      ("=== " <> h) :+      dsc+        ++ hdr+        ++ ["Start time: " ++ t, "Command line: " ++ p ++ " " ++ unwords as]  -- | See 'logHeader' but footer. logFooter :: IO String@@ -134,31 +143,31 @@   return $ intercalate "\n" [timeStr]  versionOpt :: Parser (a -> a)-versionOpt = infoOption-  (intercalate "\n" hdr)-  (  long "version"-    -- Lower case 'v' clashes with verbosity.-  <> short 'V'-  <> help "Show version"-  <> hidden-  )+versionOpt =+  infoOption+    (intercalate "\n" hdr)+    ( long "version"+        -- Lower case 'v' clashes with verbosity.+        <> short 'V'+        <> help "Show version"+        <> hidden+    ) -evoModSuiteFooter :: [Doc]-evoModSuiteFooter =-  [ empty-  , text "ELynx"-  , text "-----"-  , fillParagraph-    "A Haskell library and tool set for computational biology. The goal of ELynx is reproducible research. Evolutionary sequences and phylogenetic trees can be read, viewed, modified and simulated. The command line with all arguments is logged consistently, and automatically. Data integrity is verified using SHA256 sums so that validation of past analyses is possible without the need to recompute the result."-  , empty-  , fill 9 (text "slynx")-    <+> text "Analyze, modify, and simulate evolutionary sequences."-  , fill 9 (text "tlynx")-    <+> text "Analyze, modify, and simulate phylogenetic trees."-  , fill 9 (text "elynx") <+> text "Validate and redo past analyses."-  , empty-  , text "Get help for sub commands:"-  , text "  slynx examine --help"+elynxFooter :: [Doc]+elynxFooter =+  [ text "ELynx",+    text "-----",+    fillParagraph+      "A Haskell library and tool set for computational biology. The goal of ELynx is reproducible research. Evolutionary sequences and phylogenetic trees can be read, viewed, modified and simulated. The command line with all arguments is logged consistently, and automatically. Data integrity is verified using SHA256 sums so that validation of past analyses is possible without the need to recompute the result.",+    empty,+    fill 9 (text "slynx")+      <+> text "Analyze, modify, and simulate evolutionary sequences.",+    fill 9 (text "tlynx")+      <+> text "Analyze, modify, and simulate phylogenetic trees.",+    fill 9 (text "elynx") <+> text "Validate and redo past analyses.",+    empty,+    text "Get help for sub commands:",+    text "  slynx examine --help"   ]  -- | Verbosity levels.@@ -171,10 +180,10 @@  -- | Conert verbosity option to log level. toLogLevel :: Verbosity -> LogLevel-toLogLevel Quiet   = LevelError+toLogLevel Quiet = LevelError toLogLevel Warning = LevelWarn-toLogLevel Info    = LevelInfo-toLogLevel Debug   = LevelDebug+toLogLevel Info = LevelInfo+toLogLevel Debug = LevelDebug  -- | Exit when output exists, or overwrite. newtype Force = Force Bool@@ -186,11 +195,11 @@  -- | A set of global arguments used by all programs. The idea is to provide a -- common framework for shared arguments.--- data GlobalArguments = GlobalArguments-  { verbosity       :: Verbosity-  , outFileBaseName :: Maybe FilePath-  , forceReanalysis :: Force }+  { verbosity :: Verbosity,+    outFileBaseName :: Maybe FilePath,+    forceReanalysis :: Force+  }   deriving (Eq, Show, Generic)  instance FromJSON GlobalArguments@@ -204,33 +213,39 @@  -- | Boolean option; be verbose; default NO. verbosityOpt :: Parser Verbosity-verbosityOpt = option-  auto-  (  long "verbosity"-  <> short 'v'-  <> metavar "VALUE"-  <> value Info-  <> showDefault-  <> help ("Be verbose; one of: " ++ unwords (map show vs))-  )-  where vs = allValues :: [Verbosity]+verbosityOpt =+  option+    auto+    ( long "verbosity"+        <> short 'v'+        <> metavar "VALUE"+        <> value Info+        <> showDefault+        <> help ("Be verbose; one of: " ++ unwords (map show vs))+    )+  where+    vs = allValues :: [Verbosity]  -- | Output filename. outFileBaseNameOpt :: Parser FilePath-outFileBaseNameOpt = strOption-  (long "output-file-basename" <> short 'o' <> metavar "NAME" <> help-    "Specify base name of output file"-  )+outFileBaseNameOpt =+  strOption+    ( long "output-file-basename" <> short 'o' <> metavar "NAME"+        <> help+          "Specify base name of output file"+    )  -- | Force option parser. forceOpt :: Parser Force-forceOpt = flag-  (Force False)-  (Force True)-  -- DO NOT CHANGE --force nor -f; they are used by 'elynx redo'.-  (long "force" <> short 'f' <> help-    "Ignore previous analysis and overwrite existing output files."-  )+forceOpt =+  flag+    (Force False)+    (Force True)+    -- DO NOT CHANGE --force nor -f; they are used by 'elynx redo'.+    ( long "force" <> short 'f'+        <> help+          "Ignore previous analysis and overwrite existing output files."+    )  -- | Random or fixed seed. data Seed = Random | Fixed (Vector Word32)@@ -238,8 +253,8 @@  -- | Upon equality check, a random seed is not different from a fixed one. instance Eq Seed where-  Random  == _       = True-  _       == Random  = True+  Random == _ = True+  _ == Random = True   Fixed s == Fixed t = s == t  instance FromJSON Seed@@ -251,22 +266,26 @@ seedOpt = toSeed <$> seedPar  toSeed :: Maybe (Vector Word32) -> Seed-toSeed Nothing  = Random+toSeed Nothing = Random toSeed (Just w) = Fixed w  seedPar :: Parser (Maybe (Vector Word32))-seedPar = optional $ option-  auto-  (long "seed" <> short 'S' <> metavar "[INT]" <> help-    (  "Seed for random number generator; "-    ++ "list of 32 bit integers with up to 256 elements (default: random)"-    )-  )+seedPar =+  optional $+    option+      auto+      ( long "seed" <> short 'S' <> metavar "[INT]"+          <> help+            ( "Seed for random number generator; "+                ++ "list of 32 bit integers with up to 256 elements (default: random)"+            )+      )  -- | Argument skeleton to be used with all commands.-data Arguments a = Arguments { global :: GlobalArguments-                             , local  :: a-                             }+data Arguments a = Arguments+  { global :: GlobalArguments,+    local :: a+  }   deriving (Eq, Show, Generic)  instance FromJSON a => FromJSON (Arguments a)@@ -274,14 +293,14 @@ instance ToJSON a => ToJSON (Arguments a)  instance Reproducible a => Reproducible (Arguments a) where-  inFiles     = inFiles . local+  inFiles = inFiles . local   outSuffixes = outSuffixes . local-  getSeed     = getSeed . local+  getSeed = getSeed . local   setSeed (Arguments g l) s = Arguments g $ setSeed l s-  parser  = argumentsParser (parser @a)+  parser = argumentsParser (parser @a)   cmdName = cmdName @a-  cmdDsc  = cmdDsc @a-  cmdFtr  = cmdFtr @a+  cmdDsc = cmdDsc @a+  cmdFtr = cmdFtr @a  argumentsParser :: Parser a -> Parser (Arguments a) argumentsParser p = Arguments <$> globalArguments <*> p@@ -292,9 +311,10 @@ -- | Parse arguments. Provide a global description, header, footer, and so on. -- Custom additional description (first argument) and footer (second argument) -- can be provided. print help if needed.-parseArguments :: forall a . Reproducible a => IO (Arguments a)-parseArguments = execParser-  $ elynxParserInfo (cmdDsc @a) (cmdFtr @a) (argumentsParser $ parser @a)+parseArguments :: forall a. Reproducible a => IO (Arguments a)+parseArguments =+  execParser $+    elynxParserInfo (cmdDsc @a) (cmdFtr @a) (argumentsParser $ parser @a)  -- | Logging transformer to be used with all executables. type ELynx a = ReaderT (Arguments a) (LoggingT IO)@@ -307,54 +327,60 @@ --   - a parser to read the command line, --   - a nice program name, description, and footer. class Reproducible a where-  inFiles  :: a -> [FilePath]+  inFiles :: a -> [FilePath]   outSuffixes :: a -> [String]-  getSeed  :: a -> Maybe Seed-  setSeed  :: a -> Vector Word32 -> a-  parser   :: Parser a-  cmdName  :: String-  cmdDsc  :: [String]-  cmdFtr   :: [String]+  getSeed :: a -> Maybe Seed+  setSeed :: a -> Vector Word32 -> a+  parser :: Parser a+  cmdName :: String+  cmdDsc :: [String]+  cmdFtr :: [String]   cmdFtr = []  -- | A unique hash of the reproduction data type.-getReproductionHash :: forall a . Reproducible a => Reproduction a -> String+getReproductionHash :: forall a. Reproducible a => Reproduction a -> String getReproductionHash r =-  B.unpack-    $  encode-    $  hash-    $  B.pack-    $  unlines-    $-  -- Reproduction.-       progName r-    :  argsStr r-    <> [showVersion (rVersion r)]-    <> files r-    <> checkSums r-  -- Reproducible.-    <> inFiles ri-    <> outSuffixes ri-    <> [cmdName @a]-    <> cmdDsc @a-    <> cmdFtr @a-  where ri = reproducible r+  B.unpack $+    encode $+      hash $+        B.pack $+          unlines $+            -- Reproduction.+            progName r :+            argsStr r+              <> [showVersion (rVersion r)]+              <> files r+              <> checkSums r+              -- Reproducible.+              <> inFiles ri+              <> outSuffixes ri+              <> [cmdName @a]+              <> cmdDsc @a+              <> cmdFtr @a+  where+    ri = reproducible r  setHash :: Reproducible a => Reproduction a -> Reproduction a-setHash r = r { rHash = Just h } where h = getReproductionHash r-+setHash r = r {rHash = Just h} where h = getReproductionHash r  -- | Necessary information for a reproducible run. Notably, the input files are -- checked for consistency! data Reproduction a = Reproduction-  { progName         :: String        -- ^ Program name.-  , argsStr          :: [String]      -- ^ Command line arguments without program name.-  , rVersion         :: Version-  , rHash            :: Maybe String  -- ^ Unique hash; see 'getReproductionHash'.-  , files            :: [FilePath]    -- ^ File paths of used files.-  , checkSums        :: [String]      -- ^ SHA256 sums of used files.-  , reproducible     :: a             -- ^ Command argument.-  } deriving (Generic)+  { -- | Program name.+    progName :: String,+    -- | Command line arguments without program name.+    argsStr :: [String],+    rVersion :: Version,+    -- | Unique hash; see 'getReproductionHash'.+    rHash :: Maybe String,+    -- | File paths of used files.+    files :: [FilePath],+    -- | SHA256 sums of used files.+    checkSums :: [String],+    -- | Command argument.+    reproducible :: a+  }+  deriving (Generic)  instance FromJSON a => FromJSON (Reproduction a) @@ -365,64 +391,74 @@ hashFile f = encode . hash <$> B.readFile f  -- | Write an ELynx reproduction file.-writeReproduction-  :: forall a-   . (Eq a, Show a, Reproducible a, ToJSON a)-  => String-  -> a-  -> IO ()+writeReproduction ::+  forall a.+  (Eq a, Show a, Reproducible a, ToJSON a) =>+  String ->+  a ->+  IO () writeReproduction bn r = do   pn <- getProgName   as <- getArgs   let outFs = map (bn ++) (outSuffixes r)-  let fs    = inFiles r ++ outFs+  let fs = inFiles r ++ outFs   cs <- mapM hashFile fs   let cs' = map B.unpack cs-      s   = Reproduction pn as version Nothing fs cs' r+      s = Reproduction pn as version Nothing fs cs' r   void $ encodeFile (bn <> ".elynx") (setHash s)  -- | Create a command; convenience function.-createCommandReproducible-  :: forall a b . Reproducible a => (a -> b) -> Mod CommandFields b-createCommandReproducible f = command (cmdName @a) $ f <$> elynxParserInfo-  (cmdDsc @a)-  (cmdFtr @a)-  (parser @a)+createCommandReproducible ::+  forall a b. Reproducible a => (a -> b) -> Mod CommandFields b+createCommandReproducible f =+  command (cmdName @a) $+    f+      <$> parserInfo+        dsc'+        ftr'+        (parser @a)+  where+    dsc = cmdDsc @a+    ftr = cmdFtr @a+    dsc' = if null dsc then Nothing else Just $ vsep $ map pretty dsc+    ftr' = if null ftr then Nothing else Just $ vsep $ map pretty ftr  -- | Create a command; convenience function.-createCommand-  :: String-  -> [String]-  -> [String]-  -> Parser a-  -> (a -> b)-  -> Mod CommandFields b+createCommand ::+  String ->+  [String] ->+  [String] ->+  Parser a ->+  (a -> b) ->+  Mod CommandFields b createCommand nm dsc ftr p f = command nm $ f <$> parserInfo dsc' ftr' p- where-  dsc' = if null dsc then Nothing else Just $ vsep $ map pretty dsc-  ftr' = if null ftr then Nothing else Just $ vsep $ map pretty ftr+  where+    dsc' = if null dsc then Nothing else Just $ vsep $ map pretty dsc+    ftr' = if null ftr then Nothing else Just $ vsep $ map pretty ftr  -- | ELynx parser info; convenience function. elynxParserInfo :: [String] -> [String] -> Parser a -> ParserInfo a elynxParserInfo dsc ftr = parserInfo dsc' ftr'- where-  dsc' = if null dsc then Nothing else Just $ vsep $ map pretty dsc-  ftr' = Just $ vsep $ map pretty ftr ++ evoModSuiteFooter+  where+    dsc' = if null dsc then Nothing else Just $ vsep $ map pretty dsc+    ftr' = Just . vsep $ map pretty ftr ++ elynxFooter  -- Short version of ELynx parser info for sub commands. parserInfo :: Maybe Doc -> Maybe Doc -> Parser a -> ParserInfo a-parserInfo dsc ftr p = info-  (elynxParser p)-  (fullDesc <> headerDoc (Just hdr') <> progDescDoc dsc <> footerDoc ftr)-  where hdr' = vsep $ map pretty hdr+parserInfo dsc ftr p =+  info+    (elynxParser p)+    (fullDesc <> headerDoc (Just hdr') <> progDescDoc dsc <> footerDoc ftr)+  where+    hdr' = vsep $ map pretty hdr  -- | See 'eitherReader', but for Megaparsec. megaReadM :: Parsec Void String a -> ReadM a megaReadM p = eitherReader $ \input ->   let eea = runParser p "" input-  in  case eea of-        Left  eb -> Left $ errorBundlePretty eb-        Right a  -> Right a+   in case eea of+        Left eb -> Left $ errorBundlePretty eb+        Right a -> Right a  -- | Fill a string so that it becomes a paragraph with line breaks. Useful for -- descriptions, headers and footers.
src/ELynx/Tools/Text.hs view
@@ -1,31 +1,29 @@-{- |-Module      :  ELynx.Tools.Text-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:24:53 2019.--indispensable tools for ByteString handling :).---}-+-- |+-- Module      :  ELynx.Tools.Text+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:24:53 2019.+--+-- indispensable tools for ByteString handling :). module ELynx.Tools.Text   ( -- * Text handling-    tShow-  , fromBs+    tShow,+    fromBs,   ) where -import           Data.ByteString.Lazy           ( ByteString )-import           Data.Text                      ( Text-                                                , pack-                                                )-import           Data.Text.Lazy                 ( toStrict )-import           Data.Text.Lazy.Encoding        ( decodeUtf8 )+import Data.ByteString.Lazy (ByteString)+import Data.Text+  ( Text,+    pack,+  )+import Data.Text.Lazy (toStrict)+import Data.Text.Lazy.Encoding (decodeUtf8)  -- | Conversion to 'Text' from showable values. tShow :: Show a => a -> Text@@ -34,4 +32,3 @@ -- | Conversion to 'Text' from bytestring. fromBs :: ByteString -> Text fromBs = toStrict . decodeUtf8-
src/ELynx/Tools/Vector.hs view
@@ -1,32 +1,29 @@-{- |-Module      :  ELynx.Tools.Vector-Copyright   :  (c) Dominik Schrempf 2020-License     :  GPL-3.0-or-later--Maintainer  :  dominik.schrempf@gmail.com-Stability   :  unstable-Portability :  portable--Creation date: Thu Feb 14 13:33:13 2019.--Tools for vectors from 'Data.Vector.Generic'.---}-+-- |+-- Module      :  ELynx.Tools.Vector+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Thu Feb 14 13:33:13 2019.+--+-- Tools for vectors from 'Data.Vector.Generic'. module ELynx.Tools.Vector   ( -- * Vectors-    sumVec-  , normalizeSumVec-  , uniformVec-  , meanVec-  , chopVec-  , randomInsertVec+    sumVec,+    normalizeSumVec,+    uniformVec,+    meanVec,+    chopVec,+    randomInsertVec,   ) where -import           Control.Monad.Primitive-import qualified Data.Vector.Generic           as V-import           System.Random.MWC+import Control.Monad.Primitive+import qualified Data.Vector.Generic as V+import System.Random.MWC  -- | Sum of elements. sumVec :: (Num a, V.Vector v a) => v a -> a@@ -35,9 +32,9 @@ -- | Normalize a vector such that elements sum to a given value. normalizeSumVec :: (Fractional a, V.Vector v a) => a -> v a -> v a normalizeSumVec c v = V.map (* c') v- where-  s  = sumVec v-  c' = c / s+  where+    s = sumVec v+    c' = c / s  -- | A uniform vector of given length. uniformVec :: (Fractional a, V.Vector v a) => Int -> v a@@ -50,14 +47,14 @@ -- | Chop list into chunks of given length. If the last chop is shorter than -- length, it is dropped. chopVec :: V.Vector v a => Int -> v a -> [v a]-chopVec n xs | V.length xs < n = []-             | otherwise       = V.take n xs : chopVec n (V.drop n xs)+chopVec n xs+  | V.length xs < n = []+  | otherwise = V.take n xs : chopVec n (V.drop n xs)  -- | Insert element into random position of vector.-randomInsertVec-  :: (PrimMonad m, V.Vector v a) => a -> v a -> Gen (PrimState m) -> m (v a)+randomInsertVec ::+  (PrimMonad m, V.Vector v a) => a -> v a -> Gen (PrimState m) -> m (v a) randomInsertVec e v g = do   let l = V.length v   i <- uniformR (0, l) g   return $ V.take i v V.++ V.singleton e V.++ V.drop i v-