From 7beff57e78c62ba29fbc73da073993e75e5ca36e Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Mon, 10 Feb 2025 10:36:43 -0500 Subject: [PATCH 01/11] Switch to vitepress --- docs/.gitignore | 2 ++ docs/Project.toml | 1 + docs/make.jl | 10 ++++++++-- docs/package.json | 16 ++++++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 docs/package.json diff --git a/docs/.gitignore b/docs/.gitignore index b71a83f..f4ef123 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,3 +1,5 @@ build/ site/ Manifest.toml +node_modules/ +package-lock.json diff --git a/docs/Project.toml b/docs/Project.toml index 2349c19..0e99887 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -5,6 +5,7 @@ BioSequences = "7e6ae17a-c86d-528c-b3b9-7f778a29fe59" BioSymbols = "3c28c6f8-a34d-59c4-9654-267d177fcfa9" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8" +DocumenterVitepress = "4710194d-e776-4893-9690-8d956a29c365" FASTX = "c2308a5c-f048-11e8-3e8a-31650f418d12" FormatSpecimens = "3372ea36-2a1a-11e9-3eb7-996970b6ffbd" GFF3 = "af1dc308-cb6b-11e8-32f0-31192efa90f6" diff --git a/docs/make.jl b/docs/make.jl index bb18c23..adde125 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,14 +1,17 @@ using Documenter +using DocumenterVitepress makedocs( - sitename = "Overview of BioJulia", + sitename = "BioJulia Unified Docs", authors = "Michael Persico", modules = Module[], clean = true, doctest = false, draft = false, # TODO expand (https://github.com/SciML/SciMLDocs/blob/0fa5c9c43cf768588124861e76c7854e671ad9d7/docs/make.jl#L29C1-L29C63) - format = Documenter.HTML(assets=["assets/favicon.ico"]), + format = DocumenterVitepress.MarkdownVitepress( + repo = "https://github.com/BioJulia/BioJuliaDocs" + ), pages = [ "BioJulia: Fast, open, easy software for biology" => "index.md", "Getting Started" => [ @@ -35,5 +38,8 @@ makedocs( deploydocs( repo = "https://github.com/BioJulia/BioJuliaDocs.git", + target = "build", + devbranch = "main", + branch = "gh-pages", push_preview = true, ) diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..d45cf53 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,16 @@ +{ + "scripts": { + "docs:dev": "vitepress dev build/.documenter", + "docs:build": "vitepress build build/.documenter", + "docs:preview": "vitepress preview build/.documenter" + }, + "dependencies": { + "@nolebase/vitepress-plugin-enhanced-readabilities": "^2.12.1", + "@shikijs/transformers": "^2.0.3", + "markdown-it": "^14.1.0", + "markdown-it-footnote": "^4.0.0", + "markdown-it-mathjax3": "^4.3.2", + "vitepress": "^1.6.3", + "vitepress-plugin-tabs": "^0.5.0" + } +} From bd7097372dedcd85afab67d0b6f96be49d17c5c4 Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Mon, 10 Feb 2025 10:53:41 -0500 Subject: [PATCH 02/11] update landing page --- docs/assets/apple-touch-icon.png | Bin 0 -> 4097 bytes docs/assets/biojulia-logo-dark-svgomg.svg | 228 +++++++++++++++++++++ docs/assets/biojulia-logo-light-svgomg.png | Bin 0 -> 9785 bytes docs/assets/biojulia-logo-light-svgomg.svg | 36 ++++ docs/assets/biojulia-logo1.png | Bin 0 -> 27227 bytes docs/assets/favicon.ico | Bin 15086 -> 38078 bytes docs/assets/favicon.png | Bin 0 -> 4097 bytes docs/assets/hamburger.svg | 1 + docs/assets/rndimg.jpg | Bin 0 -> 18569 bytes docs/make.jl | 30 ++- docs/package.json | 16 -- docs/src/index.md | 76 +++---- docs/src/overview.md | 49 ++++- 13 files changed, 354 insertions(+), 82 deletions(-) create mode 100644 docs/assets/apple-touch-icon.png create mode 100644 docs/assets/biojulia-logo-dark-svgomg.svg create mode 100644 docs/assets/biojulia-logo-light-svgomg.png create mode 100644 docs/assets/biojulia-logo-light-svgomg.svg create mode 100644 docs/assets/biojulia-logo1.png create mode 100644 docs/assets/favicon.png create mode 100644 docs/assets/hamburger.svg create mode 100644 docs/assets/rndimg.jpg delete mode 100644 docs/package.json diff --git a/docs/assets/apple-touch-icon.png b/docs/assets/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..acbac43764d8ba5c6e69dc168e6a21b6d45917f4 GIT binary patch literal 4097 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 O0DWz!R+WY$>i+;<`TBAI literal 0 HcmV?d00001 diff --git a/docs/assets/biojulia-logo-dark-svgomg.svg b/docs/assets/biojulia-logo-dark-svgomg.svg new file mode 100644 index 0000000..d790c63 --- /dev/null +++ b/docs/assets/biojulia-logo-dark-svgomg.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/biojulia-logo-light-svgomg.png b/docs/assets/biojulia-logo-light-svgomg.png new file mode 100644 index 0000000000000000000000000000000000000000..bc40875eceaf4151263e1c41a1f863c6764d1a3b GIT binary patch literal 9785 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/biojulia-logo1.png b/docs/assets/biojulia-logo1.png new file mode 100644 index 0000000000000000000000000000000000000000..40f583e96551614622e668a7ac143fcc02717a42 GIT binary patch literal 27227 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 a23+@>K|}hcV11-tWYM2Cq|$3_3H%4>C>R?6 literal 15086 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 CEB00Z diff --git a/docs/assets/favicon.png b/docs/assets/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..acbac43764d8ba5c6e69dc168e6a21b6d45917f4 GIT binary patch literal 4097 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 O0DWz!R+WY$>i+;<`TBAI literal 0 HcmV?d00001 diff --git a/docs/assets/hamburger.svg b/docs/assets/hamburger.svg new file mode 100644 index 0000000..233bf21 --- /dev/null +++ b/docs/assets/hamburger.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/assets/rndimg.jpg b/docs/assets/rndimg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..98be38d7ab67b4c9a149370e4abc9a2932881c85 GIT binary patch literal 18569 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 "index.md", "Getting Started" => [ - "New User Tutorials" => [ - "getting_started/juliainstallation.md", - "getting_started/toolsinstallation.md", - "getting_started/biojuliainstallation.md", - "getting_started/casescenarios.md", - ], - "Comparison With Other Packages/Ecosystems" => [ - "comparisons/biopython.md", - "comparisons/scikitbio.md", - "comparisons/bioconductor.md", - "comparisons/biojava.md", - "comparisons/bioperl.md", - "comparisons/bioruby.md", - ], + "getting_started/juliainstallation.md", + "getting_started/toolsinstallation.md", + "getting_started/biojuliainstallation.md", + "getting_started/casescenarios.md", + ], + "Comparison With Other Packages/Ecosystems" => [ + "comparisons/biopython.md", + "comparisons/scikitbio.md", + "comparisons/bioconductor.md", + "comparisons/biojava.md", + "comparisons/bioperl.md", + "comparisons/bioruby.md", ], # Showcase of Cool Examples - "What is BioJulia?" => ["overview.md", + "What is BioJulia?" => [ + "overview.md", ] ] ) diff --git a/docs/package.json b/docs/package.json deleted file mode 100644 index d45cf53..0000000 --- a/docs/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "scripts": { - "docs:dev": "vitepress dev build/.documenter", - "docs:build": "vitepress build build/.documenter", - "docs:preview": "vitepress preview build/.documenter" - }, - "dependencies": { - "@nolebase/vitepress-plugin-enhanced-readabilities": "^2.12.1", - "@shikijs/transformers": "^2.0.3", - "markdown-it": "^14.1.0", - "markdown-it-footnote": "^4.0.0", - "markdown-it-mathjax3": "^4.3.2", - "vitepress": "^1.6.3", - "vitepress-plugin-tabs": "^0.5.0" - } -} diff --git a/docs/src/index.md b/docs/src/index.md index 2a9a1d2..3685e54 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,48 +1,34 @@ -# BioJulia: Fast, open, easy software for biology +--- +# https://vitepress.dev/reference/default-theme-home-page +# Cribbed from DimensionalData.jl +layout: home -> Note: This landing site is under extensive development and will receive -> frequent updates. It is not in a ready state, and is published under GitHub -> Pages only for testing purposes. +hero: + name: "BioJulia" + text: "Unified Docs for BioJulia" + tagline: Doing biology with julia + image: + src: '/assets/biojulia-logo-dark-svgomg.png' + actions: + - theme: brand + text: Getting Started + link: /getting_started/juliainstallation + - theme: alt + text: Overview + link: /overview + - theme: alt + text: View on Github + link: https://github.com/BioJulia/BioJuliaDocs +features: + - title: BioSequences.jl + details: Optimized types for working with biological sequences (eg DNA, RNA, proteins) + link: https://biojulia.dev/BioSequences.jl + - title: Automa.jl + details: Efficient state-machine generation to quickly and correctly parse bespoke file formats + link: https://biojulia.dev/Automa.jl + - title: BioMakie.jl + details: Visualize sequences and 3D proteins with ease + link: https://biojulia.dev/BioMakie.jl +--- -BioJulia is a passionate, community-led organization providing biology-related -packages written in the [Julia programming language](https://julialang.org/). -The organization offers a comprehensive, fully open-source ecosystem of both -libraries that serve as essential building blocks for other packages as well as -interactive tools for everyday tasks and workflows. - -Biologists and other scientists are fully empowered by Julia to easily tackle -domain-specific challenges, taking advantage of features including: -* [Fully reproducible - environments](https://pkgdocs.julialang.org/v1/environments/) thanks to - Julia's built-in package manager -* [Competitive performance](https://julialang.org/benchmarks/) that rivals that - of lower-level, more complex languages such as C and Fortran -* [Unicode-based math symbol - support](https://docs.julialang.org/en/v1/manual/unicode-input/), [transparent - BLAS - integration](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#man-linalg), - and additional features for performing complex numerical operations -* [A batteries-included read-eval-print loop - (REPL)](https://docs.julialang.org/en/v1/stdlib/REPL/#The-Julia-REPL) for - interactive data exploration and prototyping -* [Seamless - interoperability](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#Calling-C-and-Fortran-Code) - [(JLLs,](https://docs.binarybuilder.org/stable/#Project-flow) - [Cmd,...)](https://docs.julialang.org/en/v1/manual/running-external-programs/#Running-External-Programs) - with other languages via multiple foreign function interfaces - -## Where to Start? - -* Take a look at all BioJulia code via the official [GitHub - page](https://github.com/BioJulia) -* Begin contributing ideas and features following the [core - guidelines](https://github.com/BioJulia/Contributing.git) -* Deep dive into the ecosystem over at the [Overview]() -* Start learning right away using the [Getting Started tutorials]() -* See some awesome examples in the [BioJulia Showcase]() -* Come chat with us over in the [Slack](https://julialang.org/slack/) #biology - channel and on [forums](https://discourse.julialang.org/) - -Use the top navigation bar to search for provided packages within one's field of -interest. diff --git a/docs/src/overview.md b/docs/src/overview.md index 1a80318..fab7b27 100644 --- a/docs/src/overview.md +++ b/docs/src/overview.md @@ -1,11 +1,50 @@ # [Overview](@id overview) -# Overview of the BioJulia Ecosystem +# BioJulia: Fast, open, easy software for biology -BioJulia is an +> Note: This landing site is under extensive development and will receive +> frequent updates. It is not in a ready state, and is published under GitHub +> Pages only for testing purposes. -## +BioJulia is a passionate, community-led organization providing biology-related +packages written in the [Julia programming language](https://julialang.org/). +The organization offers a comprehensive, fully open-source ecosystem of both +libraries that serve as essential building blocks for other packages as well as +interactive tools for everyday tasks and workflows. -## Common Julia packages +Biologists and other scientists are fully empowered by Julia to easily tackle +domain-specific challenges, taking advantage of features including: +* [Fully reproducible + environments](https://pkgdocs.julialang.org/v1/environments/) thanks to + Julia's built-in package manager +* [Competitive performance](https://julialang.org/benchmarks/) that rivals that + of lower-level, more complex languages such as C and Fortran +* [Unicode-based math symbol + support](https://docs.julialang.org/en/v1/manual/unicode-input/), [transparent + BLAS + integration](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#man-linalg), + and additional features for performing complex numerical operations +* [A batteries-included read-eval-print loop + (REPL)](https://docs.julialang.org/en/v1/stdlib/REPL/#The-Julia-REPL) for + interactive data exploration and prototyping +* [Seamless + interoperability](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#Calling-C-and-Fortran-Code) + [(JLLs,](https://docs.binarybuilder.org/stable/#Project-flow) + [Cmd,...)](https://docs.julialang.org/en/v1/manual/running-external-programs/#Running-External-Programs) + with other languages via multiple foreign function interfaces + +## Where to Start? + +* Take a look at all BioJulia code via the official [GitHub + page](https://github.com/BioJulia) +* Begin contributing ideas and features following the [core + guidelines](https://github.com/BioJulia/Contributing.git) +* Deep dive into the ecosystem over at the [Overview]() +* Start learning right away using the [Getting Started tutorials]() +* See some awesome examples in the [BioJulia Showcase]() +* Come chat with us over in the [Slack](https://julialang.org/slack/) #biology + channel and on [forums](https://discourse.julialang.org/) + +Use the top navigation bar to search for provided packages within one's field of +interest. -Below are a few examples of common Julia packages that are \ No newline at end of file From e14fb3aa9da543703d5c26d5d9ffb81f5616088e Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Mon, 10 Feb 2025 11:08:10 -0500 Subject: [PATCH 03/11] fix index page --- .github/workflows/documentation.yml | 56 ++++++++++++++++++++--------- docs/package.json | 16 +++++++++ docs/src/index.md | 4 +-- 3 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 docs/package.json diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 3ff0ba0..4b1c8c0 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -1,27 +1,51 @@ -# https://documenter.juliadocs.org/stable/man/hosting/#GitHub-Actions -name: Documentation +# Sample workflow for building and deploying a VitePress site to GitHub Pages +# +name: Deploy documentation on: + # Runs on pushes targeting the `main` branch. Change this to `master` if you're + # using the `master` branch as the default branch. push: branches: - - main - tags: '*' + - main + tags: ['*'] pull_request: + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: write + pages: write + id-token: write + actions: write + + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: pages + cancel-in-progress: false + jobs: + # Build job build: - permissions: - contents: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 - with: - version: '1.6' - - name: Install dependencies - run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - - name: Build and deploy + - name: Checkout + uses: actions/checkout@v4 + with: # Fetches the last commit only + fetch-depth: 0 + - name: Setup Julia + uses: julia-actions/setup-julia@v1 + - name: Pull Julia cache + uses: julia-actions/cache@v1 + - name: Generate logo + - uses: julia-actions/julia-docdeploy@v1 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # If authenticating with GitHub Actions token - DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # If authenticating with SSH deploy key - run: julia --project=docs/ docs/make.jl + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key + GKSwstype: "100" # https://discourse.julialang.org/t/generation-of-documentation-fails-qt-qpa-xcb-could-not-connect-to-display/60988 + JULIA_DEBUG: "Documenter" + DATADEPS_ALWAYS_ACCEPT: true diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..d45cf53 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,16 @@ +{ + "scripts": { + "docs:dev": "vitepress dev build/.documenter", + "docs:build": "vitepress build build/.documenter", + "docs:preview": "vitepress preview build/.documenter" + }, + "dependencies": { + "@nolebase/vitepress-plugin-enhanced-readabilities": "^2.12.1", + "@shikijs/transformers": "^2.0.3", + "markdown-it": "^14.1.0", + "markdown-it-footnote": "^4.0.0", + "markdown-it-mathjax3": "^4.3.2", + "vitepress": "^1.6.3", + "vitepress-plugin-tabs": "^0.5.0" + } +} diff --git a/docs/src/index.md b/docs/src/index.md index 3685e54..15e6504 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,3 +1,4 @@ +```@raw html --- # https://vitepress.dev/reference/default-theme-home-page # Cribbed from DimensionalData.jl @@ -30,5 +31,4 @@ features: details: Visualize sequences and 3D proteins with ease link: https://biojulia.dev/BioMakie.jl --- - - +``` From 7ac23c27092ede45a65a416f1f89eb23ce44b3f0 Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Mon, 10 Feb 2025 11:11:59 -0500 Subject: [PATCH 04/11] Try to fix action --- .github/workflows/documentation.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 4b1c8c0..5061e81 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -41,8 +41,8 @@ jobs: uses: julia-actions/setup-julia@v1 - name: Pull Julia cache uses: julia-actions/cache@v1 - - name: Generate logo - - uses: julia-actions/julia-docdeploy@v1 + - name: Deploy + uses: julia-actions/julia-docdeploy@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key From aea7b9c82ef9ce60ade907063e4588d672f88f08 Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Mon, 10 Feb 2025 11:33:15 -0500 Subject: [PATCH 05/11] Remove template issues --- .github/ISSUE_TEMPLATE/custom.md | 59 ------------------ .github/ISSUE_TEMPLATE/feature_request.md | 20 ------ .github/PULL_REQUEST_TEMPLATE.md | 43 ------------- .github/workflows/pr_comment.yml | 14 +++++ docs/assets/JuliaVSCodeExtension.png | Bin 166685 -> 0 bytes docs/{ => src}/assets/apple-touch-icon.png | Bin .../assets/biojulia-logo-dark-svgomg.svg | 0 .../assets/biojulia-logo-light-svgomg.png | Bin .../assets/biojulia-logo-light-svgomg.svg | 0 docs/{ => src}/assets/biojulia-logo1.png | Bin docs/{ => src}/assets/favicon.ico | Bin docs/{ => src}/assets/favicon.png | Bin docs/{ => src}/assets/hamburger.svg | 0 docs/{ => src}/assets/rndimg.jpg | Bin docs/src/index.md | 10 ++- 15 files changed, 22 insertions(+), 124 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/custom.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/pr_comment.yml delete mode 100644 docs/assets/JuliaVSCodeExtension.png rename docs/{ => src}/assets/apple-touch-icon.png (100%) rename docs/{ => src}/assets/biojulia-logo-dark-svgomg.svg (100%) rename docs/{ => src}/assets/biojulia-logo-light-svgomg.png (100%) rename docs/{ => src}/assets/biojulia-logo-light-svgomg.svg (100%) rename docs/{ => src}/assets/biojulia-logo1.png (100%) rename docs/{ => src}/assets/favicon.ico (100%) rename docs/{ => src}/assets/favicon.png (100%) rename docs/{ => src}/assets/hamburger.svg (100%) rename docs/{ => src}/assets/rndimg.jpg (100%) diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md deleted file mode 100644 index 984d171..0000000 --- a/.github/ISSUE_TEMPLATE/custom.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -name: Custom issue template -about: Describe this issue template's purpose here. -title: '' -labels: '' -assignees: M-PERSIC - ---- - - - -> _This template is rather extensive. Fill out all that you can, if are a new contributor or you're unsure about any section, leave it unchanged and a reviewer will help you_ :smile:. _This template is simply a tool to help everyone remember the BioJulia guidelines, if you feel anything in this template is not relevant, simply delete it._ - -### Description - -Please provide a clear and concise description of the documentation issue or improvement request. - -### Current Documentation - -If applicable, describe the current state of the documentation related to this issue. What needs to be changed, added, or improved? - -### Desired Documentation - -Explain how you envision the documentation should be modified or improved. Provide specific details or examples, if possible. - -### Motivation - -Share the motivation behind this documentation change or improvement. What problem does it solve or what value does it add? - -### Steps to Reproduce (if applicable) - -If the issue is related to incorrect or unclear documentation, please provide steps to reproduce the problem or confusion. - -### Additional Context - -Provide any additional context or information that might be helpful in addressing this documentation issue. - -### Checklist - -Please make sure that the following items have been considered for this documentation issue: - -- [ ] The proposed documentation change aligns with the overall project goals and objectives. -- [ ] The requested documentation modification adds value to users or contributors. -- [ ] Any code snippets, examples, or configuration files that need to be updated are identified. -- [ ] Links, references, or external resources mentioned in the documentation are accurate and up-to-date. -- [ ] The language and grammar used in the documentation are clear and concise. -- [ ] The documentation follows the established style and formatting guidelines. - -### Possible Solution (if known) - -If you have any ideas or suggestions for how to address this documentation issue, please share them here. - -### Related Issues or PRs - -List any related issues or pull requests that may be relevant to this documentation issue. - -### Assignees (if known) - -Assign relevant individuals or teams responsible for addressing this documentation issue. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index d7411b2..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,43 +0,0 @@ -# A clear and descriptive title (No issue numbers please) - -> _This template is rather extensive. Fill out all that you can, if are a new contributor or you're unsure about any section, leave it unchanged and a reviewer will help you_ :smile:. _This template is simply a tool to help everyone remember the BioJulia guidelines, if you feel anything in this template is not relevant, simply delete it._ - -### Description - -Please provide a brief description of the changes made in this documentation pull request. - -### Motivation - -Explain the motivation or purpose behind these documentation changes. What problem is there to be solved or what improvement is being proposed? - -### Changes Made - -List the specific changes made in this pull request. Include details such as files modified, sections updated, or new content added. - -### Related Issues - -Are there any related issues or tickets associated with this pull request? If yes, please provide their numbers or links. - -### Screenshots (if applicable) - -If relevant, provide any screenshots or visual representations that support and clarify the documentation changes made. - -### Checklist - -Please make sure that the following items have been addressed in this pull request: - -- [ ] The documentation changes are clear and concise. -- [ ] The language and grammar have been reviewed and edited for readability. -- [ ] The changes are consistent with the overall style and formatting guidelines. -- [ ] Any relevant code snippets or examples have been updated to reflect the changes made. -- [ ] Links and references within the documentation are accurate and up-to-date. -- [ ] The documentation has been reviewed for accuracy and completeness. -- [ ] The changes have been tested to ensure they work as expected. - -### Additional Notes - -Add any additional notes or information that would be helpful for reviewers or others who may be involved in this pull request. - -### Reviewers - -Tag the relevant reviewers or individuals who should review this documentation pull request. \ No newline at end of file diff --git a/.github/workflows/pr_comment.yml b/.github/workflows/pr_comment.yml new file mode 100644 index 0000000..c7d29b6 --- /dev/null +++ b/.github/workflows/pr_comment.yml @@ -0,0 +1,14 @@ +name: pr_comment +on: + pull_request: + types: [opened, reopened] +jobs: + pr_comment: + runs-on: ubuntu-latest + steps: + - name: Create PR comment + if: github.event_name == 'pull_request' && github.repository == github.event.pull_request.head.repo.full_name # if this is a pull request build AND the pull request is NOT made from a fork + uses: thollander/actions-comment-pull-request@71efef56b184328c7ef1f213577c3a90edaa4aff + with: + message: 'Once the build has completed, you can preview your PR at this URL: https://biojulia.dev/BiojuliaDocs/previews/PR${{ github.event.number }}/' + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/assets/JuliaVSCodeExtension.png b/docs/assets/JuliaVSCodeExtension.png deleted file mode 100644 index 15ab654c5f564d38f8a47d368915ee3173397a75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166685 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

?5!ktVl^X6sZZWjBMN@s}??g`o4 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

v;8A6IC^LNfw(l)9ZDF_MlSx!XPE80vOl*i`TZ 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 diff --git a/docs/assets/apple-touch-icon.png b/docs/src/assets/apple-touch-icon.png similarity index 100% rename from docs/assets/apple-touch-icon.png rename to docs/src/assets/apple-touch-icon.png diff --git a/docs/assets/biojulia-logo-dark-svgomg.svg b/docs/src/assets/biojulia-logo-dark-svgomg.svg similarity index 100% rename from docs/assets/biojulia-logo-dark-svgomg.svg rename to docs/src/assets/biojulia-logo-dark-svgomg.svg diff --git a/docs/assets/biojulia-logo-light-svgomg.png b/docs/src/assets/biojulia-logo-light-svgomg.png similarity index 100% rename from docs/assets/biojulia-logo-light-svgomg.png rename to docs/src/assets/biojulia-logo-light-svgomg.png diff --git a/docs/assets/biojulia-logo-light-svgomg.svg b/docs/src/assets/biojulia-logo-light-svgomg.svg similarity index 100% rename from docs/assets/biojulia-logo-light-svgomg.svg rename to docs/src/assets/biojulia-logo-light-svgomg.svg diff --git a/docs/assets/biojulia-logo1.png b/docs/src/assets/biojulia-logo1.png similarity index 100% rename from docs/assets/biojulia-logo1.png rename to docs/src/assets/biojulia-logo1.png diff --git a/docs/assets/favicon.ico b/docs/src/assets/favicon.ico similarity index 100% rename from docs/assets/favicon.ico rename to docs/src/assets/favicon.ico diff --git a/docs/assets/favicon.png b/docs/src/assets/favicon.png similarity index 100% rename from docs/assets/favicon.png rename to docs/src/assets/favicon.png diff --git a/docs/assets/hamburger.svg b/docs/src/assets/hamburger.svg similarity index 100% rename from docs/assets/hamburger.svg rename to docs/src/assets/hamburger.svg diff --git a/docs/assets/rndimg.jpg b/docs/src/assets/rndimg.jpg similarity index 100% rename from docs/assets/rndimg.jpg rename to docs/src/assets/rndimg.jpg diff --git a/docs/src/index.md b/docs/src/index.md index 15e6504..dc12c0f 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -6,10 +6,10 @@ layout: home hero: name: "BioJulia" - text: "Unified Docs for BioJulia" + text: "Unified Docs" tagline: Doing biology with julia image: - src: '/assets/biojulia-logo-dark-svgomg.png' + src: '/assets/biojulia-logo1.png' actions: - theme: brand text: Getting Started @@ -21,6 +21,9 @@ hero: text: View on Github link: https://github.com/BioJulia/BioJuliaDocs features: + - title: BioTutorials + details: These are still a work in progress + link: https://biojulia.dev/BioTutorials - title: BioSequences.jl details: Optimized types for working with biological sequences (eg DNA, RNA, proteins) link: https://biojulia.dev/BioSequences.jl @@ -30,5 +33,8 @@ features: - title: BioMakie.jl details: Visualize sequences and 3D proteins with ease link: https://biojulia.dev/BioMakie.jl + - title: SingleCellProjections.jl + details: More cells? No Problem! Get UMAPs and other projections of your singlg cell data using the power of Sparse Matrices + link: https://biojulia.dev/SingleCellProjections.jl --- ``` From 8d2ff7941616255d5d1d97bdf3bbc86e3207c2ac Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Mon, 10 Feb 2025 12:10:28 -0500 Subject: [PATCH 06/11] Add a full logo.png --- docs/src/assets/logo.png | Bin 0 -> 52561 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/src/assets/logo.png diff --git a/docs/src/assets/logo.png b/docs/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cf81e1e0fc3f5e60371113de10c4696d9eaf8ee6 GIT binary patch literal 52561 zcmYg&2{@GR_x>!HHiSYLOQ<9ylEzwgT2(3(r3Kl_gsd}d$S!FohBjF$A;R0LozX(s zrqxI>l_HY={rY@=*Y)qZTv=w`=XuU@pL6bWo=IG_!a;J9(j*FnBI)F4>q? zTU{J%@jw3kv8jo}e-lF-H-=IuVrAoB>ADJd8->AkT5iYap-qyJm|EAX=Yl6voNSk@ zjd=UDBmBg!b$`mI~;O z;f+dbbo1$Wzn0UkMMf5kvV~>RA<}|Xf_H?xP4$z0%518hU?mZE`B!razwrRM&_JlV zHu?IA3ydr(7lzCi`JST%sGJ#?A#kx)t|Hd0CAX7(hnqz{Rs2io{0r7lLUQ45yzF?NEwxi5Et?MYuTIF$>gp+?*4CAHYV7Wp~z8S>YXIa(I}$jUV80v z+&c-~kIV@XpC+7cqg*RSN#BHGe5@w4< zh|gbBe7qz0&`DWIM>nNwp? zTl_~=u_M!4fg)Y<+GV!G_)e7c{#&Pf3f9r(c2m`k1UY34(o1(MTakjttgUl57&T`t#lxFL|69WjFQA*!O!cd`Pq{TC!Urd@{BIYc|2@JEyJ(Xg znkH%$W*hFA71HHjJCG)vO3MB2J8Nfhr}Dl#B7?jHjeMrhl?}zmW2Z4S$W4g;(@rz( z>9R(P2}7IN4PqB*YB&U+iFZv(FWv4&Yoparq9{@H8hRx?Oss-pLMx%_i~o~6BmTEI z&TO)&T2=nWo_592h=H;H?N}1~iINiWg{c!4&~IIIH|UtkoC#^Yd)%_%G-$+Ax?8zY%7!-x8>n$we*^mm|@W*`zL%=1H zIA1694^JkpS{H5X@tiSgzD((Vf|ef_bQ+~GG3ccC14vc|DP%OeIG8$%c0-WuHMcp5zmo$x=@$7 zzFRtju0zVTdPe-}ME0!o-G%T0*T|2%PM+l)r;aIfT$|8HO%0#FP(`W$yVkl?8n0g5mQER>i+R%A}?R+L&glF%ca!X^>eRYdHaAN_>n$(l*M@iFU=gT!Tud^p} zJf@F}ZR}X-_J=JCq!}gZ9e3w&3}|srS{AI~YkasjecaZ?NaZnywz1<)gmfYQozVI`--HHoS zJEz<-Wo?zkk&Y22LJzomF8P20_NJ2P9U+ zQ_>{%XjZk!ixvtR2sIc$;W)e>o#XW+z$I8b-Q;VpHT2f5$jn^(pS3Pe21>7_txW4{ zYVxGCSGXJ8tllvL&$AzJv#?N#&Q0#tHq~WswCkUl z5oKFh@URy$Je{wZ`S^b_oNr`toVp?rPh7sfx3JO9p

)F4-;_VIsOB%n>)0A2Jnr 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%0AvV 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 LHodXl`M3W86Dn08 literal 0 HcmV?d00001 From 07385294c64e78bc3793823445c946d10213dbb9 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Mon, 10 Feb 2025 12:10:44 -0500 Subject: [PATCH 07/11] Add the new logo to the main page --- docs/src/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/index.md b/docs/src/index.md index dc12c0f..b3ae4ed 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -9,7 +9,7 @@ hero: text: "Unified Docs" tagline: Doing biology with julia image: - src: '/assets/biojulia-logo1.png' + src: '/assets/logo.png' actions: - theme: brand text: Getting Started From 1a893807488f04cf3f7421acda4730053cf2e8ca Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Mon, 10 Feb 2025 12:10:54 -0500 Subject: [PATCH 08/11] Add an icon to the BioMakie hero card --- docs/src/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/index.md b/docs/src/index.md index b3ae4ed..1d8d26e 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -33,6 +33,7 @@ features: - title: BioMakie.jl details: Visualize sequences and 3D proteins with ease link: https://biojulia.dev/BioMakie.jl + icon: - title: SingleCellProjections.jl details: More cells? No Problem! Get UMAPs and other projections of your singlg cell data using the power of Sparse Matrices link: https://biojulia.dev/SingleCellProjections.jl From 6121498babd128fcf4eec1edf5bfc3253497aa2c Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Fri, 21 Feb 2025 10:31:39 -0500 Subject: [PATCH 09/11] Add old posts --- docs/src/posts/automa1.md | 891 ++++++++++++++++++++++++++++++++++ docs/src/posts/biojl.md | 47 ++ docs/src/posts/cajun-kevin.md | 32 ++ docs/src/posts/hardware.md | 16 + docs/src/posts/index.md | 3 + docs/src/posts/seq-lang.md | 115 +++++ 6 files changed, 1104 insertions(+) create mode 100644 docs/src/posts/automa1.md create mode 100644 docs/src/posts/biojl.md create mode 100644 docs/src/posts/cajun-kevin.md create mode 100644 docs/src/posts/hardware.md create mode 100644 docs/src/posts/index.md create mode 100644 docs/src/posts/seq-lang.md diff --git a/docs/src/posts/automa1.md b/docs/src/posts/automa1.md new file mode 100644 index 0000000..198f8a1 --- /dev/null +++ b/docs/src/posts/automa1.md @@ -0,0 +1,891 @@ ++++ +using Dates +date = Date("2020-08-30") +title = "Tutorial to Automa: Part 1" +author = "Jakob Nybo Nissen" ++++ + + + +# Tutorial to Automa: Part 1 + +**Find this notebook at [https://github.com/jakobnissen//assets/posts/automa1/automa_tutorial](https://github.com/jakobnissen//assets/posts/automa1/automa_tutorial)** + +In bioinformatics, we have a saying: + +> The first step of any bioinformatics project is to define a new file format, incompatible with all previous ones. + +The situation might not be _quite_ as bad as the saying implies, but it _is_ true that we have a _lot_ of different file formats, representing the various kinds of data we work with. + +For that reason, creating file parsers is a central task in bioinformatics, and has almost become [a craft in itself.](http://biopython.org/DIST/docs/tutorial/Tutorial.html#sec14) An awful, awful craft. For anything but the simplest formats, designing robust parsers is hard, and it is difficult to know if a parser you've built is solid. Insignificant details like trailing whitespace can break a seemingly well-built parser. + +At its core, a parser is a program that checks whether some input data comforms to some format. For bioinformatics, we typically also want to load the data in the file into some data structure to work on it. The format itself is typically specified in some kind of higher-level, but unambiguous language, like [this description of the Newick format.](https://en.wikipedia.org/wiki/Newick_format#Grammar) A parser then, can be viewed as a program that: + +- Is given a format specified in a high-level “language”, e.g. “a leaf in the Newick format consist of only a _name_, which is formed from the alphabet “a-z, A-Z and \_"", and +- Checks whether some input follows that format using relatively low-level instructions, e.g. checking whether the following bytes until the next `(`, `)`, `,` or `;` match the pattern `[A-Za-z_]` + +The central job of a parser is then to act as a _translator_ between different abstraction levels: The format is specified in a high-level language, but the actual data processing must happen at a lower level language. + +When described like that, parser generation seems quite analogous to code compilation, and begins too look like a _machine's_ job, not a human's. Machines are fast and accurate, and do not make oversights or mistakes - exactly the characteristics you want when making a parser. Let's leave the machine tasks to the machines; we humans ought to put our effort into what we do best: Specifying the formats themselves. + +In this tutorial, I will introduce Automa, a Julia package for creating parsers. Actually, when reading this you might be able to tell that Automa solves a problem slightly more general than just creating parsers, but creating parsers is what we will use it for in this tutorial. Automa is not an easy package to use; it is complex and a little opaque, but it's worth all the effort and more. Parsers generated by Automa have several advantages over human-made parsers: + +- They are failsafe: Any deviation of the input from the specified format, no matter how trivial, will cause it to fail. Therefore, they are much more reliant than human-written parsers. +- They are easy to change. You can often easily change details in the input format, such as allowing whitespace, with minimal changes to your code, +- They are quite fast, with Automa-code often being faster than even optimized human-crafted parsers. + +In this first part of the tutorial I will show how to create parsers from data loaded into memory in order to highlight Automa itself. In the second part, which I will release at a later date, I will show how to create a proper BioJulia reader and writer for a file format. + +## Our format + +For our example, let us begin with a simlified version of the FASTA format - we can call it “SimpleFasta”. Our format will be defined as something that looks like this: + +```fasta +>first +TGATAGTAGTCGTGTGATA +>second +AGGACCCAATTATCGGGGTAA +``` + +I.e. + +- A SimpleFasta file is a sequence of zero or more _records_ +- A _record_ consists of _header_ \* newline \* _sequence_ \* newline, where "\*" signifies concatenation +- A _header_ consists of `>` followed by one or more characters from the alphabet a-z +- A _sequence_ consists of one or more chatacters from the alphabet A, C, G or T. + +We can visualize a hypothetical SimpleFasta parser using a simple flowchart - note: You need to have `graphviz` installed to be able to run the code below. + +```julia +s = """digraph { +graph [ rankdir = LR ]; +begin [ shape = circle ]; +begin -> header; +header [ shape = circle ]; +header -> sequence; +sequence [ shape = circle ]; +sequence -> end; +end [ shape = circle ]; +sequence -> header; +begin -> end; +} +""" +function display_machine() + write("/tmp/fasta_machine.dot", s) + run(`dot -Tsvg -o /tmp/fasta_machine.svg /tmp/fasta_machine.dot`) + open("/tmp/fasta_machine.svg") do file + display("image/svg+xml", String(read(file))) + end +end; +``` + +```julia +display_machine() +``` + +![svg](/assets/posts/automa1/automa_tutorial_2_0.svg) + +After the beginning of the file, we expect to see a header. Next, we move to the sequence. From there, we can either reach the end of the file, or loop back to another header. Alternatively, in the case of an empty file, we may move from the beginning of the file to the end immediately without any headers or sequences. We consider an empty file to also be specification-compliant. + +Note that this simple flowchart describes any _valid_ SimpleFasta format. But if, for example, a file had two consecutive header lines, there is no path we can take through the flowchart from “begin” to “end” which describes the file, and we can tell that the input did not conform to the format. + +The circles marked “begin”, “header”, “sequence” or “end” are what we call the four _states_. Because the parser shown in the diagram has a fixed list of possible states that it changes between, we call the parser a _finite state machine_ (FSM), or _finite state automaton_ (FSA). + +The flowchart above doesn't do a very good job of describing the FSM that our parser is, because it doesn't tell you _how_ the machine transitions between states. The state _transitions_ are what actually defines the format. For example, we know we are transitioning to a header when we see a `>` symbol - that is, in a way, what _defines_ the header state. + +In the flowchart below, the arrows signifying transitions between states are marked with the input character(s) that causes the FSM (our parser) to transition, written in a [regex-like](http://regexr.com) notation. For example, the transition from a header to a sequence is defined by a `\n` followed by one of the characters in `[ACGT]`. “EOF” signifies end of file. Note also that some states have transitions leading to itself. For example, when in the “header” state, the FSM may continue to read characters in `a-z` and stay in the “header” state. + +```julia +s = """digraph { + graph [ rankdir = LR ]; +begin [ shape = circle ]; +header [ shape = circle ]; +sequence [ shape = circle ]; +end [ shape = circle ]; + +begin -> header [ label = ">[a-z]" ]; +header -> header [ label = "[a-z]"]; +header -> sequence [ label = "\\\\n[ACGT]" ]; +sequence -> sequence [ label = "[ACGT]" ]; +sequence -> header [ label = "\\\\n>" ]; +sequence -> end [ label = "\\\\nEOF" ]; +begin -> end; +} +""" +display_machine() +``` + +![svg](/assets/posts/automa1/automa_tutorial_4_0.svg) + +How does the machine know when it's supposed to transition between states? Suppose a machine is at the beginning of a file and it begins by observing the input `>`. Is this part of a transition to the header state, or the beginning of a malformed input? + +It is certainly possible for the machine to have a _memory_ of the pattern, such that it only transitions to the “header” state once it sees the two specific inputs `>` and `[a-z]` in that order. However, we can make things much simpler by requiring the machine to make a state transition for _every single input byte_, then we don't need any memory other than what state the machine is in, which is a single integer. To still represent the same format at the flowchart above, we need to insert some extra states: + +```julia +s = """digraph { + graph [ rankdir = LR ]; + begin [ shape = circle ]; + 2 [ shape = circle ]; +1 [ shape = circle ]; +3 [ shape = circle ]; + begin -> 1 [ label = ">" ]; + header [ shape = circle ]; +1 -> header [label = "[a-z]" ]; +header -> header [ label = "[a-z]" ]; +2 -> sequence [ label = "[ACGT]" ]; +header -> 2 [ label = "\\\\n" ]; + + +sequence [ shape = circle ]; +sequence -> sequence [ label = "[ACGT]" ]; +sequence -> 3 [ label = "\\\\n" ]; +3 -> 1 [ label = ">" ]; +end [ shape = circle ]; +3 -> end [ label = "EOF" ]; +"begin" -> end [ label = "EOF" ]; +} +""" +display_machine() +``` + +![svg](/assets/posts/automa1/automa_tutorial_6_0.svg) + +The diagram above is exactly equivalent to the previous one, but this diagram makes a state transition for _every single_ input byte. All bytes cause a transition, and no transition consumes multiple bytes. For simplicity, Automa's parsers work like that. + +Note that it is always possible, given a FSM with multi-byte transitions to convert it to a FSM with single-byte transitions by just putting in more nodes. E.g. the transition from header to sequence requires two bytes, a newline and an A, C, G or T. Therefore, an intermediate note (on the illustration marked “2”) is needed. Unfortunately, the requirement of single-byte transitions limits what you can do with Automa - I'll come back to the limitations later. + +Now let's create this same FSM using Automa. + +## Introducing Automa + +```julia +# First imports +import Automa +import Automa.RegExp: @re_str +const re = Automa.RegExp; +``` + +We define the elements that make up the SimpleFasta (the header and the sequence) using `Automa.RegExp`, a subset of regular expressions. Automa's regular expressions can be manipulated with the following operations: + +Function + +Alias + +Meaning + +`cat(re...)` + +`*` + +concatenation + +`alt(re1, re2...)` + +`|` + +alternation + +`rep(re)` + +zero or more repetition + +`rep1(re)` + +one or more repetition + +`opt(re)` + +zero or one repetition + +`isec(re1, re2)` + +`&` + +intersection + +`diff(re1, re2)` + +`&bsol` | difference (subtraction) | + +`neg(re)` + +`!` + +negation + +Furthermore inside the re-strings themselves, you can use + +- groups of characters, like `[ACGT]` representing the set `{A, C, G, T}` +- ranges `A-Z` representing `'A':'Z'` (or more accurately, the _bytes_ `UInt8('A'):UInt8('Z')` +- `*`, representing zero or more repetitions of the last element, such as `[a-z]*` +- `+`, representing one or more repetitions of the last element, such as `[a-z]+` +- `?`, representing zero or one repetition of the last element, such as `[a-z]?` + +We can specify our FSM like below. We use a `let` statement only so we don't pollute global namespace with `header`, `sequence` etc. + +```julia +machine = let + # Define SimpleFasta syntax + header = re">[a-z]+" + sequence = re"[ACGT]+" + record = header * re"\n" * sequence * re"\n" + fasta = re.rep(record) + + # Compile the regex to a FSM + Automa.compile(fasta) +end; +``` + +If you have `dot` installed on your computer, you can visualize the compiled FSM. You might want to modify the paths in the function below to make it work on your computer. + +```julia +function display_machine(machine) + write("/tmp/fasta_machine.dot", Automa.machine2dot(machine)) + run(`dot -Tsvg -o /tmp/fasta_machine.svg /tmp/fasta_machine.dot`) + open("/tmp/fasta_machine.svg") do file + display("image/svg+xml", String(read(file))) + end +end; +``` + +```julia +display_machine(machine) +``` + +![svg](/assets/posts/automa1/automa_tutorial_13_0.svg) + +Yes, that looks correct! The start node here is the small point on the left. You can see one of the states are represented by a double circle. This represents an _accept state_, where the machine may stop at a valid end of input - here after each SimpleFasta record. If the machine stops at any other state, it did not complete correctly. In other words, state “1” here doubles as the “end” state. + +With this parser we can read a SimpleFasta file and determine if it conforms to the specification. In Automa, we do this by having our machine create Julia code in the form of a Julia expression (of type `Expr`), which we can then use to create a function using metaprogramming. + +First, we need an `Automa.CodeGenContext`, an object which contains the options for code generation. For now, we don't worry about the settings and just make a default context object: + +```julia +context = Automa.CodeGenContext(); +``` + +Then, we use two functions to generate code: + +- `Automa.generate_init_code(::CodeGenContext, ::Machine)` creates the Julia code needed to initialize the parsing of the given FSM. +- `Automa.generate_exec_code(::CodeGenContext, ::Machine, ::Dict{Symbol, Expr})` creates the Julia code needed for the main loop of the running parser. Here, the `Dict` is an _action dict_, which may contain arbitrary Julia code that the parser executes while parsing. We need that action dict later to make our parser do something useful - but for now, we simply want to create _a_ parser, not necessarily a _useful_ one, so we just use an empty dict. We will come back to the action dict later. + +Let's have a look at these functions: + +```julia +Automa.generate_init_code(context, machine) +``` + +``` +quote + #= /home/jakob/.julia/packages/Automa/sfHZ6/src/codegen.jl:94 =# + p::Int = 1 + #= /home/jakob/.julia/packages/Automa/sfHZ6/src/codegen.jl:95 =# + p_end::Int = 0 + #= /home/jakob/.julia/packages/Automa/sfHZ6/src/codegen.jl:96 =# + p_eof::Int = -1 + #= /home/jakob/.julia/packages/Automa/sfHZ6/src/codegen.jl:97 =# + cs::Int = 1 +end +``` + +Besides the comments, the init code seems to define four integers. What to they mean? + +Automa works by reading the data byte by byte. When doing this, the data is represented in the function as an `AbstractVector{UInt8}` - let us call that `data`. `p` represents the index of `data` that the parser is currently reading from. `p_end` represents the last position of the data in `data`. Because `data` may just be a small, buffered part of a much larger file being parsed, `p_eof` represents the index of actual end of input. Last, `cs` is short for “current state”, and is an integer representing the state of the FSM. You can see that sensibly, it is initialized at state 1, and so, by looking at the FSM diagram, we can see it next expects a ‘>’. The zero state is special, and represents the “accept state”, that is, the state of a correctly exited FSM. + +The code generated by `Automa.generate_exec_code` is a little more complicated, and also depends on the `CodeGenContext`. But it will increment `p` by one, read a byte from `data`, and execute a state transition (i.e. change `cs`) depending on the byte. If `cs` goes negative, it knows the input is malformed. If `cs` is zero, the parser has finished. If `cs` is positive, it will continue until end of file. + +Alright, let's create a parser using these functions! + +```julia +@eval function parse_fasta(data::Union{String,Vector{UInt8}}) + $(Automa.generate_init_code(context, machine)) + + # p_end and p_eof were set to 0 and -1 in the init code, + # we need to set them to the end of input, i.e. the length of `data`. + p_end = p_eof = lastindex(data) + + # We just use an empty dict here because we don't want our parser + # to do anything just yet - only parse the input + $(Automa.generate_exec_code(context, machine, Dict{Symbol, Expr}())) + + # We need to make sure that we reached the accept state, else the + # input did not parse correctly + iszero(cs) || error("failed to parse on byte ", p) + return nothing +end; +``` + +Does it work? + +```julia +for (inputno, data) in enumerate([ + "", + ">hi\nACGT\n", + ">hi\nACGT", + ">hi\nAA\n>x\nGTGATCGTAGTA\n", + ">hi\nthere!" + ]) + try + parse_fasta(data) + println("Input $inputno: parsed successfully!") + catch e + println("Input $inputno: ", e) + end +end +``` + +``` +Input 1: parsed successfully! +Input 2: parsed successfully! +Input 3: ErrorException("failed to parse on byte 9") +Input 4: parsed successfully! +Input 5: ErrorException("failed to parse on byte 5") +``` + +Excellent. It correctly parsed the empty data, input 2 and 4. Input 3 lacked a trailing newline, and input 5 didn't have a proper sequence. + +But just parsing a file is not too useful. Normally, we parse a file in order to load it into some kind of datastructure to manipulate it. That's where the action dict comes into the picture. We can make Automa execute arbitrary Julia code during parsing. Here is how it works: + +- When defining our machine, we add _action names_, in the form of Julia `Symbol`s to certain regexes. For example, we may define that exiting the regex `sequence` should execute the action `:exit_sequence`. Like other Julia identifiers, the name can be chosen arbitrarily. +- Using the action dict, which was of type `Dict{Symbol, Expr}`, we can map action names to Julia code. This tells Automa what each action name _means_. +- The actions expressions are put into the function we create at parse time, so there is no runtime cost to this. + +First, we redefine our machine. This time, we add actions: + +```julia +machine = let + # Define SimpleFasta syntax + newline = re"\n" + header = re">[a-z]+" + sequence = re"[ACGT]+" + record = header * newline * sequence * newline + fasta = re.rep(record) + + # Define SimpleFasta actions using arbitrary names + header.actions[:enter] = [:enter] + header.actions[:exit] = [:exit_header] + sequence.actions[:enter] = [:enter] + sequence.actions[:exit] = [:exit_sequence] + record.actions[:exit] = [:exit_record] + + Automa.compile(fasta) +end; +``` + +If we visualize the machine now, the actions will be printed on the relevant edges in the FSM diagram. For example, the newline after a header is labeled `'\n'/exit_header`, meaning the transition will happen at the input byte `'\n'`, and it will execute the action `exit_header`. + +Also note that the diagram structure itself changed, because the entering state and exit state are now distinct. The exit state 6 will execute `:exit_record` at the end of file (EOF), whereas if the FSM ends at state 1, `:exit_record` is not executed. + +```julia +display_machine(machine) +``` + +![svg](/assets/posts/automa1/automa_tutorial_25_0.svg) + +Let's also define a simple data structure to parse the SimpleFasta records into. Like our SimpleFasta format, let's not overcomplicate things: + +```julia +using BioSequences +``` + +```julia +struct FastaRecord{A} + header::String + sequence::LongSequence{A} +end + +FastaRecord(h, sequence::LongSequence{A}) where A = FastaRecord{A}(h, sequence); +``` + +And now our action dict. I can use the variables `data`, `p`, `p_end` etc. in the code: + +```julia +actions = Dict( + # Record which byte position marks the beginning of header or sequence + :enter => quote + mark = p + end, + :exit_header => quote + header = String(data[mark+1:p-1]) + end, + :exit_sequence => quote + sequence = LongSequence{A}(data[mark:p-1]) + end, + :exit_record => quote + record = FastaRecord(header, sequence) + push!(records, record) + end, +); +``` + +```julia +@eval function parse_fasta(::Type{A}, data::Union{String,Vector{UInt8}}) where {A <: Alphabet} + # We can't control the order that the code from out action dict is executed, so + # we define variables beforehand so we can be sure they are not used before + # they are defined. + mark = 0 + records = FastaRecord{A}[] + header = "" + sequence = LongSequence{A}() + + # The rest is just like in our previous example, except now we use the + # action dict we just created. + $(Automa.generate_init_code(context, machine)) + p_end = p_eof = lastindex(data) + $(Automa.generate_exec_code(context, machine, actions)) + + iszero(cs) || error("failed to parse on byte ", p) + return records +end; +``` + +We can verify that it works: + +```julia +parse_fasta(DNAAlphabet{4}, ">hello\nTAG\n>there\nTAA\n") +``` + +``` +2-element Array{FastaRecord{DNAAlphabet{4}},1}: + FastaRecord{DNAAlphabet{4}}("hello", TAG) + FastaRecord{DNAAlphabet{4}}("there", TAA) +``` + +## Redesign the format + +With the basics now covered, let's step up the game a tad and make it parse SimpleFasta records with multiple lines per sequence. We first define a `seqline` pattern that looks like the old `sequence` pattern, and build a new `sequence` pattern from multiple `seqline` patterns. + +```julia +machine = let + # Define SimpleFasta syntax + header = re">[a-z]+" + seqline = re"[ACGT]+" + sequence = seqline * re.rep(re"\n" * seqline) + record = header * re"\n" * sequence * re"\n" + fasta = re.rep(record) + + # Define SimpleFasta actions + header.actions[:enter] = [:enter] + header.actions[:exit] = [:exit_header] + seqline.actions[:enter] = [:enter] + seqline.actions[:exit] = [:exit_seqline] + record.actions[:exit] = [:exit_record] + + Automa.compile(fasta) +end; +``` + +The machine now has a subtle change with a small loop between node 5 and 6 representing the parser seeing multiple sequence lines. + +```julia +display_machine(machine) +``` + +![svg](/assets/posts/automa1/automa_tutorial_37_0.svg) + +We also need to update the `actions`. Here, I use `:(this syntax)`, which is equivalent to + +``` +quote + this syntax +end +``` + +but more readable for one-liners. I keep a buffer containing the sequence, and append every sequence line to the buffer at the end of each `seqline`. When the record is done, I create the sequence and empty the buffer for the next record. + +```julia +actions = Dict( + :enter => :(mark= p), + :exit_header => :(header = String(data[mark+1:p-1])), + :exit_seqline => quote + doff = length(seqbuffer) + 1 + resize!(seqbuffer, length(seqbuffer) + p - mark) + copyto!(seqbuffer, doff, data, mark, p-mark) + end, + :exit_record => quote + sequence = LongSequence{A}(seqbuffer) + empty!(seqbuffer) + record = FastaRecord(header, sequence) + push!(records, record) + end, +); +``` + +We need to redefine `parse_fasta`, now also containing the `seqbuffer`: + +```julia +@eval function parse_fasta(::Type{A}, data::Union{String,Vector{UInt8}}) where {A <: Alphabet} + mark = 0 + records = FastaRecord{A}[] + header = "" + sequence = LongSequence{A}() + seqbuffer = UInt8[] + + $(Automa.generate_init_code(context, machine)) + p_end = p_eof = lastindex(data) + $(Automa.generate_exec_code(context, machine, actions)) + + iszero(cs) || error("failed to parse on byte ", p) + return records +end; +``` + +And we can confirm it now works for multiple sequences! + +```julia +parse_fasta(DNAAlphabet{2}, ">hello\nTAG\nGGG\n>there\nTAA\nTAG\n") +``` + +``` +2-element Array{FastaRecord{DNAAlphabet{2}},1}: + FastaRecord{DNAAlphabet{2}}("hello", TAGGGG) + FastaRecord{DNAAlphabet{2}}("there", TAATAG) +``` + +## Even more complexity + +One of the greatest things about Automa is how we can parse quite complicated formats without needing to manually construct much code. For example, here, I change _only_ the regular expressions: + +- I allow optional Windows-style newlines (`\r\n`) +- I allow trailing whitespace on each line (`re.space() \ (re"\r" | re"\n")` means all space characters except \\r or \\n), but not whitespace inside headers +- Sequences can only contain all UIPAC ambiguous RNA or DNA nucleotides +- The trailing record no longer needs a trailing newline to be valid. It has the same actions as a regular record. + +```julia +machine = let + # Define FASTA syntax + newline = re.opt("\r") * re"\n" + hspace = re.space() \ (re"\r" | re"\n") + header = re">" * re.rep1((re.any() \ re.space())) * re.opt(hspace) + seqline = re"[acgturmkyswbdhvnACGTURMKYSWBDHVN\-*]+" * re.opt(hspace) + sequence = seqline * re.rep(newline * seqline) + record = header * newline * sequence * newline + trailing_record = header * newline * sequence * re.rep(newline * re.opt(hspace)) + fasta = re.rep(newline) * re.rep(record) * re.opt(trailing_record) + + # Define FASTA actions + header.actions[:enter] = [:enter] + header.actions[:exit] = [:exit_header] + seqline.actions[:enter] = [:enter] + seqline.actions[:exit] = [:exit_seqline] + record.actions[:exit] = [:exit_record] + trailing_record.actions[:exit] = [:exit_record] + + Automa.compile(fasta) +end; +``` + +The machine is now a bit more complicated. But who cares, it's automatically generated. Look how easy it was to generate! + +```julia +display_machine(machine) +``` + +![svg](/assets/posts/automa1/automa_tutorial_47_0.svg) + +## Pitfall 1: Ambiguous parsers + +Besides its complexity, building parsers with Automa has some pitfalls - notably those caused by Automa transitioning state for every input byte. + +Unfortunately, it's very easy to accidentally create a machine that can't possibly figure out what action to take when looking only at one byte at a time. The following simple machine will not compile (on the master branch of Automa). + +```julia +bad_machine = let + left = re"Turn left!" + right = re"Turn right!" + left_or_right = left | right + + left.actions[:enter] = [:turn_left] + right.actions[:enter] = [:turn_right] + + Automa.compile(left_or_right) +end +``` + +``` +Ambiguous DFA: Input 0x54 can lead to actions [:turn_right] or [:turn_left] + + + +Stacktrace: + + [1] error(::String) at ./error.jl:33 + + [2] validate_paths(::Array{Tuple{Union{Nothing, Automa.Edge},Array{Symbol,1}},1}) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:176 + + [3] validate_nfanodes(::Automa.StableSet{Automa.NFANode}) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:195 + + [4] nfa2dfa(::Automa.NFA, ::Bool) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:104 + + [5] compile(::Automa.RegExp.RE; optimize::Bool, unambiguous::Bool) at /home/jakob/.julia/packages/Automa/sfHZ6/src/machine.jl:55 + + [6] compile(::Automa.RegExp.RE) at /home/jakob/.julia/packages/Automa/sfHZ6/src/machine.jl:55 + + [7] top-level scope at In[27]:9 + + [8] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091 +``` + +Automa refuse to create this FSM. Why? Well, the first byte it expects is a `T` (or `0x54`) - but there is no way of knowing whether it's entering `left` or `right` when it sees that byte, and these two patters have conflicting actions! If they had the same actions, there would be no problem. + +This situation is highly artificial, but the situation happens often in real life. Here's a very subtle change to one of the previous parsers: + +```julia +bad_machine = let + # Define SimpleFasta syntax + header = re">[a-z]+" + seqline = re"[ACGT]+" + sequence = seqline * re.rep(re"\n" * seqline) + record = header * re"\n" * sequence + fasta = re.rep(record * re"\n") + + # Define SimpleFasta actions + header.actions[:enter] = [:enter] + header.actions[:exit] = [:exit_header] + seqline.actions[:enter] = [:enter] + seqline.actions[:exit] = [:exit_seqline] + record.actions[:exit] = [:exit_record] + + Automa.compile(fasta) +end; +``` + +``` +Ambiguous DFA: Input 0x0a can lead to actions [:exit_seqline, :exit_record] or [:exit_seqline] + + + +Stacktrace: + + [1] error(::String) at ./error.jl:33 + + [2] validate_paths(::Array{Tuple{Union{Nothing, Automa.Edge},Array{Symbol,1}},1}) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:176 + + [3] validate_nfanodes(::Automa.StableSet{Automa.NFANode}) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:195 + + [4] nfa2dfa(::Automa.NFA, ::Bool) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:104 + + [5] compile(::Automa.RegExp.RE; optimize::Bool, unambiguous::Bool) at /home/jakob/.julia/packages/Automa/sfHZ6/src/machine.jl:55 + + [6] compile(::Automa.RegExp.RE) at /home/jakob/.julia/packages/Automa/sfHZ6/src/machine.jl:55 + + [7] top-level scope at In[28]:16 + + [8] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091 +``` + +After a `seqline`, when encountering a newline, there is no way of knowing whether this marks the end of a record or whether it continues at the next line. Automa can't look ahead, it has to make a decision at every byte. + +Here, the solution is to move the newline from the definition of `fasta` to that of `sequence`. That way, the newline functions as a kind of one-byte lookahead - if the byte after the newline is a `>`, it knows the record is complete. + +In general, encountering situations like this is usually a sign that the parser is badly built - or that the format is. You can usually resolve it by using single-byte lookahead like above. If not, it is possible to optionally disable the check for ambiguous actions by passing a keyword to the `Automa.parse` function. But beware that this may lead to absurd results. + +## Pitfall 2: No recursively defined patterns + +Some formats are naturally recursive. The [Newick format](https://en.wikipedia.org/wiki/Newick_format), for example, defines “subtree” in terms of “internal”, which is defined in terms of “branchset”, defined in terms of “branch” which is defined in terms of… “subtree”. + +Something like that will not work Automa: + +```julia +simple_newick = let + name = re"[a-z_]" + clade = name | (re"\(" * cladeset * ")") + cladeset = clade * re.rep(re"," * clade) + Automa.compile(cladeset * re";") +end + +``` + +``` +UndefVarError: cladeset not defined + + + +Stacktrace: + + [1] top-level scope at In[29]:3 + + [2] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091 +``` + +Because, in general, you can't refer to objects in Julia that have not yet been defined. Worse, even if the syntactical challenge was solved, recursive patterns usually only make sense if you have lookahead. Newick files, for example, simply _can't_ be parsed by FSMs, because every time you see an open parenthesis, you need to make sure there is a closing one further in the file, and this requires lookahead that can't be resolved by parsing one byte at a time. + +Luckily, because Automa can execute arbitrary Julia code, we can have the FSM manipulate a stack and turn the FSM into a _pushdown automaton_, which can handle formats like Newick. It does require a little more manual fiddling, and is less elegant: + +```julia +simple_newick = let + name = re"[a-z_]+" + cladestart = re"\(" + cladestop = re"\)" + cladesep = re"," + nodechange = cladestart | cladestop | cladesep + newick_element = nodechange * re.opt(name) + tree = re.opt(name) * re.rep(newick_element) * re";" + + cladestart.actions[:enter] = [:push] + cladestop.actions[:enter] = [:pop] + cladesep.actions[:enter] = [:pop, :push] + + Automa.compile(tree) +end + +actions = Dict( + :push => quote + level -= 1 + end, + :pop => quote + iszero(level) && error("Too many closing parentheses") + level += 1 + end +); +``` + +```julia +@eval function parse_newick(data::Union{String,Vector{UInt8}}) + level = 0 + $(Automa.generate_init_code(context, simple_newick)) + p_end = p_eof = lastindex(data) + $(Automa.generate_exec_code(context, simple_newick, actions)) + + iszero(cs) || error("failed to parse on byte ", p) + iszero(level) || error("Too many opening parentheses") +end; +``` + +And it sort of works: + +```julia +println("Does this parse? ", parse_newick("(hello,hi);")) +println("Does this parse? ", parse_newick("(hello,hi)(;")) +``` + +``` +Does this parse? true + + + +Too many opening parentheses + + + +Stacktrace: + + [1] error(::String) at ./error.jl:33 + + [2] parse_newick(::String) at ./In[31]:8 + + [3] top-level scope at In[32]:2 + + [4] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091 +``` + +Here, I needed to manually keep track of the level of nesting. In fact, I would have to keep track of more stuff to disallow inputs like `();`, removing some of the point of Automa - namely, that it is automatic. + +In the next part of this tutorial, I will show how to use Automa to create honest-to-God parsers which integrate with the BioJulia ecosystem and can work on streamed data. + +## Optimizing + +Automa's parsers are pretty fast. To create hand-written parsers of comparable speeds, you need to microoptimize every operation, which is annoying. That being said, for actually loading parsed files to be fast, you need to optimize the user-defined actions in the actions dictionary, too. + +How fast is our un-optimized Fasta parser already? Let's test it on some data and find out. I'll make 50k sequences with 2k base pairs each, for a total of 100 MB data. + +Remember to re-run the block of code where the `parse_fasta` function is defined since we changed the machine. + +```julia +# Create 50k records with 2kbp each +function generate_data() + open("/tmp/fasta.fna", "w") do file + for seq in 1:50000 + println(file, '>', join(rand('a':'z', 16))) + for line in 1:20 + println(file, join(rand("ACGT", 100))) + end + end + end +end +generate_data() +``` + +```julia +function parsedata() + open("/tmp/fasta.fna") do file + parse_fasta(DNAAlphabet{2}, read(file)) + end +end; +``` + +```julia +parsedata(); +@time parsedata(); +``` + +``` + 0.330489 seconds (200.04 k allocations: 138.861 MiB, 4.15% gc time) +``` + +Alright! It does about 300 MB/s on my laptop. Not bad! I'd say for most applications, this speed is more than sufficient. + +But this is Julia. We want to be able to optimize the crap out of it. So let's optimize the actions: + +```julia +actions = Dict( + :enter => :(mark = p), + + # Create string with only one copy of the data. + :exit_header => :(header = unsafe_string(pointer(data, mark + 1), p - mark - 1)), + + # Only resize buffer if it's too small, else just keep track of how many bytes are used. + :exit_seqline => quote + N = p - mark + length(seqbuffer) < filled + N && resize!(seqbuffer, filled + N) + copyto!(seqbuffer, filled+1, data, mark, N) + filled += N + end, + + # Use `copyto!` to only encode data directly from data vector into sequence + # note this requires the latest versions of BioSequences. + :exit_record => quote + sequence = copyto!(LongSequence{A}(filled), 1, seqbuffer, 1, filled) + record = FastaRecord(header, sequence) + push!(records, record) + filled = 0 + end, +); +``` + +If we want to optimize, we also need to use the fastest `CodeGenContext`. We use the `:goto`\-generator. This creates machine code using `@goto`\-statements, which creates very long and completely unreadable code - but it's fast. Also, who cares if it's hard to read. It's machine-generated code. We disable the FSM's boundschecks when accessing the `data` vector - since we don't manipulate the position `p` manually, we are confident it will not go out of bounds. And we allow the code generator to unroll loops: + +```julia +context = Automa.CodeGenContext(generator=:goto, checkbounds=false, loopunroll=4); +``` + +We also need to modify the `parse` function because we use a new variable called `filled` and need to initialize it. + +```julia +@eval function parse_fasta(::Type{A}, data::Union{String,Vector{UInt8}}) where {A <: Alphabet} + mark = 0 + records = FastaRecord{A}[] + header = "" + sequence = LongSequence{A}() + seqbuffer = UInt8[] + filled = 0 + + $(Automa.generate_init_code(context, machine)) + p_end = p_eof = lastindex(data) + $(Automa.generate_exec_code(context, machine, actions)) + + iszero(cs) || error("failed to parse on byte ", p) + return records +end; +``` + +```julia +parsedata(); +@time parsedata(); +``` + +```! +0.162113 seconds (150.04 k allocations: 133.520 MiB, 7.90% gc time) +``` + +Okay, we're at slightly above 600 MB/s. Profiling confirms nearly all time is spent encoding the DNA sequences to `LongSequence`. We can make it faster still by not storing the data as a `LongSequence`, and instead make it a "lazy" object that only constructs the sequence upon demand. Even further, we could avoid heap-allocating each sequence individually. But these optimizations do not pertain directly to Automa, and I will leave them here. diff --git a/docs/src/posts/biojl.md b/docs/src/posts/biojl.md new file mode 100644 index 0000000..e5b4067 --- /dev/null +++ b/docs/src/posts/biojl.md @@ -0,0 +1,47 @@ ++++ +using Dates + +date = Date("2020-01-23") +author = "sabrina" ++++ + +# Bio.jl is old and deprecated + +![biojulia logo](/assets/biojulia-logo1.png) + +Hi there! There have been incidents of confusion where newer users have tried to install and run an old and deprecated BioJulia package called `Bio.jl`, or they have not known which package(s) they need to install in order to start working. + +So I'd like to take the opportunity to clear this situation up and perhaps put out a clearer explanation, of why Bio.jl exists when there are other packages with overlapping functionality. + +Bio.jl was the first package BioJulia produced, at a time when the scale of the project meant it made sense to have a single module - Bio - with several submodules + + `Seq`, `Align`, `Phylo`, `Intervals`, `Structure`, `Var`, `Services`, `Tools`. + +Bio has existed since very early days - or versions - of julia as well. + +Eventually there came a point where datatype and algorithm specific packages made more sense than a single monolithic repository. + +And so the package got split into many: + +- `Bio.Seq` became [`BioSequences.jl`](https://github.com/BioJulia/BioSequences.jl/) +- `Bio.Align` became [`BioAlignments.jl`](https://github.com/BioJulia/BioAlignments.jl/) +- `Bio.Intervals` became [`GenomicFeatures.jl`](https://github.com/BioJulia/GenomicFeatures.jl/) +- `Bio.Structure` became [`BioStructures.jl`](https://github.com/BioJulia/BioStructures.jl/) +- `Bio.Var` became [`GeneticVariation.jl`](https://github.com/BioJulia/GeneticVariation.jl/) +- `Bio.Phylo` became [`Phylogenies.jl`](https://github.com/BioJulia/Phylogenies.jl/) +- `Bio.Services` became [`BioServices.jl`](https://github.com/BioJulia/BioServices.jl/) +- `Bio.Tools` became [`BioTools.jl`](https://github.com/BioJulia/BioTools.jl/) + +`Bio.jl` then basically persisted as a convenience wrapper around those packages, so that they could be installed with a single command and were distributed set to compatible versions. + +With julia v0.7/v1.0 and the new `Pkg` and Project system the need for `Bio.jl` to provide that functionality became largely moot. + +## So what should you do? + +As of today, `Bio.jl` is available for installation, but mostly just to prevent old scripts and projects breaking. + +It is not longer recommended that you use `Bio.jl`. Instead you should start a julia project and add just the BioJulia packages you want to use. For a brief description on how to do this, check out the getting started page. + +Happy hacking. + +Sabrina. diff --git a/docs/src/posts/cajun-kevin.md b/docs/src/posts/cajun-kevin.md new file mode 100644 index 0000000..00f6d33 --- /dev/null +++ b/docs/src/posts/cajun-kevin.md @@ -0,0 +1,32 @@ ++++ +using Dates +date = Date("2024-04-21") +title = "BioJulia at CAJUN" +author = "Kevin Bonham" ++++ + +# BioJulia at Cajun + +This Tuesday, I (Kevin) will be giving a talk for +the [Cambridge Area Julia Users Network][cajun] +on "Doing Biology in Julia". + +[See here][event] for event details +[and here][slides] for the slides. +If you're in the area, hope to see you there! + +~~~ + +~~~ + +[cajun]: https://www.meetup.com/julia-cajun/ +[event]: https://www.meetup.com/julia-cajun/events/299773552/ +[slides]: https://gitlab.com/kescobo/cajun_bio + + diff --git a/docs/src/posts/hardware.md b/docs/src/posts/hardware.md new file mode 100644 index 0000000..3ddf9c9 --- /dev/null +++ b/docs/src/posts/hardware.md @@ -0,0 +1,16 @@ ++++ +using Dates +date = Date("2022-09-04") +title = "What scientists must know about hardware to write fast code" +author = "Jakob Nybo Nissen" ++++ + + +~~~ + +~~~ + +# What scientists must know about hardware to write fast code + + +{{ insert posts/hardware/pluto.html assets }} diff --git a/docs/src/posts/index.md b/docs/src/posts/index.md new file mode 100644 index 0000000..4f69a32 --- /dev/null +++ b/docs/src/posts/index.md @@ -0,0 +1,3 @@ +# Posts + +- [Hardware](/posts/hardware) diff --git a/docs/src/posts/seq-lang.md b/docs/src/posts/seq-lang.md new file mode 100644 index 0000000..287bc5c --- /dev/null +++ b/docs/src/posts/seq-lang.md @@ -0,0 +1,115 @@ ++++ +using Dates + +title = "On the performance and design of BioSequences compared to the Seq language" +date = Date("2020-01-23") +author = "Jakob Nybo Nissen, Sabrina Ward" ++++ + +# On the performance and design of BioSequences compared to the Seq language + +![](/assets/posts/seq-lang/featured_hu673fdf9bf6c03bbd2130cc0e6402b2ac_100218_720x0_resize_lanczos_2.png) + +## Introduction + +In October 2019, a paper was published in Proceedings of the ACM on Programming Languages, introducing a new language for bioinformatics called [Seq](https://dl.acm.org/doi/10.1145/3360551). + +In it, the authors rightly recognize that the field of bioinformatics is in need of a high-performance, yet expressive and productive language. They present Seq, a domain specific compiled language, with the user friendliness of Python, the performance of C, and bioinformatics-specific data types and optimisations. As Julians, we consider their goal to be noble and well worth pursuit. However, they also presented a series of benchmarking results in which they claim the performance of Seq code is far greater than equivalent code written in other languages, including C++ and Julia. + +Of course, benchmarking between languages is a tricky thing. Different languages present different syntax, tools and idioms to the programmer, such that what is efficient and natural in one language may be inefficient and clumsy in another. When benchmarking different languages, therefore, it is important to write code that is idiomatic in each language before comparing the code in terms of performance, readability or ease-of-writing. Disagreements about benchmarks between languages often come down to disagreements of whether the code compared are equivalent - if they aren’t, comparisons may be meaningless. + +For example, in the majority of the benchmarks between Seq and Julia in the Seq paper, the DNA sequences of Seq are represented by a dedicated sequence type, whereas the sequences in Julia are represented by strings. As the Seq type is crafted specifically for efficient DNA processing, and Julia’s strings are crafted for efficient generic text processing, it is no surprise that Seq is much faster in these benchmarks. Therefore, these particular benchmarks are obviously misleading, and we will not discuss them further here. + +The Seq authors, to their credit, realize this and include comparison between Seq and Julia code that uses BioSequences, a package of the BioJulia organization. This package contains custom, efficient types for exactly the type of work they are benchmarking, and so here, the code is equivalent and the comparison reasonable. Even when comparing against BioSequences, the Seq authors find that Seq offers a large speed advantage. As a core developer and long-time user of BioJulia, respectively, we were puzzled by these results. BioJulia is highly optimised. Could Seq really be that much faster? Perhaps we could learn something from Seq? + +## Recreating the benchmarks + +The first thing to do was to see if the results in the paper could be replicated. The Seq authors have made a real effort to allow easy replication of their results, as they have released a virtual machine with all necessary code and software to run their benchmarks out of the box. Only their BioJulia code was missing, which they promptly provided upon request. So we spun up their VM, and recreated their benchmarks. For details on the benchmarking procedure, see the last section of this post. + +We note that the provided version of Seq provides wrong answers to the benchmarks on several counts. First, kmers containing ambiguous nucleotides are not skipped during iteration, leading to simpler and faster (but by convention, wrong) code. Second, the middle base is not complemented during reverse-complementation of odd-length sequences. Third, the reverse-complement of ambiguous nucleotides are wrong, as e.g. K is complemented to N rather than the correct answer (M). Fourth, we can make little sense of what the result returned by their CpG benchmarking code actually means. However, these small blemishes could easily be fixed by the Seq authors with little or no performance penalty, so they are not of great importance here. + +The results of our recreation are seen in the plot below. We were happy to see we could recreate their performance difference, seeing nearly the same performance difference they found. + +![figure-1](/assets/posts/seq-lang/fig1.png) **Figure 1. Running time of BioJulia (blue) versus Seq (red). We could recreate the authors findings and found Seq to be much faster than BioJulia for the three provided benchmarks. The barplot shows shows the mean +/- stddev time of 5 consecutive runs.** + +## Improving the benchmarked code + +As a long time developers and users of BioJulia, we feel qualified to judge whether or not the Julia code used for the benchmarks is idiomatic or not, and whether or not BioJulia was being correctly used. Non-idiomatic Julia is the most common source of complaints when new Julia users benchmark Julia code and find the performance disappointing. This often happens because new users code in a way that carries little penalty in languages like R and Python, but which is difficult for Julia’s JIT compiler to optimise. So, a natural starting point was to check their Julia code for inefficiencies. + +However, the Seq author’s Julia benchmarks were well implemented. Only the code for the CpG benchmark could be improved by fixing an error which resulted in incorrect answers, and by computing the result in a single pass of the input sequence. The two other benchmarks only needed minor tweaking to be idiomatic. These minor changes did not improve the timings of BioJulia markedly (**Figure 2**). + +![figure-2](/assets/posts/seq-lang/fig2.png) **Figure 2. Improving the Julia code of the Seq paper’s benchmarks (green series), did not change the results very much. The barplot shows shows the mean +/- stddev time of 5 consecutive runs.** + +## Explaining the difference in performance + +It seems that Seq really is much faster than BioJulia, at least for the benchmarked tasks, and we wanted to know why. So we profiled their BioJulia code to see what BioJulia was taking its sweet time doing. The results for the three benchmarks are shown below in **Figure 3**. + +![figure-3](/assets/posts/seq-lang/fig3.png) **Figure 3. Barplots showing the fraction of time BioJulia benchmarking code was spending doing various sub-tasks, as determined by the built-in Julia Profiler tool.** + +Surprisingly, **Figure 3** reveals that only a small fraction of the time is spent doing what the benchmark nominally measures. For example, the RC benchmark presumably should benchmark reverse-complementation (RC’ing) of sequences, but BioJulia spends less than 10% of the time actually RC’ing. Likewise, checking symmetric kmers and kmer iteration in the 16-mer benchmark is relatively insignificant time-wise. We implemented Seq’s algorithm for RC’ing kmers as described in their paper, but found no difference in performance to BioJulia’s approach, even when benchmarking only the time spent RC’ing. + +In fact, **Figure 3** shows that for all benchmarks, most of the time is spent building instances of the BioSequence type that BioSequences.jl uses to represent long DNA, RNA and Amino Acid sequences. To find the source of the performance difference between Seq and BioSequences, then, it is necessary to take a small detour into the internals of BioSequences and Seq. + +## How to represent DNA sequences in software + +DNA consists of four nucleotides called A, C, G and T. In some contexts, a nucleotide may instead be one of 16 [IUPAC](https://en.wikipedia.org/wiki/Nucleic_acid_notation) defined symbols. Hence, one nucleotide may be represented in either two bits or four bits. In BioSequences, DNA is stored in a compact format, where nucleotides are encoded to 2 or 4-bit encodings in an integer array. This representation comes with a few advantages: + +1. The encoding and decoding step implicitly validates that the input data is meaningful DNA data instead of some random string. Therefore, when given a BioSequence, the user can be confident that the underlying data actually represents valid DNA. +2. Encoding saves 4x or 2x on RAM. Speed is important in bioinformatics precisely because of our large datasets, and this also puts a premium on RAM, making these savings worthwhile. +3. The encoded representation of DNA makes biological operations easier and more efficient. Complementation of a 2-bit DNA sequence, for example, consists only of inverting the encoded bits. Converting between DNA and RNA includes only changing the metadata. + +The encoding/decoding also comes with a disadvantage, as it takes more time than just accessing raw bytes. This tradeoff is reminiscent of the pros and cons of a boolean vector versus a bit-vector. As the benchmarks here consists of very simple, fast operations on many small sequences that are read in as text, encoding time dominate. + +In contrast, Seq represents DNA sequences as a byte array with the underlying data simply being the bytes of the input string. Constructing this type is obviously much faster than a BioSequence since it can wrap a string directly, but the RAM consumption is 2 or 4 times higher. Remarkably, Seq appears to do no input validation at all, as we confirmed by re-running the benchmarks with corrupted data. BioSequences immediately crashed with an informative error message, whereas Seq happily produced the wrong answer with no warnings. + +So it appears the primary reason BioJulia code is slower than Seq code in these three benchmarks is that BioSequences.jl is doing important work for you that Seq is not doing. As scientists, we hope you value tools that spend the time and effort to validate inputs given to it rather than fail silently. + +## Implementing Seq-like types in Julia + +BioSequences may be more memory efficient and safer to use, we still verified the finding of the Seq authors: Seq really is much faster than BioSequences. That surprised us. Was Seq so fast because of amazing software engineering in the language itself, or simply because so much time is lost in BioSequence’s encoding and decoding? We decided to mimic Seq in Julia by implementing DNA sequences and kmer types in Julia with the same data representation Seq uses. Our module, [SeqJL](https://github.com/jakobnissen/SeqLangBenchmarks) turned out to be simple to write, taking less than 100 lines of code. We note that BioSequences could easily have been written this way, and intentionally isn’t. + +Figure 4 shows the performance of our SeqJL code (**Figure 4**, red), where it is significantly faster than Seq, except in the RC benchmark (**Figure 4**, orange). We found that even further speed improvements could be found by buffering input and output using the BufferedStreams.jl package, but we did not use that in the benchmarks. + +![figure-4](/assets/posts/seq-lang/fig4.png) **Figure 4. Timing a Julia implementation of the data types in Seq (red) resulted in timings which beat those achieved by the Seq code (orange). The barplot shows shows the mean +/- stddev time of 5 consecutive runs.** + +## Learning from Seq + +Being challenged often teaches valuable lessons, and the challenge Seq presented to BioJulia is no exception. We were surprised to see a bioinformatics workload where the encoding step of BioSequences proved to be a bottleneck, as we have always believed it to be very fast. We did not expect our simple SeqJL code to outperform BioSequences by such a large factor in these benchmarks. + +In most realistic workloads, sequences are subject to more intense processing, which makes the speed of encoding and IO operations less important in comparison. In addition we note that BioJulia provides optimal buffered, state machine generated parsers for many file formats like FASTA and FASTQ, but they were not explored in this work as no benchmark involved them. BioJulia also offers ReadDatastores.jl, which implements indexed disk-backed collections of sequences, stored in the BioSequences encodings. These data-stores mean commonly used sequence datasets like sequencing reads stored in FASTQ files need to be encoded only once, and then the data-store can be reused for a great performance benefit. Nonetheless, the impressive speed of Seq over BioSequences in these benchmarks made us reconsider the need for much faster string/sequence conversion and printing. As a result of this challenge, we have subjected BioSequences to [a performance review](https://github.com/BioJulia/BioSequences.jl/issues/86), optimising a dozen code sections that was causing slowdowns. To benefit from these improvements, users should install BioSequences version 2.X from the BioJuliaRegistry. + +We were happy to discover that these changes made a big difference. With the updates, BioSequences rivals Seq in speed while keeping its advantages of a lower memory footprint and doing data validation. + +![figure-5](/assets/posts/seq-lang/fig5.png) **Figure 5. The newest version of BioSequences (purple) comes with performance improvements in encoding, decoding and IO, making it 3-4 times faster than BioSequences v 1.1.0 (green) for these benchmarks, and rivaling Seq (orange). The barplot shows shows the mean +/- stddev time of 5 consecutive runs.** + +## Our take away impressions + +### Jakob + +I wholeheartedly agree with Seq’s goal of bringing a performant language to the masses, so to speak. I also applaud Seq’s authors for their efforts in providing reproducible results by sharing their code and environment, and for their efforts to compare Seq to efficient, proper Julia code. Ultimately, the speed difference between BioSequences and Seq comes down to a design decision in the implementation of the sequence type. I happen to think BioSequences made the right call by encoding the sequences, and Seq made the wrong one. + +More broadly I think Seq brings little of value to bioinformatics. Our simple SeqJL implementation shows that Julia can achieve what Seq aims to do with even higher performance and, I would argue, even more elegant, reusable and concise code. In contrast, Seq comes with serious drawbacks. Beside DNA sequence processing, a typical bioinformatics workflow may include reading CSV files, feature extraction, doing statistical tests, plotting data and more. Being a domain specific language, Seq has zero chance of having packages for all these tasks available. In contrast, because BioSequences is simply a package in pure Julia, a user of BioSequences have all the tools of the broader Julia ecosystem available. + +More realistically, Seq could survive by providing interoperation with other languages. But madness lies that way. In the bad old days, in a few hours of work, a bioinformatician would use awk to edit text files, pass them through Perl one-liners, run it through Python data processing before graphing using ggplot, all these languages duct-taped together using Bash. Workflows of that kind were inefficient, brittle, and required the programmer to learn a handful of different domain specific languages. Surely that path, the path that Seq shows us, must lie behind us. + +### Ben + +I can only echo and agreement with Jakob in applauding Seq’s authors efforts in trying to bring a performant programming language to life, and also applaud their efforts in providing reproducible results. + +That said, before playing with these benchmarks it’s fair to say I was fairly skeptical of the idea that what bioinformatics really needs is a domain specific language. When I consider critical problems the field faces, my mind goes to problems such as sometimes undocumented, sometimes poorly understood assumptions about biological systems hardcoded into tools (e.g. assembly pipelines that assume levels of ploidy or genome characteristics). I think of experiments that start with a single reference genome, and run pipelines of heuristic after heuristic, each with its own slew of parameters and biases. + +In other words the greatest gains are to be made by improving how we do things, not how fast we do them. Everyone wants speed, that’s why so many Big Data frameworks exist. Indeed the Seq developer’s intention of having a language that is Pythonic in user friendliness, and speed approaching C, is also one of the main reasons Julia exists today. After Julia 1.0 was released, as a core developer of BioJulia, I considered the argument as to whether or not Julia is performant to be settled. It is. + +Now the question of whether Julia is fast enough for bioinformatics is settled. I think the current goal of BioJulia is to provide clear, flexible, easy to use frameworks for doing bioinformatics analyses in a robust/reproducible, transparent manner, using clear concepts. + +After this review I think I would echo the same same conclusions as Jakob: In brief, the results in the paper can be explained largely due to our design choices in BioSequences.jl, which we maintain were the right calls. The exercise has been valuable, as it has resulted in several pull requests that improve on the performance of the string conversions and sequence encoding BioSequences.jl does; whilst we think the computational effort is justified, we also want it to be faster if it can be. Without Seq’s benchmarks to prompt us to examine this more closely, those those improvements might not have been made for a long time, if at all. + +## Benchmarking procedure + +### Benchmarking environment + +We ran the code in the Vagrant [virtual machine provided](https://zenodo.org/record/3374036) by the authors. In the virtual machine, all software needed to reproduce the benchmarks was there, except the Seq author’s BioJulia code, which [was provided upon request](https://github.com/seq-lang/benchmarks/tree/master/paper/idiomatic). The code was run on a 2018 MacBook pro using Julia v 1.0.3 and BioSequences v1.1.0. We could not determine the version of Seq used in the VM. + +### Benchmarking method + +Due to a small virtual disk size in the VM, the whole dataset could not be downloaded, so we generated input data instead by taking the provided small test dataset HG00123_small.txt, and concatenating it to itself 16 times for a total of 2^24 lines, 1.3 GiB. To benchmark, we ran each script 5 times consecutively. For Seq, we used the idiomatic Seq code "seq-id", and did not include compilation time. For Julia, we included JIT compilation (which we estimated to be ~2 seconds for BioJulia benchmarks, and somewhat less for SeqJL benchmarks), but not package precompilation time. Note that unlike the Seq authors, we ran Julia with default optimization level and boundschecks enabled, as these are the most common settings to run Julia in. From f28312ea8a4d3187510650356d28c27237d2c4b9 Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Fri, 21 Feb 2025 11:00:11 -0500 Subject: [PATCH 10/11] Update liveServer instructions --- README.md | 20 ++++++++++++++++---- docs/make.jl | 6 ++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 526df56..1d04f04 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,26 @@ similar to [SciMLDocs](https://github.com/SciML/SciMLDocs) (see the production p The rendered BioJuliaDocs site, for testing purposes, is published online using GitHub Pages at [biojulia.dev/BioJuliaDocs](https://biojulia.dev/BioJuliaDocs). A GitHub action rebuilds the site on every successful pull request. -To deploy the site locally: +To deploy the site locally, open two separate julia processes, +and activate the "docs/" project. +Then, in the first, run: + ```julia # Make sure you are within or are pointing to the the docs/ folder -using Documenter, LiveServer -include("make.jl") -serve(dir="build") +using LiveServer +servedocs(; foldername=pwd()) ``` +And in the other, run: + +```julia +using DocumenterVitepress + +DocumenterVitepress.dev_docs("build"; md_output_path="") +``` + +Open the LocalHost Url spawned by the vitepress process + ## Contributing We appreciate contributions from users/members of the BioJulia commmunity diff --git a/docs/make.jl b/docs/make.jl index dc1eb78..1bc63e6 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,12 +5,14 @@ makedocs( sitename = "BioJulia Unified Docs", authors = "Michael Persico", modules = Module[], - clean = true, + clean = false, doctest = false, draft = false, # TODO expand (https://github.com/SciML/SciMLDocs/blob/0fa5c9c43cf768588124861e76c7854e671ad9d7/docs/make.jl#L29C1-L29C63) format = DocumenterVitepress.MarkdownVitepress( - repo = "https://github.com/BioJulia/BioJuliaDocs" + repo = "https://github.com/BioJulia/BioJuliaDocs", + md_output_path = ".", + build_vitepress = false ), pages = [ "Getting Started" => [ From da8f577d3585648001fb8d557382befe8611922b Mon Sep 17 00:00:00 2001 From: Kevin Bonham Date: Fri, 21 Feb 2025 11:00:42 -0500 Subject: [PATCH 11/11] remove posts (deal with them later) --- docs/src/index.md | 6 +- docs/src/posts/automa1.md | 891 ---------------------------------- docs/src/posts/biojl.md | 47 -- docs/src/posts/cajun-kevin.md | 32 -- docs/src/posts/hardware.md | 16 - docs/src/posts/index.md | 3 - docs/src/posts/seq-lang.md | 115 ----- 7 files changed, 3 insertions(+), 1107 deletions(-) delete mode 100644 docs/src/posts/automa1.md delete mode 100644 docs/src/posts/biojl.md delete mode 100644 docs/src/posts/cajun-kevin.md delete mode 100644 docs/src/posts/hardware.md delete mode 100644 docs/src/posts/index.md delete mode 100644 docs/src/posts/seq-lang.md diff --git a/docs/src/index.md b/docs/src/index.md index dc12c0f..155c4b9 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -6,10 +6,10 @@ layout: home hero: name: "BioJulia" - text: "Unified Docs" - tagline: Doing biology with julia + text: "Doing Biology with Julia" + tagline: Unified Docs image: - src: '/assets/biojulia-logo1.png' + src: '/assets/biojulia-logo1.svg' actions: - theme: brand text: Getting Started diff --git a/docs/src/posts/automa1.md b/docs/src/posts/automa1.md deleted file mode 100644 index 198f8a1..0000000 --- a/docs/src/posts/automa1.md +++ /dev/null @@ -1,891 +0,0 @@ -+++ -using Dates -date = Date("2020-08-30") -title = "Tutorial to Automa: Part 1" -author = "Jakob Nybo Nissen" -+++ - - - -# Tutorial to Automa: Part 1 - -**Find this notebook at [https://github.com/jakobnissen//assets/posts/automa1/automa_tutorial](https://github.com/jakobnissen//assets/posts/automa1/automa_tutorial)** - -In bioinformatics, we have a saying: - -> The first step of any bioinformatics project is to define a new file format, incompatible with all previous ones. - -The situation might not be _quite_ as bad as the saying implies, but it _is_ true that we have a _lot_ of different file formats, representing the various kinds of data we work with. - -For that reason, creating file parsers is a central task in bioinformatics, and has almost become [a craft in itself.](http://biopython.org/DIST/docs/tutorial/Tutorial.html#sec14) An awful, awful craft. For anything but the simplest formats, designing robust parsers is hard, and it is difficult to know if a parser you've built is solid. Insignificant details like trailing whitespace can break a seemingly well-built parser. - -At its core, a parser is a program that checks whether some input data comforms to some format. For bioinformatics, we typically also want to load the data in the file into some data structure to work on it. The format itself is typically specified in some kind of higher-level, but unambiguous language, like [this description of the Newick format.](https://en.wikipedia.org/wiki/Newick_format#Grammar) A parser then, can be viewed as a program that: - -- Is given a format specified in a high-level “language”, e.g. “a leaf in the Newick format consist of only a _name_, which is formed from the alphabet “a-z, A-Z and \_"", and -- Checks whether some input follows that format using relatively low-level instructions, e.g. checking whether the following bytes until the next `(`, `)`, `,` or `;` match the pattern `[A-Za-z_]` - -The central job of a parser is then to act as a _translator_ between different abstraction levels: The format is specified in a high-level language, but the actual data processing must happen at a lower level language. - -When described like that, parser generation seems quite analogous to code compilation, and begins too look like a _machine's_ job, not a human's. Machines are fast and accurate, and do not make oversights or mistakes - exactly the characteristics you want when making a parser. Let's leave the machine tasks to the machines; we humans ought to put our effort into what we do best: Specifying the formats themselves. - -In this tutorial, I will introduce Automa, a Julia package for creating parsers. Actually, when reading this you might be able to tell that Automa solves a problem slightly more general than just creating parsers, but creating parsers is what we will use it for in this tutorial. Automa is not an easy package to use; it is complex and a little opaque, but it's worth all the effort and more. Parsers generated by Automa have several advantages over human-made parsers: - -- They are failsafe: Any deviation of the input from the specified format, no matter how trivial, will cause it to fail. Therefore, they are much more reliant than human-written parsers. -- They are easy to change. You can often easily change details in the input format, such as allowing whitespace, with minimal changes to your code, -- They are quite fast, with Automa-code often being faster than even optimized human-crafted parsers. - -In this first part of the tutorial I will show how to create parsers from data loaded into memory in order to highlight Automa itself. In the second part, which I will release at a later date, I will show how to create a proper BioJulia reader and writer for a file format. - -## Our format - -For our example, let us begin with a simlified version of the FASTA format - we can call it “SimpleFasta”. Our format will be defined as something that looks like this: - -```fasta ->first -TGATAGTAGTCGTGTGATA ->second -AGGACCCAATTATCGGGGTAA -``` - -I.e. - -- A SimpleFasta file is a sequence of zero or more _records_ -- A _record_ consists of _header_ \* newline \* _sequence_ \* newline, where "\*" signifies concatenation -- A _header_ consists of `>` followed by one or more characters from the alphabet a-z -- A _sequence_ consists of one or more chatacters from the alphabet A, C, G or T. - -We can visualize a hypothetical SimpleFasta parser using a simple flowchart - note: You need to have `graphviz` installed to be able to run the code below. - -```julia -s = """digraph { -graph [ rankdir = LR ]; -begin [ shape = circle ]; -begin -> header; -header [ shape = circle ]; -header -> sequence; -sequence [ shape = circle ]; -sequence -> end; -end [ shape = circle ]; -sequence -> header; -begin -> end; -} -""" -function display_machine() - write("/tmp/fasta_machine.dot", s) - run(`dot -Tsvg -o /tmp/fasta_machine.svg /tmp/fasta_machine.dot`) - open("/tmp/fasta_machine.svg") do file - display("image/svg+xml", String(read(file))) - end -end; -``` - -```julia -display_machine() -``` - -![svg](/assets/posts/automa1/automa_tutorial_2_0.svg) - -After the beginning of the file, we expect to see a header. Next, we move to the sequence. From there, we can either reach the end of the file, or loop back to another header. Alternatively, in the case of an empty file, we may move from the beginning of the file to the end immediately without any headers or sequences. We consider an empty file to also be specification-compliant. - -Note that this simple flowchart describes any _valid_ SimpleFasta format. But if, for example, a file had two consecutive header lines, there is no path we can take through the flowchart from “begin” to “end” which describes the file, and we can tell that the input did not conform to the format. - -The circles marked “begin”, “header”, “sequence” or “end” are what we call the four _states_. Because the parser shown in the diagram has a fixed list of possible states that it changes between, we call the parser a _finite state machine_ (FSM), or _finite state automaton_ (FSA). - -The flowchart above doesn't do a very good job of describing the FSM that our parser is, because it doesn't tell you _how_ the machine transitions between states. The state _transitions_ are what actually defines the format. For example, we know we are transitioning to a header when we see a `>` symbol - that is, in a way, what _defines_ the header state. - -In the flowchart below, the arrows signifying transitions between states are marked with the input character(s) that causes the FSM (our parser) to transition, written in a [regex-like](http://regexr.com) notation. For example, the transition from a header to a sequence is defined by a `\n` followed by one of the characters in `[ACGT]`. “EOF” signifies end of file. Note also that some states have transitions leading to itself. For example, when in the “header” state, the FSM may continue to read characters in `a-z` and stay in the “header” state. - -```julia -s = """digraph { - graph [ rankdir = LR ]; -begin [ shape = circle ]; -header [ shape = circle ]; -sequence [ shape = circle ]; -end [ shape = circle ]; - -begin -> header [ label = ">[a-z]" ]; -header -> header [ label = "[a-z]"]; -header -> sequence [ label = "\\\\n[ACGT]" ]; -sequence -> sequence [ label = "[ACGT]" ]; -sequence -> header [ label = "\\\\n>" ]; -sequence -> end [ label = "\\\\nEOF" ]; -begin -> end; -} -""" -display_machine() -``` - -![svg](/assets/posts/automa1/automa_tutorial_4_0.svg) - -How does the machine know when it's supposed to transition between states? Suppose a machine is at the beginning of a file and it begins by observing the input `>`. Is this part of a transition to the header state, or the beginning of a malformed input? - -It is certainly possible for the machine to have a _memory_ of the pattern, such that it only transitions to the “header” state once it sees the two specific inputs `>` and `[a-z]` in that order. However, we can make things much simpler by requiring the machine to make a state transition for _every single input byte_, then we don't need any memory other than what state the machine is in, which is a single integer. To still represent the same format at the flowchart above, we need to insert some extra states: - -```julia -s = """digraph { - graph [ rankdir = LR ]; - begin [ shape = circle ]; - 2 [ shape = circle ]; -1 [ shape = circle ]; -3 [ shape = circle ]; - begin -> 1 [ label = ">" ]; - header [ shape = circle ]; -1 -> header [label = "[a-z]" ]; -header -> header [ label = "[a-z]" ]; -2 -> sequence [ label = "[ACGT]" ]; -header -> 2 [ label = "\\\\n" ]; - - -sequence [ shape = circle ]; -sequence -> sequence [ label = "[ACGT]" ]; -sequence -> 3 [ label = "\\\\n" ]; -3 -> 1 [ label = ">" ]; -end [ shape = circle ]; -3 -> end [ label = "EOF" ]; -"begin" -> end [ label = "EOF" ]; -} -""" -display_machine() -``` - -![svg](/assets/posts/automa1/automa_tutorial_6_0.svg) - -The diagram above is exactly equivalent to the previous one, but this diagram makes a state transition for _every single_ input byte. All bytes cause a transition, and no transition consumes multiple bytes. For simplicity, Automa's parsers work like that. - -Note that it is always possible, given a FSM with multi-byte transitions to convert it to a FSM with single-byte transitions by just putting in more nodes. E.g. the transition from header to sequence requires two bytes, a newline and an A, C, G or T. Therefore, an intermediate note (on the illustration marked “2”) is needed. Unfortunately, the requirement of single-byte transitions limits what you can do with Automa - I'll come back to the limitations later. - -Now let's create this same FSM using Automa. - -## Introducing Automa - -```julia -# First imports -import Automa -import Automa.RegExp: @re_str -const re = Automa.RegExp; -``` - -We define the elements that make up the SimpleFasta (the header and the sequence) using `Automa.RegExp`, a subset of regular expressions. Automa's regular expressions can be manipulated with the following operations: - -Function - -Alias - -Meaning - -`cat(re...)` - -`*` - -concatenation - -`alt(re1, re2...)` - -`|` - -alternation - -`rep(re)` - -zero or more repetition - -`rep1(re)` - -one or more repetition - -`opt(re)` - -zero or one repetition - -`isec(re1, re2)` - -`&` - -intersection - -`diff(re1, re2)` - -`&bsol` | difference (subtraction) | - -`neg(re)` - -`!` - -negation - -Furthermore inside the re-strings themselves, you can use - -- groups of characters, like `[ACGT]` representing the set `{A, C, G, T}` -- ranges `A-Z` representing `'A':'Z'` (or more accurately, the _bytes_ `UInt8('A'):UInt8('Z')` -- `*`, representing zero or more repetitions of the last element, such as `[a-z]*` -- `+`, representing one or more repetitions of the last element, such as `[a-z]+` -- `?`, representing zero or one repetition of the last element, such as `[a-z]?` - -We can specify our FSM like below. We use a `let` statement only so we don't pollute global namespace with `header`, `sequence` etc. - -```julia -machine = let - # Define SimpleFasta syntax - header = re">[a-z]+" - sequence = re"[ACGT]+" - record = header * re"\n" * sequence * re"\n" - fasta = re.rep(record) - - # Compile the regex to a FSM - Automa.compile(fasta) -end; -``` - -If you have `dot` installed on your computer, you can visualize the compiled FSM. You might want to modify the paths in the function below to make it work on your computer. - -```julia -function display_machine(machine) - write("/tmp/fasta_machine.dot", Automa.machine2dot(machine)) - run(`dot -Tsvg -o /tmp/fasta_machine.svg /tmp/fasta_machine.dot`) - open("/tmp/fasta_machine.svg") do file - display("image/svg+xml", String(read(file))) - end -end; -``` - -```julia -display_machine(machine) -``` - -![svg](/assets/posts/automa1/automa_tutorial_13_0.svg) - -Yes, that looks correct! The start node here is the small point on the left. You can see one of the states are represented by a double circle. This represents an _accept state_, where the machine may stop at a valid end of input - here after each SimpleFasta record. If the machine stops at any other state, it did not complete correctly. In other words, state “1” here doubles as the “end” state. - -With this parser we can read a SimpleFasta file and determine if it conforms to the specification. In Automa, we do this by having our machine create Julia code in the form of a Julia expression (of type `Expr`), which we can then use to create a function using metaprogramming. - -First, we need an `Automa.CodeGenContext`, an object which contains the options for code generation. For now, we don't worry about the settings and just make a default context object: - -```julia -context = Automa.CodeGenContext(); -``` - -Then, we use two functions to generate code: - -- `Automa.generate_init_code(::CodeGenContext, ::Machine)` creates the Julia code needed to initialize the parsing of the given FSM. -- `Automa.generate_exec_code(::CodeGenContext, ::Machine, ::Dict{Symbol, Expr})` creates the Julia code needed for the main loop of the running parser. Here, the `Dict` is an _action dict_, which may contain arbitrary Julia code that the parser executes while parsing. We need that action dict later to make our parser do something useful - but for now, we simply want to create _a_ parser, not necessarily a _useful_ one, so we just use an empty dict. We will come back to the action dict later. - -Let's have a look at these functions: - -```julia -Automa.generate_init_code(context, machine) -``` - -``` -quote - #= /home/jakob/.julia/packages/Automa/sfHZ6/src/codegen.jl:94 =# - p::Int = 1 - #= /home/jakob/.julia/packages/Automa/sfHZ6/src/codegen.jl:95 =# - p_end::Int = 0 - #= /home/jakob/.julia/packages/Automa/sfHZ6/src/codegen.jl:96 =# - p_eof::Int = -1 - #= /home/jakob/.julia/packages/Automa/sfHZ6/src/codegen.jl:97 =# - cs::Int = 1 -end -``` - -Besides the comments, the init code seems to define four integers. What to they mean? - -Automa works by reading the data byte by byte. When doing this, the data is represented in the function as an `AbstractVector{UInt8}` - let us call that `data`. `p` represents the index of `data` that the parser is currently reading from. `p_end` represents the last position of the data in `data`. Because `data` may just be a small, buffered part of a much larger file being parsed, `p_eof` represents the index of actual end of input. Last, `cs` is short for “current state”, and is an integer representing the state of the FSM. You can see that sensibly, it is initialized at state 1, and so, by looking at the FSM diagram, we can see it next expects a ‘>’. The zero state is special, and represents the “accept state”, that is, the state of a correctly exited FSM. - -The code generated by `Automa.generate_exec_code` is a little more complicated, and also depends on the `CodeGenContext`. But it will increment `p` by one, read a byte from `data`, and execute a state transition (i.e. change `cs`) depending on the byte. If `cs` goes negative, it knows the input is malformed. If `cs` is zero, the parser has finished. If `cs` is positive, it will continue until end of file. - -Alright, let's create a parser using these functions! - -```julia -@eval function parse_fasta(data::Union{String,Vector{UInt8}}) - $(Automa.generate_init_code(context, machine)) - - # p_end and p_eof were set to 0 and -1 in the init code, - # we need to set them to the end of input, i.e. the length of `data`. - p_end = p_eof = lastindex(data) - - # We just use an empty dict here because we don't want our parser - # to do anything just yet - only parse the input - $(Automa.generate_exec_code(context, machine, Dict{Symbol, Expr}())) - - # We need to make sure that we reached the accept state, else the - # input did not parse correctly - iszero(cs) || error("failed to parse on byte ", p) - return nothing -end; -``` - -Does it work? - -```julia -for (inputno, data) in enumerate([ - "", - ">hi\nACGT\n", - ">hi\nACGT", - ">hi\nAA\n>x\nGTGATCGTAGTA\n", - ">hi\nthere!" - ]) - try - parse_fasta(data) - println("Input $inputno: parsed successfully!") - catch e - println("Input $inputno: ", e) - end -end -``` - -``` -Input 1: parsed successfully! -Input 2: parsed successfully! -Input 3: ErrorException("failed to parse on byte 9") -Input 4: parsed successfully! -Input 5: ErrorException("failed to parse on byte 5") -``` - -Excellent. It correctly parsed the empty data, input 2 and 4. Input 3 lacked a trailing newline, and input 5 didn't have a proper sequence. - -But just parsing a file is not too useful. Normally, we parse a file in order to load it into some kind of datastructure to manipulate it. That's where the action dict comes into the picture. We can make Automa execute arbitrary Julia code during parsing. Here is how it works: - -- When defining our machine, we add _action names_, in the form of Julia `Symbol`s to certain regexes. For example, we may define that exiting the regex `sequence` should execute the action `:exit_sequence`. Like other Julia identifiers, the name can be chosen arbitrarily. -- Using the action dict, which was of type `Dict{Symbol, Expr}`, we can map action names to Julia code. This tells Automa what each action name _means_. -- The actions expressions are put into the function we create at parse time, so there is no runtime cost to this. - -First, we redefine our machine. This time, we add actions: - -```julia -machine = let - # Define SimpleFasta syntax - newline = re"\n" - header = re">[a-z]+" - sequence = re"[ACGT]+" - record = header * newline * sequence * newline - fasta = re.rep(record) - - # Define SimpleFasta actions using arbitrary names - header.actions[:enter] = [:enter] - header.actions[:exit] = [:exit_header] - sequence.actions[:enter] = [:enter] - sequence.actions[:exit] = [:exit_sequence] - record.actions[:exit] = [:exit_record] - - Automa.compile(fasta) -end; -``` - -If we visualize the machine now, the actions will be printed on the relevant edges in the FSM diagram. For example, the newline after a header is labeled `'\n'/exit_header`, meaning the transition will happen at the input byte `'\n'`, and it will execute the action `exit_header`. - -Also note that the diagram structure itself changed, because the entering state and exit state are now distinct. The exit state 6 will execute `:exit_record` at the end of file (EOF), whereas if the FSM ends at state 1, `:exit_record` is not executed. - -```julia -display_machine(machine) -``` - -![svg](/assets/posts/automa1/automa_tutorial_25_0.svg) - -Let's also define a simple data structure to parse the SimpleFasta records into. Like our SimpleFasta format, let's not overcomplicate things: - -```julia -using BioSequences -``` - -```julia -struct FastaRecord{A} - header::String - sequence::LongSequence{A} -end - -FastaRecord(h, sequence::LongSequence{A}) where A = FastaRecord{A}(h, sequence); -``` - -And now our action dict. I can use the variables `data`, `p`, `p_end` etc. in the code: - -```julia -actions = Dict( - # Record which byte position marks the beginning of header or sequence - :enter => quote - mark = p - end, - :exit_header => quote - header = String(data[mark+1:p-1]) - end, - :exit_sequence => quote - sequence = LongSequence{A}(data[mark:p-1]) - end, - :exit_record => quote - record = FastaRecord(header, sequence) - push!(records, record) - end, -); -``` - -```julia -@eval function parse_fasta(::Type{A}, data::Union{String,Vector{UInt8}}) where {A <: Alphabet} - # We can't control the order that the code from out action dict is executed, so - # we define variables beforehand so we can be sure they are not used before - # they are defined. - mark = 0 - records = FastaRecord{A}[] - header = "" - sequence = LongSequence{A}() - - # The rest is just like in our previous example, except now we use the - # action dict we just created. - $(Automa.generate_init_code(context, machine)) - p_end = p_eof = lastindex(data) - $(Automa.generate_exec_code(context, machine, actions)) - - iszero(cs) || error("failed to parse on byte ", p) - return records -end; -``` - -We can verify that it works: - -```julia -parse_fasta(DNAAlphabet{4}, ">hello\nTAG\n>there\nTAA\n") -``` - -``` -2-element Array{FastaRecord{DNAAlphabet{4}},1}: - FastaRecord{DNAAlphabet{4}}("hello", TAG) - FastaRecord{DNAAlphabet{4}}("there", TAA) -``` - -## Redesign the format - -With the basics now covered, let's step up the game a tad and make it parse SimpleFasta records with multiple lines per sequence. We first define a `seqline` pattern that looks like the old `sequence` pattern, and build a new `sequence` pattern from multiple `seqline` patterns. - -```julia -machine = let - # Define SimpleFasta syntax - header = re">[a-z]+" - seqline = re"[ACGT]+" - sequence = seqline * re.rep(re"\n" * seqline) - record = header * re"\n" * sequence * re"\n" - fasta = re.rep(record) - - # Define SimpleFasta actions - header.actions[:enter] = [:enter] - header.actions[:exit] = [:exit_header] - seqline.actions[:enter] = [:enter] - seqline.actions[:exit] = [:exit_seqline] - record.actions[:exit] = [:exit_record] - - Automa.compile(fasta) -end; -``` - -The machine now has a subtle change with a small loop between node 5 and 6 representing the parser seeing multiple sequence lines. - -```julia -display_machine(machine) -``` - -![svg](/assets/posts/automa1/automa_tutorial_37_0.svg) - -We also need to update the `actions`. Here, I use `:(this syntax)`, which is equivalent to - -``` -quote - this syntax -end -``` - -but more readable for one-liners. I keep a buffer containing the sequence, and append every sequence line to the buffer at the end of each `seqline`. When the record is done, I create the sequence and empty the buffer for the next record. - -```julia -actions = Dict( - :enter => :(mark= p), - :exit_header => :(header = String(data[mark+1:p-1])), - :exit_seqline => quote - doff = length(seqbuffer) + 1 - resize!(seqbuffer, length(seqbuffer) + p - mark) - copyto!(seqbuffer, doff, data, mark, p-mark) - end, - :exit_record => quote - sequence = LongSequence{A}(seqbuffer) - empty!(seqbuffer) - record = FastaRecord(header, sequence) - push!(records, record) - end, -); -``` - -We need to redefine `parse_fasta`, now also containing the `seqbuffer`: - -```julia -@eval function parse_fasta(::Type{A}, data::Union{String,Vector{UInt8}}) where {A <: Alphabet} - mark = 0 - records = FastaRecord{A}[] - header = "" - sequence = LongSequence{A}() - seqbuffer = UInt8[] - - $(Automa.generate_init_code(context, machine)) - p_end = p_eof = lastindex(data) - $(Automa.generate_exec_code(context, machine, actions)) - - iszero(cs) || error("failed to parse on byte ", p) - return records -end; -``` - -And we can confirm it now works for multiple sequences! - -```julia -parse_fasta(DNAAlphabet{2}, ">hello\nTAG\nGGG\n>there\nTAA\nTAG\n") -``` - -``` -2-element Array{FastaRecord{DNAAlphabet{2}},1}: - FastaRecord{DNAAlphabet{2}}("hello", TAGGGG) - FastaRecord{DNAAlphabet{2}}("there", TAATAG) -``` - -## Even more complexity - -One of the greatest things about Automa is how we can parse quite complicated formats without needing to manually construct much code. For example, here, I change _only_ the regular expressions: - -- I allow optional Windows-style newlines (`\r\n`) -- I allow trailing whitespace on each line (`re.space() \ (re"\r" | re"\n")` means all space characters except \\r or \\n), but not whitespace inside headers -- Sequences can only contain all UIPAC ambiguous RNA or DNA nucleotides -- The trailing record no longer needs a trailing newline to be valid. It has the same actions as a regular record. - -```julia -machine = let - # Define FASTA syntax - newline = re.opt("\r") * re"\n" - hspace = re.space() \ (re"\r" | re"\n") - header = re">" * re.rep1((re.any() \ re.space())) * re.opt(hspace) - seqline = re"[acgturmkyswbdhvnACGTURMKYSWBDHVN\-*]+" * re.opt(hspace) - sequence = seqline * re.rep(newline * seqline) - record = header * newline * sequence * newline - trailing_record = header * newline * sequence * re.rep(newline * re.opt(hspace)) - fasta = re.rep(newline) * re.rep(record) * re.opt(trailing_record) - - # Define FASTA actions - header.actions[:enter] = [:enter] - header.actions[:exit] = [:exit_header] - seqline.actions[:enter] = [:enter] - seqline.actions[:exit] = [:exit_seqline] - record.actions[:exit] = [:exit_record] - trailing_record.actions[:exit] = [:exit_record] - - Automa.compile(fasta) -end; -``` - -The machine is now a bit more complicated. But who cares, it's automatically generated. Look how easy it was to generate! - -```julia -display_machine(machine) -``` - -![svg](/assets/posts/automa1/automa_tutorial_47_0.svg) - -## Pitfall 1: Ambiguous parsers - -Besides its complexity, building parsers with Automa has some pitfalls - notably those caused by Automa transitioning state for every input byte. - -Unfortunately, it's very easy to accidentally create a machine that can't possibly figure out what action to take when looking only at one byte at a time. The following simple machine will not compile (on the master branch of Automa). - -```julia -bad_machine = let - left = re"Turn left!" - right = re"Turn right!" - left_or_right = left | right - - left.actions[:enter] = [:turn_left] - right.actions[:enter] = [:turn_right] - - Automa.compile(left_or_right) -end -``` - -``` -Ambiguous DFA: Input 0x54 can lead to actions [:turn_right] or [:turn_left] - - - -Stacktrace: - - [1] error(::String) at ./error.jl:33 - - [2] validate_paths(::Array{Tuple{Union{Nothing, Automa.Edge},Array{Symbol,1}},1}) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:176 - - [3] validate_nfanodes(::Automa.StableSet{Automa.NFANode}) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:195 - - [4] nfa2dfa(::Automa.NFA, ::Bool) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:104 - - [5] compile(::Automa.RegExp.RE; optimize::Bool, unambiguous::Bool) at /home/jakob/.julia/packages/Automa/sfHZ6/src/machine.jl:55 - - [6] compile(::Automa.RegExp.RE) at /home/jakob/.julia/packages/Automa/sfHZ6/src/machine.jl:55 - - [7] top-level scope at In[27]:9 - - [8] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091 -``` - -Automa refuse to create this FSM. Why? Well, the first byte it expects is a `T` (or `0x54`) - but there is no way of knowing whether it's entering `left` or `right` when it sees that byte, and these two patters have conflicting actions! If they had the same actions, there would be no problem. - -This situation is highly artificial, but the situation happens often in real life. Here's a very subtle change to one of the previous parsers: - -```julia -bad_machine = let - # Define SimpleFasta syntax - header = re">[a-z]+" - seqline = re"[ACGT]+" - sequence = seqline * re.rep(re"\n" * seqline) - record = header * re"\n" * sequence - fasta = re.rep(record * re"\n") - - # Define SimpleFasta actions - header.actions[:enter] = [:enter] - header.actions[:exit] = [:exit_header] - seqline.actions[:enter] = [:enter] - seqline.actions[:exit] = [:exit_seqline] - record.actions[:exit] = [:exit_record] - - Automa.compile(fasta) -end; -``` - -``` -Ambiguous DFA: Input 0x0a can lead to actions [:exit_seqline, :exit_record] or [:exit_seqline] - - - -Stacktrace: - - [1] error(::String) at ./error.jl:33 - - [2] validate_paths(::Array{Tuple{Union{Nothing, Automa.Edge},Array{Symbol,1}},1}) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:176 - - [3] validate_nfanodes(::Automa.StableSet{Automa.NFANode}) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:195 - - [4] nfa2dfa(::Automa.NFA, ::Bool) at /home/jakob/.julia/packages/Automa/sfHZ6/src/dfa.jl:104 - - [5] compile(::Automa.RegExp.RE; optimize::Bool, unambiguous::Bool) at /home/jakob/.julia/packages/Automa/sfHZ6/src/machine.jl:55 - - [6] compile(::Automa.RegExp.RE) at /home/jakob/.julia/packages/Automa/sfHZ6/src/machine.jl:55 - - [7] top-level scope at In[28]:16 - - [8] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091 -``` - -After a `seqline`, when encountering a newline, there is no way of knowing whether this marks the end of a record or whether it continues at the next line. Automa can't look ahead, it has to make a decision at every byte. - -Here, the solution is to move the newline from the definition of `fasta` to that of `sequence`. That way, the newline functions as a kind of one-byte lookahead - if the byte after the newline is a `>`, it knows the record is complete. - -In general, encountering situations like this is usually a sign that the parser is badly built - or that the format is. You can usually resolve it by using single-byte lookahead like above. If not, it is possible to optionally disable the check for ambiguous actions by passing a keyword to the `Automa.parse` function. But beware that this may lead to absurd results. - -## Pitfall 2: No recursively defined patterns - -Some formats are naturally recursive. The [Newick format](https://en.wikipedia.org/wiki/Newick_format), for example, defines “subtree” in terms of “internal”, which is defined in terms of “branchset”, defined in terms of “branch” which is defined in terms of… “subtree”. - -Something like that will not work Automa: - -```julia -simple_newick = let - name = re"[a-z_]" - clade = name | (re"\(" * cladeset * ")") - cladeset = clade * re.rep(re"," * clade) - Automa.compile(cladeset * re";") -end - -``` - -``` -UndefVarError: cladeset not defined - - - -Stacktrace: - - [1] top-level scope at In[29]:3 - - [2] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091 -``` - -Because, in general, you can't refer to objects in Julia that have not yet been defined. Worse, even if the syntactical challenge was solved, recursive patterns usually only make sense if you have lookahead. Newick files, for example, simply _can't_ be parsed by FSMs, because every time you see an open parenthesis, you need to make sure there is a closing one further in the file, and this requires lookahead that can't be resolved by parsing one byte at a time. - -Luckily, because Automa can execute arbitrary Julia code, we can have the FSM manipulate a stack and turn the FSM into a _pushdown automaton_, which can handle formats like Newick. It does require a little more manual fiddling, and is less elegant: - -```julia -simple_newick = let - name = re"[a-z_]+" - cladestart = re"\(" - cladestop = re"\)" - cladesep = re"," - nodechange = cladestart | cladestop | cladesep - newick_element = nodechange * re.opt(name) - tree = re.opt(name) * re.rep(newick_element) * re";" - - cladestart.actions[:enter] = [:push] - cladestop.actions[:enter] = [:pop] - cladesep.actions[:enter] = [:pop, :push] - - Automa.compile(tree) -end - -actions = Dict( - :push => quote - level -= 1 - end, - :pop => quote - iszero(level) && error("Too many closing parentheses") - level += 1 - end -); -``` - -```julia -@eval function parse_newick(data::Union{String,Vector{UInt8}}) - level = 0 - $(Automa.generate_init_code(context, simple_newick)) - p_end = p_eof = lastindex(data) - $(Automa.generate_exec_code(context, simple_newick, actions)) - - iszero(cs) || error("failed to parse on byte ", p) - iszero(level) || error("Too many opening parentheses") -end; -``` - -And it sort of works: - -```julia -println("Does this parse? ", parse_newick("(hello,hi);")) -println("Does this parse? ", parse_newick("(hello,hi)(;")) -``` - -``` -Does this parse? true - - - -Too many opening parentheses - - - -Stacktrace: - - [1] error(::String) at ./error.jl:33 - - [2] parse_newick(::String) at ./In[31]:8 - - [3] top-level scope at In[32]:2 - - [4] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091 -``` - -Here, I needed to manually keep track of the level of nesting. In fact, I would have to keep track of more stuff to disallow inputs like `();`, removing some of the point of Automa - namely, that it is automatic. - -In the next part of this tutorial, I will show how to use Automa to create honest-to-God parsers which integrate with the BioJulia ecosystem and can work on streamed data. - -## Optimizing - -Automa's parsers are pretty fast. To create hand-written parsers of comparable speeds, you need to microoptimize every operation, which is annoying. That being said, for actually loading parsed files to be fast, you need to optimize the user-defined actions in the actions dictionary, too. - -How fast is our un-optimized Fasta parser already? Let's test it on some data and find out. I'll make 50k sequences with 2k base pairs each, for a total of 100 MB data. - -Remember to re-run the block of code where the `parse_fasta` function is defined since we changed the machine. - -```julia -# Create 50k records with 2kbp each -function generate_data() - open("/tmp/fasta.fna", "w") do file - for seq in 1:50000 - println(file, '>', join(rand('a':'z', 16))) - for line in 1:20 - println(file, join(rand("ACGT", 100))) - end - end - end -end -generate_data() -``` - -```julia -function parsedata() - open("/tmp/fasta.fna") do file - parse_fasta(DNAAlphabet{2}, read(file)) - end -end; -``` - -```julia -parsedata(); -@time parsedata(); -``` - -``` - 0.330489 seconds (200.04 k allocations: 138.861 MiB, 4.15% gc time) -``` - -Alright! It does about 300 MB/s on my laptop. Not bad! I'd say for most applications, this speed is more than sufficient. - -But this is Julia. We want to be able to optimize the crap out of it. So let's optimize the actions: - -```julia -actions = Dict( - :enter => :(mark = p), - - # Create string with only one copy of the data. - :exit_header => :(header = unsafe_string(pointer(data, mark + 1), p - mark - 1)), - - # Only resize buffer if it's too small, else just keep track of how many bytes are used. - :exit_seqline => quote - N = p - mark - length(seqbuffer) < filled + N && resize!(seqbuffer, filled + N) - copyto!(seqbuffer, filled+1, data, mark, N) - filled += N - end, - - # Use `copyto!` to only encode data directly from data vector into sequence - # note this requires the latest versions of BioSequences. - :exit_record => quote - sequence = copyto!(LongSequence{A}(filled), 1, seqbuffer, 1, filled) - record = FastaRecord(header, sequence) - push!(records, record) - filled = 0 - end, -); -``` - -If we want to optimize, we also need to use the fastest `CodeGenContext`. We use the `:goto`\-generator. This creates machine code using `@goto`\-statements, which creates very long and completely unreadable code - but it's fast. Also, who cares if it's hard to read. It's machine-generated code. We disable the FSM's boundschecks when accessing the `data` vector - since we don't manipulate the position `p` manually, we are confident it will not go out of bounds. And we allow the code generator to unroll loops: - -```julia -context = Automa.CodeGenContext(generator=:goto, checkbounds=false, loopunroll=4); -``` - -We also need to modify the `parse` function because we use a new variable called `filled` and need to initialize it. - -```julia -@eval function parse_fasta(::Type{A}, data::Union{String,Vector{UInt8}}) where {A <: Alphabet} - mark = 0 - records = FastaRecord{A}[] - header = "" - sequence = LongSequence{A}() - seqbuffer = UInt8[] - filled = 0 - - $(Automa.generate_init_code(context, machine)) - p_end = p_eof = lastindex(data) - $(Automa.generate_exec_code(context, machine, actions)) - - iszero(cs) || error("failed to parse on byte ", p) - return records -end; -``` - -```julia -parsedata(); -@time parsedata(); -``` - -```! -0.162113 seconds (150.04 k allocations: 133.520 MiB, 7.90% gc time) -``` - -Okay, we're at slightly above 600 MB/s. Profiling confirms nearly all time is spent encoding the DNA sequences to `LongSequence`. We can make it faster still by not storing the data as a `LongSequence`, and instead make it a "lazy" object that only constructs the sequence upon demand. Even further, we could avoid heap-allocating each sequence individually. But these optimizations do not pertain directly to Automa, and I will leave them here. diff --git a/docs/src/posts/biojl.md b/docs/src/posts/biojl.md deleted file mode 100644 index e5b4067..0000000 --- a/docs/src/posts/biojl.md +++ /dev/null @@ -1,47 +0,0 @@ -+++ -using Dates - -date = Date("2020-01-23") -author = "sabrina" -+++ - -# Bio.jl is old and deprecated - -![biojulia logo](/assets/biojulia-logo1.png) - -Hi there! There have been incidents of confusion where newer users have tried to install and run an old and deprecated BioJulia package called `Bio.jl`, or they have not known which package(s) they need to install in order to start working. - -So I'd like to take the opportunity to clear this situation up and perhaps put out a clearer explanation, of why Bio.jl exists when there are other packages with overlapping functionality. - -Bio.jl was the first package BioJulia produced, at a time when the scale of the project meant it made sense to have a single module - Bio - with several submodules - - `Seq`, `Align`, `Phylo`, `Intervals`, `Structure`, `Var`, `Services`, `Tools`. - -Bio has existed since very early days - or versions - of julia as well. - -Eventually there came a point where datatype and algorithm specific packages made more sense than a single monolithic repository. - -And so the package got split into many: - -- `Bio.Seq` became [`BioSequences.jl`](https://github.com/BioJulia/BioSequences.jl/) -- `Bio.Align` became [`BioAlignments.jl`](https://github.com/BioJulia/BioAlignments.jl/) -- `Bio.Intervals` became [`GenomicFeatures.jl`](https://github.com/BioJulia/GenomicFeatures.jl/) -- `Bio.Structure` became [`BioStructures.jl`](https://github.com/BioJulia/BioStructures.jl/) -- `Bio.Var` became [`GeneticVariation.jl`](https://github.com/BioJulia/GeneticVariation.jl/) -- `Bio.Phylo` became [`Phylogenies.jl`](https://github.com/BioJulia/Phylogenies.jl/) -- `Bio.Services` became [`BioServices.jl`](https://github.com/BioJulia/BioServices.jl/) -- `Bio.Tools` became [`BioTools.jl`](https://github.com/BioJulia/BioTools.jl/) - -`Bio.jl` then basically persisted as a convenience wrapper around those packages, so that they could be installed with a single command and were distributed set to compatible versions. - -With julia v0.7/v1.0 and the new `Pkg` and Project system the need for `Bio.jl` to provide that functionality became largely moot. - -## So what should you do? - -As of today, `Bio.jl` is available for installation, but mostly just to prevent old scripts and projects breaking. - -It is not longer recommended that you use `Bio.jl`. Instead you should start a julia project and add just the BioJulia packages you want to use. For a brief description on how to do this, check out the getting started page. - -Happy hacking. - -Sabrina. diff --git a/docs/src/posts/cajun-kevin.md b/docs/src/posts/cajun-kevin.md deleted file mode 100644 index 00f6d33..0000000 --- a/docs/src/posts/cajun-kevin.md +++ /dev/null @@ -1,32 +0,0 @@ -+++ -using Dates -date = Date("2024-04-21") -title = "BioJulia at CAJUN" -author = "Kevin Bonham" -+++ - -# BioJulia at Cajun - -This Tuesday, I (Kevin) will be giving a talk for -the [Cambridge Area Julia Users Network][cajun] -on "Doing Biology in Julia". - -[See here][event] for event details -[and here][slides] for the slides. -If you're in the area, hope to see you there! - -~~~ - -~~~ - -[cajun]: https://www.meetup.com/julia-cajun/ -[event]: https://www.meetup.com/julia-cajun/events/299773552/ -[slides]: https://gitlab.com/kescobo/cajun_bio - - diff --git a/docs/src/posts/hardware.md b/docs/src/posts/hardware.md deleted file mode 100644 index 3ddf9c9..0000000 --- a/docs/src/posts/hardware.md +++ /dev/null @@ -1,16 +0,0 @@ -+++ -using Dates -date = Date("2022-09-04") -title = "What scientists must know about hardware to write fast code" -author = "Jakob Nybo Nissen" -+++ - - -~~~ - -~~~ - -# What scientists must know about hardware to write fast code - - -{{ insert posts/hardware/pluto.html assets }} diff --git a/docs/src/posts/index.md b/docs/src/posts/index.md deleted file mode 100644 index 4f69a32..0000000 --- a/docs/src/posts/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Posts - -- [Hardware](/posts/hardware) diff --git a/docs/src/posts/seq-lang.md b/docs/src/posts/seq-lang.md deleted file mode 100644 index 287bc5c..0000000 --- a/docs/src/posts/seq-lang.md +++ /dev/null @@ -1,115 +0,0 @@ -+++ -using Dates - -title = "On the performance and design of BioSequences compared to the Seq language" -date = Date("2020-01-23") -author = "Jakob Nybo Nissen, Sabrina Ward" -+++ - -# On the performance and design of BioSequences compared to the Seq language - -![](/assets/posts/seq-lang/featured_hu673fdf9bf6c03bbd2130cc0e6402b2ac_100218_720x0_resize_lanczos_2.png) - -## Introduction - -In October 2019, a paper was published in Proceedings of the ACM on Programming Languages, introducing a new language for bioinformatics called [Seq](https://dl.acm.org/doi/10.1145/3360551). - -In it, the authors rightly recognize that the field of bioinformatics is in need of a high-performance, yet expressive and productive language. They present Seq, a domain specific compiled language, with the user friendliness of Python, the performance of C, and bioinformatics-specific data types and optimisations. As Julians, we consider their goal to be noble and well worth pursuit. However, they also presented a series of benchmarking results in which they claim the performance of Seq code is far greater than equivalent code written in other languages, including C++ and Julia. - -Of course, benchmarking between languages is a tricky thing. Different languages present different syntax, tools and idioms to the programmer, such that what is efficient and natural in one language may be inefficient and clumsy in another. When benchmarking different languages, therefore, it is important to write code that is idiomatic in each language before comparing the code in terms of performance, readability or ease-of-writing. Disagreements about benchmarks between languages often come down to disagreements of whether the code compared are equivalent - if they aren’t, comparisons may be meaningless. - -For example, in the majority of the benchmarks between Seq and Julia in the Seq paper, the DNA sequences of Seq are represented by a dedicated sequence type, whereas the sequences in Julia are represented by strings. As the Seq type is crafted specifically for efficient DNA processing, and Julia’s strings are crafted for efficient generic text processing, it is no surprise that Seq is much faster in these benchmarks. Therefore, these particular benchmarks are obviously misleading, and we will not discuss them further here. - -The Seq authors, to their credit, realize this and include comparison between Seq and Julia code that uses BioSequences, a package of the BioJulia organization. This package contains custom, efficient types for exactly the type of work they are benchmarking, and so here, the code is equivalent and the comparison reasonable. Even when comparing against BioSequences, the Seq authors find that Seq offers a large speed advantage. As a core developer and long-time user of BioJulia, respectively, we were puzzled by these results. BioJulia is highly optimised. Could Seq really be that much faster? Perhaps we could learn something from Seq? - -## Recreating the benchmarks - -The first thing to do was to see if the results in the paper could be replicated. The Seq authors have made a real effort to allow easy replication of their results, as they have released a virtual machine with all necessary code and software to run their benchmarks out of the box. Only their BioJulia code was missing, which they promptly provided upon request. So we spun up their VM, and recreated their benchmarks. For details on the benchmarking procedure, see the last section of this post. - -We note that the provided version of Seq provides wrong answers to the benchmarks on several counts. First, kmers containing ambiguous nucleotides are not skipped during iteration, leading to simpler and faster (but by convention, wrong) code. Second, the middle base is not complemented during reverse-complementation of odd-length sequences. Third, the reverse-complement of ambiguous nucleotides are wrong, as e.g. K is complemented to N rather than the correct answer (M). Fourth, we can make little sense of what the result returned by their CpG benchmarking code actually means. However, these small blemishes could easily be fixed by the Seq authors with little or no performance penalty, so they are not of great importance here. - -The results of our recreation are seen in the plot below. We were happy to see we could recreate their performance difference, seeing nearly the same performance difference they found. - -![figure-1](/assets/posts/seq-lang/fig1.png) **Figure 1. Running time of BioJulia (blue) versus Seq (red). We could recreate the authors findings and found Seq to be much faster than BioJulia for the three provided benchmarks. The barplot shows shows the mean +/- stddev time of 5 consecutive runs.** - -## Improving the benchmarked code - -As a long time developers and users of BioJulia, we feel qualified to judge whether or not the Julia code used for the benchmarks is idiomatic or not, and whether or not BioJulia was being correctly used. Non-idiomatic Julia is the most common source of complaints when new Julia users benchmark Julia code and find the performance disappointing. This often happens because new users code in a way that carries little penalty in languages like R and Python, but which is difficult for Julia’s JIT compiler to optimise. So, a natural starting point was to check their Julia code for inefficiencies. - -However, the Seq author’s Julia benchmarks were well implemented. Only the code for the CpG benchmark could be improved by fixing an error which resulted in incorrect answers, and by computing the result in a single pass of the input sequence. The two other benchmarks only needed minor tweaking to be idiomatic. These minor changes did not improve the timings of BioJulia markedly (**Figure 2**). - -![figure-2](/assets/posts/seq-lang/fig2.png) **Figure 2. Improving the Julia code of the Seq paper’s benchmarks (green series), did not change the results very much. The barplot shows shows the mean +/- stddev time of 5 consecutive runs.** - -## Explaining the difference in performance - -It seems that Seq really is much faster than BioJulia, at least for the benchmarked tasks, and we wanted to know why. So we profiled their BioJulia code to see what BioJulia was taking its sweet time doing. The results for the three benchmarks are shown below in **Figure 3**. - -![figure-3](/assets/posts/seq-lang/fig3.png) **Figure 3. Barplots showing the fraction of time BioJulia benchmarking code was spending doing various sub-tasks, as determined by the built-in Julia Profiler tool.** - -Surprisingly, **Figure 3** reveals that only a small fraction of the time is spent doing what the benchmark nominally measures. For example, the RC benchmark presumably should benchmark reverse-complementation (RC’ing) of sequences, but BioJulia spends less than 10% of the time actually RC’ing. Likewise, checking symmetric kmers and kmer iteration in the 16-mer benchmark is relatively insignificant time-wise. We implemented Seq’s algorithm for RC’ing kmers as described in their paper, but found no difference in performance to BioJulia’s approach, even when benchmarking only the time spent RC’ing. - -In fact, **Figure 3** shows that for all benchmarks, most of the time is spent building instances of the BioSequence type that BioSequences.jl uses to represent long DNA, RNA and Amino Acid sequences. To find the source of the performance difference between Seq and BioSequences, then, it is necessary to take a small detour into the internals of BioSequences and Seq. - -## How to represent DNA sequences in software - -DNA consists of four nucleotides called A, C, G and T. In some contexts, a nucleotide may instead be one of 16 [IUPAC](https://en.wikipedia.org/wiki/Nucleic_acid_notation) defined symbols. Hence, one nucleotide may be represented in either two bits or four bits. In BioSequences, DNA is stored in a compact format, where nucleotides are encoded to 2 or 4-bit encodings in an integer array. This representation comes with a few advantages: - -1. The encoding and decoding step implicitly validates that the input data is meaningful DNA data instead of some random string. Therefore, when given a BioSequence, the user can be confident that the underlying data actually represents valid DNA. -2. Encoding saves 4x or 2x on RAM. Speed is important in bioinformatics precisely because of our large datasets, and this also puts a premium on RAM, making these savings worthwhile. -3. The encoded representation of DNA makes biological operations easier and more efficient. Complementation of a 2-bit DNA sequence, for example, consists only of inverting the encoded bits. Converting between DNA and RNA includes only changing the metadata. - -The encoding/decoding also comes with a disadvantage, as it takes more time than just accessing raw bytes. This tradeoff is reminiscent of the pros and cons of a boolean vector versus a bit-vector. As the benchmarks here consists of very simple, fast operations on many small sequences that are read in as text, encoding time dominate. - -In contrast, Seq represents DNA sequences as a byte array with the underlying data simply being the bytes of the input string. Constructing this type is obviously much faster than a BioSequence since it can wrap a string directly, but the RAM consumption is 2 or 4 times higher. Remarkably, Seq appears to do no input validation at all, as we confirmed by re-running the benchmarks with corrupted data. BioSequences immediately crashed with an informative error message, whereas Seq happily produced the wrong answer with no warnings. - -So it appears the primary reason BioJulia code is slower than Seq code in these three benchmarks is that BioSequences.jl is doing important work for you that Seq is not doing. As scientists, we hope you value tools that spend the time and effort to validate inputs given to it rather than fail silently. - -## Implementing Seq-like types in Julia - -BioSequences may be more memory efficient and safer to use, we still verified the finding of the Seq authors: Seq really is much faster than BioSequences. That surprised us. Was Seq so fast because of amazing software engineering in the language itself, or simply because so much time is lost in BioSequence’s encoding and decoding? We decided to mimic Seq in Julia by implementing DNA sequences and kmer types in Julia with the same data representation Seq uses. Our module, [SeqJL](https://github.com/jakobnissen/SeqLangBenchmarks) turned out to be simple to write, taking less than 100 lines of code. We note that BioSequences could easily have been written this way, and intentionally isn’t. - -Figure 4 shows the performance of our SeqJL code (**Figure 4**, red), where it is significantly faster than Seq, except in the RC benchmark (**Figure 4**, orange). We found that even further speed improvements could be found by buffering input and output using the BufferedStreams.jl package, but we did not use that in the benchmarks. - -![figure-4](/assets/posts/seq-lang/fig4.png) **Figure 4. Timing a Julia implementation of the data types in Seq (red) resulted in timings which beat those achieved by the Seq code (orange). The barplot shows shows the mean +/- stddev time of 5 consecutive runs.** - -## Learning from Seq - -Being challenged often teaches valuable lessons, and the challenge Seq presented to BioJulia is no exception. We were surprised to see a bioinformatics workload where the encoding step of BioSequences proved to be a bottleneck, as we have always believed it to be very fast. We did not expect our simple SeqJL code to outperform BioSequences by such a large factor in these benchmarks. - -In most realistic workloads, sequences are subject to more intense processing, which makes the speed of encoding and IO operations less important in comparison. In addition we note that BioJulia provides optimal buffered, state machine generated parsers for many file formats like FASTA and FASTQ, but they were not explored in this work as no benchmark involved them. BioJulia also offers ReadDatastores.jl, which implements indexed disk-backed collections of sequences, stored in the BioSequences encodings. These data-stores mean commonly used sequence datasets like sequencing reads stored in FASTQ files need to be encoded only once, and then the data-store can be reused for a great performance benefit. Nonetheless, the impressive speed of Seq over BioSequences in these benchmarks made us reconsider the need for much faster string/sequence conversion and printing. As a result of this challenge, we have subjected BioSequences to [a performance review](https://github.com/BioJulia/BioSequences.jl/issues/86), optimising a dozen code sections that was causing slowdowns. To benefit from these improvements, users should install BioSequences version 2.X from the BioJuliaRegistry. - -We were happy to discover that these changes made a big difference. With the updates, BioSequences rivals Seq in speed while keeping its advantages of a lower memory footprint and doing data validation. - -![figure-5](/assets/posts/seq-lang/fig5.png) **Figure 5. The newest version of BioSequences (purple) comes with performance improvements in encoding, decoding and IO, making it 3-4 times faster than BioSequences v 1.1.0 (green) for these benchmarks, and rivaling Seq (orange). The barplot shows shows the mean +/- stddev time of 5 consecutive runs.** - -## Our take away impressions - -### Jakob - -I wholeheartedly agree with Seq’s goal of bringing a performant language to the masses, so to speak. I also applaud Seq’s authors for their efforts in providing reproducible results by sharing their code and environment, and for their efforts to compare Seq to efficient, proper Julia code. Ultimately, the speed difference between BioSequences and Seq comes down to a design decision in the implementation of the sequence type. I happen to think BioSequences made the right call by encoding the sequences, and Seq made the wrong one. - -More broadly I think Seq brings little of value to bioinformatics. Our simple SeqJL implementation shows that Julia can achieve what Seq aims to do with even higher performance and, I would argue, even more elegant, reusable and concise code. In contrast, Seq comes with serious drawbacks. Beside DNA sequence processing, a typical bioinformatics workflow may include reading CSV files, feature extraction, doing statistical tests, plotting data and more. Being a domain specific language, Seq has zero chance of having packages for all these tasks available. In contrast, because BioSequences is simply a package in pure Julia, a user of BioSequences have all the tools of the broader Julia ecosystem available. - -More realistically, Seq could survive by providing interoperation with other languages. But madness lies that way. In the bad old days, in a few hours of work, a bioinformatician would use awk to edit text files, pass them through Perl one-liners, run it through Python data processing before graphing using ggplot, all these languages duct-taped together using Bash. Workflows of that kind were inefficient, brittle, and required the programmer to learn a handful of different domain specific languages. Surely that path, the path that Seq shows us, must lie behind us. - -### Ben - -I can only echo and agreement with Jakob in applauding Seq’s authors efforts in trying to bring a performant programming language to life, and also applaud their efforts in providing reproducible results. - -That said, before playing with these benchmarks it’s fair to say I was fairly skeptical of the idea that what bioinformatics really needs is a domain specific language. When I consider critical problems the field faces, my mind goes to problems such as sometimes undocumented, sometimes poorly understood assumptions about biological systems hardcoded into tools (e.g. assembly pipelines that assume levels of ploidy or genome characteristics). I think of experiments that start with a single reference genome, and run pipelines of heuristic after heuristic, each with its own slew of parameters and biases. - -In other words the greatest gains are to be made by improving how we do things, not how fast we do them. Everyone wants speed, that’s why so many Big Data frameworks exist. Indeed the Seq developer’s intention of having a language that is Pythonic in user friendliness, and speed approaching C, is also one of the main reasons Julia exists today. After Julia 1.0 was released, as a core developer of BioJulia, I considered the argument as to whether or not Julia is performant to be settled. It is. - -Now the question of whether Julia is fast enough for bioinformatics is settled. I think the current goal of BioJulia is to provide clear, flexible, easy to use frameworks for doing bioinformatics analyses in a robust/reproducible, transparent manner, using clear concepts. - -After this review I think I would echo the same same conclusions as Jakob: In brief, the results in the paper can be explained largely due to our design choices in BioSequences.jl, which we maintain were the right calls. The exercise has been valuable, as it has resulted in several pull requests that improve on the performance of the string conversions and sequence encoding BioSequences.jl does; whilst we think the computational effort is justified, we also want it to be faster if it can be. Without Seq’s benchmarks to prompt us to examine this more closely, those those improvements might not have been made for a long time, if at all. - -## Benchmarking procedure - -### Benchmarking environment - -We ran the code in the Vagrant [virtual machine provided](https://zenodo.org/record/3374036) by the authors. In the virtual machine, all software needed to reproduce the benchmarks was there, except the Seq author’s BioJulia code, which [was provided upon request](https://github.com/seq-lang/benchmarks/tree/master/paper/idiomatic). The code was run on a 2018 MacBook pro using Julia v 1.0.3 and BioSequences v1.1.0. We could not determine the version of Seq used in the VM. - -### Benchmarking method - -Due to a small virtual disk size in the VM, the whole dataset could not be downloaded, so we generated input data instead by taking the provided small test dataset HG00123_small.txt, and concatenating it to itself 16 times for a total of 2^24 lines, 1.3 GiB. To benchmark, we ran each script 5 times consecutively. For Seq, we used the idiomatic Seq code "seq-id", and did not include compilation time. For Julia, we included JIT compilation (which we estimated to be ~2 seconds for BioJulia benchmarks, and somewhat less for SeqJL benchmarks), but not package precompilation time. Note that unlike the Seq authors, we ran Julia with default optimization level and boundschecks enabled, as these are the most common settings to run Julia in.