diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cf3f801 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: python +python: + - "3.8" + - "3.9" + +# command to install dependencies +install: + - pip install -r requirements.txt + - pip install pytest-cov pytest + - pip install codecov + - pip install . + +# command to run tests +script: + - pytest --cov-report term --cov=nuskell/ + +after_success: + - codecov diff --git a/README.md b/README.md index 18b7171..59b4253 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,49 @@ -# Nuskell: a nucleic acid strand displacement compiler +# Nuskell: nucleic acid strand displacement compiler [![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/DNA-and-Natural-Algorithms-Group/nuskell)](https://github.com/DNA-and-Natural-Algorithms-Group/nuskell/tags) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/DNA-and-Natural-Algorithms-Group/nuskell?include_prereleases)](https://github.com/DNA-and-Natural-Algorithms-Group/nuskell/releases) -![build](https://github.com/DNA-and-Natural-Algorithms-Group/nuskell/actions/workflows/python-package.yml/badge.svg) -[![Codecov](https://img.shields.io/codecov/c/github/dna-and-natural-algorithms-group/nuskell)](https://codecov.io/gh/dna-and-natural-algorithms-group/nuskell) +[![PyPI version](https://badge.fury.io/py/nuskell.svg)](https://badge.fury.io/py/nuskell) +[![PyPI - License](https://img.shields.io/pypi/l/nuskell)](https://opensource.org/licenses/MIT) +[![Build Status](https://travis-ci.com/DNA-and-Natural-Algorithms-Group/nuskell.svg?branch=master)](https://travis-ci.com/github/DNA-and-Natural-Algorithms-Group/nuskell) +[![Codecov branch](https://img.shields.io/codecov/c/github/DNA-and-Natural-Algorithms-Group/nuskell/master)](https://codecov.io/gh/DNA-and-Natural-Algorithms-Group/nuskell) -**Nuskell** is a compiler framework to translate formal chemical reaction -networks (CRNs) into domain-level strand displacement (DSD) systems. -To support the diversity of proposed CRN-to-DSD translation methods -from literature, as well as potential new CRN-to-DSD translation -methods that are yet to be developed, Nuskell provides a *domain-specific -programming language*. In this language, CRN-to-DSD translations can be -formulated as algorithms: so-called *translation schemes*. We provide a -library of selected existing [translation schemes] that users can use -without understanding the details of the Nuskell programming language. +``Nuskell`` is software framework to compile formal chemical reaction networks +(CRNs) into domain-level strand displacement (DSD) systems. As there are many +ways to do such a translation, we provide a library of [translation schemes] +(i.e. variations of CRN-to-DSD translations) that the user can select from. -A notion of correctness for a particular translation is established on a -case-by-case basis using the domain-level reaction enumeration package +In order to proof/disproof the correctness of a particular translation, +``Nuskell`` includes the domain-level reaction enumeration package [Peppercorn][] [[Badelt et al. (2020)]] and the CRN verification package -[crnverifier][], which implements the rate-independent, stochastic-level -theories of pathway decomposition equivalence [[Shin et al. (2019)]] and/or -CRN bisimulation [[Johnson et al. (2019)]]. +[crnverifier][]. +Peppercorn finds intended and potentially unintended reaction pathways, the +crnverifier then checks if the implementation CRN is a correct implementation +of the formal CRN using the stochastic trajectory-type CRN correctness notions +of bisimulation [[Johnson et al. (2019)]] and pathway decomposition +[[Shin et al. (2019)]]. -Peppercorn first finds intended and potentially unintended reaction pathways, -then the crnverifier checks if the implementation CRN is a correct -implementation of the formal CRN. Nuskell is a first step to integrate -biophysical modeling of nucleic acids with rigorous abstraction hierarchies of -modern compilers to design and characterize DSD systems. For more details, see -[[Badelt et al. (2017)]]. +### Examples -## Installation -Nuskell must be installed directly from this repository, we recommend clining -the repository and then using: -```bash -pip install . -``` +Implement a formal CRN using a particular translation-scheme: -For debugging, or if you are planning a contribution to the repository, please -install the development version and make sure all tests pass: -```bash -pip install .[dev] -pytest ``` - -## Quickstart: the nuskell executable -Upon installation, the package provides an executable `nuskell`, which is the -main interface combining CRN-to-DSD translation, DSD enumeration and CRN -verification. For example, to implement the formal CRN + $ echo "A + B <=> X + Y; X -> A" | nuskell --ts srinivas2017.ts --verify crn-bisimulation ``` -A + B <=> X + Y -X -> A +for options see: ``` -using the translation-scheme from [Srinivas (2015)], and to verify that -the translation is correct with CRN bisimulation, use the command line call: -```bash -echo "A + B <=> X + Y; X -> A" | nuskell --ts srinivas2015.ts --verify crn-bisimulation + $ nuskell --help ``` -New users may also appreciate the `-v` flag to get more detailed information on -the individual compilation steps, as well as the option `--pilfile` to print the -DNA complexes generated in different stages of the compilation. -Detailed information about existing translation schemes can be found in the -[translation schemes] directory. - -For more options see: -```bash -nuskell --help +## Translation Schemes +Detailed information about translation schemes can be found in the [translation +schemes] directory. + +## Installation +``` + $ python setup.py install ``` -## Nuskell documentation -A (preliminary) documentation can be found online: [documentation]. Most -importantly, the documentation provides more details on what kind of -translation schemes are supported and how to write them. Suggestions and -contributions that improve the documentation are very welcome. +## Documentation +A preview of the documentation for release v1.0 can be found at: [documentation]. ## Version 0.8 -- basically a complete rewrite, python>=3.8 only. @@ -80,23 +52,26 @@ contributions that improve the documentation are very welcome. * enumeration interface updated to peppercornenumerator-v1.1. * nuskell now uses the prototype objects provided by the dsdobjects library. -## Authors +### Authors - Stefan Badelt - Seung Woo Shin - - Hope Amber Johnson + - Robert Johnson - Qing Dong - Erik Winfree +### License +MIT + ## Cite Stefan Badelt, Seung Woo Shin, Robert F. Johnson, Qing Dong, Chris Thachuk, and Erik Winfree (2017) "A General-Purpose CRN-to-DSD Compiler with Formal Verification, Optimization, and Simulation Capabilities" [[Badelt et al. (2017)]]. + [//]: References [Peppercorn]: [crnverifier]: [translation schemes]: -[Srinivas (2015)]: [Badelt et al. (2017)]: [Badelt et al. (2020)]: [Shin et al. (2019)]: diff --git a/docs/Makefile b/docs/Makefile index d4bb2cb..38772cd 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,20 +1,177 @@ -# Minimal makefile for Sphinx documentation +# Makefile for Sphinx documentation # -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = BUILDDIR = _build -# Put it first so that "make" without argument is like "make help". +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/nuskell.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/nuskell.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/nuskell" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/nuskell" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." -.PHONY: help Makefile +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/compiler.rst b/docs/compiler.rst new file mode 100644 index 0000000..b28e7eb --- /dev/null +++ b/docs/compiler.rst @@ -0,0 +1,6 @@ +nuskell.compiler +========================== + +.. automodule:: nuskell.compiler + :members: translate, genCRN, InvalidSchemeError + diff --git a/docs/conf.py b/docs/conf.py index 6fd9c83..b2d1fb3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,71 +1,340 @@ -# Configuration file for the Sphinx documentation builder. +# -*- coding: utf-8 -*- # -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html +# Nuskell documentation build configuration file, created by +# sphinx-quickstart on Mon May 9 21:46:13 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. -# -- Path setup -------------------------------------------------------------- +import sys +import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('..')) - - -# -- Project information ----------------------------------------------------- - -project = 'Nuskell' -copyright = '2023, Stefan Badelt, Seung Woo Shin, Hope Amber Johnson, Erik Winfree' -author = 'Stefan Badelt, Seung Woo Shin, Hope Amber Johnson, Erik Winfree' - -# The full version, including alpha/beta/rc tags -release = '0.8' +#sys.path.insert(0, os.path.abspath('.')) +# -- General configuration ------------------------------------------------ -# -- General configuration --------------------------------------------------- +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx_copybutton', - 'myst_parser', 'sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', - 'sphinx.ext.napoleon', # Google-style doc strings + 'sphinxcontrib.napoleon', # Google-style doc strings ] +napoleon_include_special_with_doc = True + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Nuskell' +copyright = u'2010-2017, Seung Woo Shin, Qing Dong, Robert Johnson, Stefan Badelt, Erik Winfree' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.5' +# The full version, including alpha/beta/rc tags. +release = '0.5.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False -# -- Options for HTML output ------------------------------------------------- +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -# html_theme = 'default' +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None -autodoc_mock_imports = ['natsort', 'dsdobjects', 'peppercornenumerator', 'crnverifier'] +# Output file base name for HTML help builder. +htmlhelp_basename = 'nuskelldoc' -source_suffix = [ - ".rst", - ".md", + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'nuskell.tex', u'Nuskell Documentation', + u'Seung Woo Shin, Qing Dong, Robert Johnson, Stefan Badelt, Erik Winfree', 'manual'), ] +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'nuskell', u'Nuskell Documentation', + [u'Seung Woo Shin, Qing Dong, Robert Johnson, Stefan Badelt, Erik Winfree'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'nuskell', u'Nuskell Documentation', + u'Seung Woo Shin, Qing Dong, Robert Johnson, Stefan Badelt, Erik Winfree', 'Nuskell', 'A verifying CRN-to-DSD compiler.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'Nuskell' +epub_author = u'Seung Woo Shin, Qing Dong, Robert Johnson, Stefan Badelt, Erik Winfree' +epub_publisher = u'Seung Woo Shin, Qing Dong, Robert Johnson, Stefan Badelt, Erik Winfree' +epub_copyright = u'2010-2017, Seung Woo Shin, Qing Dong, Robert Johnson, Stefan Badelt, Erik Winfree' + +# The basename for the epub file. It defaults to the project name. +#epub_basename = u'Nuskell' + +# The HTML theme for the epub output. Since the default themes are not optimized +# for small screen space, using the same theme for HTML and epub output is +# usually not wise. This defaults to 'epub', a theme designed to save visual +# space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the PIL. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/docs/enumeration.rst b/docs/enumeration.rst new file mode 100644 index 0000000..e6cbfa6 --- /dev/null +++ b/docs/enumeration.rst @@ -0,0 +1,9 @@ +nuskell.enumeration +=================== + +API documentation of the nuskell.enumeration module. + +.. .. automodule:: nuskell.enumeration +.. :members: + + diff --git a/docs/index.rst b/docs/index.rst index ebd1224..b346398 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,34 +1,315 @@ .. Nuskell documentation master file, created by - sphinx-quickstart on Thu May 25 15:03:21 2023. + sphinx-quickstart on Mon May 9 21:46:13 2016. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Nuskell compiler documentation -============================== +Nuskell Documentation (PREVIEW) +=============================== -.. note:: - The source for the Nuskell project is available on GitHub: +------------ +Introduction +------------ +Nuskell compiles formal chemical reaction networks (**CRNs**) into +domain-level strand displacement (**DSD**) systems, based on rigorous +proofs establishing the correctness of compilation from a higher +level to a lower level. +To support the wide range of translation schemes that have already been +proposed in the literature, as well as potential new ones that are yet to be +proposed, Nuskell provides a **domain-specific programming language for +translation schemes**. A notion of correctness is established on a case-by-case +basis using the rate-independent stochastic-level theories of **pathway +decomposition equivalence** and/or **CRN bisimulation**. - https://github.com/DNA-and-Natural-Algorithms-Group/nuskell +Nuskell is a first step to integrate biophysical modelling of nucleic acids +with rigorous abstraction hierarchies of modern compilers to design and +characterize DSD systems. Our independently developed DSD reaction enumeration +library `peppercornenumerator`_ is used for translation-independent reaction +enumeration with well-defined semantics and based on empirical +(sequence-independent) DNA folding parameters. Nuskell also provides an +interface to translate these enumerated systems into systems of ordinary +differential equations (**ODEs**), which are printed into stand-alone, +executable Python scripts using the `crnsimulator`_ library. -.. include:: ../README.md - :parser: myst_parser.sphinx_ +:ref:`Quickstart` introduces high-level concepts that are supported by library, +for more details on how to write translation schemes visit :ref:`Nuskell +programming language`. For advanced development on the Nuskell library, use the +:ref:`API Reference` section and the :ref:`Developer Guidelines`. +The section :ref:`Background` provides an intuition about the formalisms +underlying the Nuskell library. More details can be found in the publications +cited below. + +**Cite:** + * Nuskell: `Badelt et al. (2017)`_ + * CRN bisimulation: `Johnson et al. (2016)`_ + * Peppercornenumerator: `Grun et al. (2014)`_ + * Pathway decomposition equivalence: `Shin et al. (2014)`_ + +.. _Quickstart: + +Quickstart +---------- +The following command translates a formal **CRN** into a **DSD** system using the +built-in translation scheme: ``qian2011_3D.ts``, verifies whether the +implementation is correct using *CRN bisimulation* and prints the domain-level +specification in the ``*.pil`` file format. + +.. code-block:: bash + + nuskell --ts qian2011_3D.ts --verify bisimulation --pilfile < formal_crn.in + + +The Nuskell library is meant to help researchers building custom **DSD** +compilers. Nuskell provides (i) a number of different **CRN-to-DSD** +translation schemes, (ii) functions that test different **CRN** equivalence +notions, as well as (iii) **DSD** reaction enumeration and **CRN-to-ODE** +simulations based on empirical (sequence-independent) DNA folding parameters. + +.. code-block:: python + + from nuskell import translate, verify + + testtube = translate('A+B->C', scheme = 'soloveichik2010.ts') + + # Get the enumerated CRN + testtube.enumerate_reactions() + + # Interpret the enumerated CRN, i.e. replace history species + interpretation = testtube.interpret_species(['A','B','C'], prune=True) + + # Formulate reversible reactions as two irreversible reactions. + fcrn = [[['A','B'],['C']]] + vcrn = [] + for r in testtube.reactions: + rxn = [map(str,r.reactants), map(str,r.products)] + vcrn.append(rxn) + + v = verify(fcrn, vcrn, fs, method = 'bisimulation') + + if v : + print("Input CRN and TestTube-Species are CRN bisimulation equivalent.") + else : + print("Input CRN and TestTube-Species are not CRN bisimulation equivalent.") -Please also consider citing the dependencies of nuskell: - * Peppercornenumerator: `Badelt et al. (2020)`_ - * Pathway decomposition equivalence: `Shin et al. (2019)`_ - * CRN bisimulation: `Johnson et al. (2019)`_ ---------------------- CRN-to-DSD translation ---------------------- +DSD system requirements +----------------------- +Automated compilation of **DSD** system requires **DSD** systems to follow a +particular format. First, all involved species and complexes need to be free +of pseudo-knots. Second, we distinguish **signal species** and **fuel +species**. Signal species are at low concentrations and they present the +information (input/output) unit. Fuel species are at high (ideally constant) +concentrations and they mediate the information transfer by consuming and/or +releasing signal species. After compilation, every species in the formal CRN +corresponds to one signal species. Thus, all signal species must have the same +domain-level constitution and structure, but they need to be independent of +each other. A signal species may be a complex composed of multiple molecules. + +**History domains** are common in many translation schemes. A history domain is +considered to be an inert domain of a signal species, but it is unique to the +reaction that has produced the signal species. Hence, multiple species that +differ only by their history domains map to the same formal species. In the +translation scheme language, a history domain is a **wildcard**: ``?``. Together +with the remainder of the molecule, a species with a wildcard forms a +regular-expression, matching every other species in the system that differs only +by a single domain instead of ``?``. + +.. In order to produce a minimal domain-level system specification, Nuskell +.. automatically removes signal species that are specified using wildcard domains +.. after domain-level enumeration. In particular, if there exists a species +.. matching the regular expression, then the species with the wildcard domain and +.. every enumerated reaction emerging from that species is be removed from the +.. system, otherwise, the wildcard domain is replaced by a regular long domain. + +The Nuskell programming language +---------------------------------- +The ``Nuskell programming language`` is used to write ``translation schemes``, +i.e. design algorithms which can be interpreted by the Nuskell compiler. +Translation schemes translate a **CRN** into a **DSD** system. A library of existing +schemes can be found in the official Nuskell `repository`_, the links below +point to a tutorial to write your own translation scheme: + .. toctree:: - intro - tlstutorial - analysis - peppercorn - crn_equivalence + + tlstutorial + +Analysis of implementation networks +----------------------------------- +Besides the top-down interface of Nuskell to translate CRNs to DSD systems, +there also exists a modular, bottom-up interface where users can analyze, +simulate and verify handcrafted or alternatively designed DSD systems. + +.. code-block:: bash + + nuskell --readpil zhang2007_catalyst.pil --verify bisimulation < formal_crn.in + +The option ``--readpil `` tells Nuskell to load domain-level +specifications from a text file, as opposed to automated design via translation +schemes. The input format is a `variation` of the pepper internal language +(**PIL**) kernel notation which allows the specification of ``constant`` or +``initial`` concentrations in ``M``, ``mM``, ``uM``, ``nM``, ``pM``. + +.. code-block:: none + + # Use '#' for comments. + + # Domains + length d1 = 10 + length d2a = 6 + + # Complexes # Concentratios + C = d4 d5 @initial 2 nM + OB = d1 d2a d2b d2c @constant 100 nM + +The concentration specification (e.g. ``@initial 10 nM``) is **optional, but +relevant** for both verification and simulation of DSD systems. Nuskell's +verification has to be provided with the information of which species correspond +to signal and fuel species. + +A complex with a **corresponding name in the formal CRN**, is **always** +interpreted as a **signal species**, independent of whether or not `constant` or +`initial` concentrations have been specified. Species that are not present in +formal CRN default to **fuel species** if: **(i)** they have no concentration specified, +or **(ii)** their concentration is higher than ``0``. Variant (i) allows a compact +DSD system specification, which is equivalent to the format of a ``PIL`` file when +using option ``--pilfile``, and compatible with input for the +peppercornenumerator. +Variant (ii) enables us to define named **intermediate complexes** as those which +are explicitly **initially not present**, i.e are followed by the ``@initial 0 +nM`` tag. Note, do **not** use ``@constant 0 nM`` to specify an intermediate +species, as the behavior of Nuskell is currently undefined and might change in +future versions. + +The following ``PIL`` file shows a complete DSD system specification, including +initial concentrations for signal species, formal species and all enumerated +intermediate species: + +.. code-block:: none + + # + # Zhang, Turberfield, Yurke, Winfree (2007) + # "Engineering Entropy-Driven Reactions and Networks Catalyzed by DNA" + # + # A DSD implementation of the catalyst reaction (Figure 1A + 1D) + # Note: Domain 2 is actually contains two toeholds (2a, 2b) + # + # CRN: + # C + S -> C + OB + # OB -> ROX + # + # verify: + # echo "C + S -> C + OB; OB -> ROX" | nuskell --readpil zhang2007_catalyst.pil --verify pathway bisimulation + # => not pathway equivalent + # => bisimulation equivalent + # echo "C -> C + OB; OB -> ROX" | nuskell --readpil zhang2007_catalyst.pil --verify pathway bisimulation + # => not pathway equivalent + # => bisimulation equivalent + # + # Coded by Stefan Badelt (badelt@caltech.edu) + + # Domains + length d1 = 10 + length d2a = 6 + length d2b = 6 + length d2c = 12 + length d3 = 4 + length d4 = 16 + length d5 = 6 + length d6 = 16 + + # Species + C = d4 d5 @initial 2 nM # defaults to fuel + OB = d1 d2a d2b d2c @initial 0 nM # defaults to intermediate + ROX = d1 d2a @initial 0 nM # defaults to intermediate + S = d1 d2a( d2b( d2c( + d6 d3( d4( + d5* ) ) ) ) ) @initial 100 nM # defaults to fuel + F = d2a d2b d2c d3 d4 @initial 100 nM # defaults to fuel + OR = d1( d2a( + d2b* ) ) @initial 100 nM # defaults to fuel + SB = d6 d3 d4 @initial 0 nM # defaults to intermediate + + +.. _Background : + +---------- +Background +---------- + +DSD enumeration +--------------- +The domain-level representation provides a more coarse-grained perspective on +nucleic acid folding than the single-nucleotide-level. At the nucleotide-level +every step is a base pair opening or closing reaction and the corresponding rate +can be calculated from the free energy change of a reaction. On the +domain-level, we consider a more diverse set of reactions in order to compensate +for the fine-grained details that can happen on the sequence level. Nuskell +uses a domain-level reaction enumeration library [`peppercornenumerator`_], to +predict desired and, potentially, undesired reactions emerging from previously +compiled signal and fuel species. + +The general types of reactions are spontaneous **binding and unbinding of domains**, +**3-way branch migration**, **4-way branch migration** and **remote toehold +branch-migration**. Peppercorn's enumeration semantics are +justified based on the assumption that the DSD system is operated at +sufficiently low concentrations, such that unimolecular reactions always go to +completion before the next bimolecular interaction takes place. +Under the assumptions of low concentrations, a **condensed** CRN can be +calculated, with reactions that indicate just the eventual results after all +unimolecular reactions complete, and with rate constants systematically derived +from the detailed reaction network rate constants. + +There are **many** options available to adjust the semantics of reaction +enumeration, they are described in detail in [`Grun et al. (2014)`_]. + +**More:** + * Peppercornenumerator: `Grun et al. (2014)`_ + +CRN equivalence +--------------- +The most fundamental requirement towards compilation of large scale DSD systems, +is verification. Every formal reaction is translated into multiple +implementation reactions. Thus, there are many possibilities to introduce +`bugs`, i.e. unwanted side reactions that alter the implemented algorithm. +Nuskell supports currently variants of two case-by-case verification strategies +that compare formal CRNs with their implementations. As intended, our approach +does not verify the general correctness of a particular scheme, but the +correctness of a particular implementation. + +**Pathway decomposition equivalence.** +The core idea is to represent each implementation trajectory as a +combination of independent pathways of reactions between formal species. +Pathway decomposition yields a set of pathways which are +indivisible (or `prime`) and are called the `formal basis` of a CRN. +The formal basis is unique for any valid implementation. Any two CRNs are said +to be equivalent if they have the same formal basis. Conveniently, a CRN +without intermediate species has itself as the formal basis, but it is worth +pointing out that this equivalence relation allows for the comparison of one +implementation with another implementation. + +**CRN bisimulation verification.** A CRN bisimulation is an +interpretation of the implementation CRN, where every implementation +species is mapped to a multiset of formal species. This often yields so-called +`trivial` reactions, where reactants and products do not change according +to the interpretation. An +interpretation is only a bisimulation, if three conditions are fulfilled: **(i) +atomic condition** -- for every formal species there exists an +implementation species that interprets to it, **(ii) delimiting condition** +-- any reaction in the implementation is either trivial or a valid formal +reaction, and **(iii) permissive condition** -- for any initial condition in +the implementation CRN, the set of possible next non-trivial reactions is +exactly the same as it would be in the formal CRN. CRNs are said to be +bisimulation equivalent, if the translation can be interpreted as an +implementation of that formal CRN. + +**More:** + * CRN bisimulation: `Johnson et al. (2016)`_ + * Pathway decomposition equivalence: `Shin et al. (2014)`_ + +Simulations of DSD systems +-------------------------- +Translate enumerated CRNs into ODEs + .. _API Reference: @@ -37,36 +318,53 @@ Nuskell API ----------- .. toctree:: - :maxdepth: 2 - :caption: Contents: - - framework - ioutils - objects - crnutils - dsdcompiler.objects - dsdcompiler.compiler - dsdcompiler.interpreter - dsdenumerator - crnverifier + :maxdepth: 2 + + compiler + parser + interpreter + enumeration + verifier + objects + +.. Nuskell Objects +.. ----------------------- +.. +.. Input Parsers +.. ----------------------- +.. +.. CRN-to-DSD Translation +.. ----------------------- +.. +.. CRN Equivalence +.. ----------------------- +.. +.. Output Formats +.. ----------------------- .. _Developer Guidelines: Developer Guidelines ==================== -Please document code using the `[Google Docstring Guidelines] `_. -If possible, provide unittests that demonstrate the functionalty of any new code contribution. +In order to ensure sustainability of the Nuskell compiler package, there +are a few rules for developers before submitting a pull request. + + * **Use Google docstring format** `[Google Docstring Guidelines] `_ + + +The Nuskell `repository`_ can be found on ``GitHub``: + +https://github.com/DNA-and-Natural-Algorithms-Group/nuskell .. _repository: https://github.com/DNA-and-Natural-Algorithms-Group/nuskell .. _peppercornenumerator: https://github.com/DNA-and-Natural-Algorithms-Group/peppercornenumerator .. _crnsimulator: https://github.com/bad-ants-fleet/crnsimulator .. _Badelt et al. (2017): http://dna.caltech.edu/DNAresearch_publications.html#NuskellCompiler -.. _Badelt et al. (2020): http://dna.caltech.edu/DNAresearch_publications.html#Peppercorn -.. _Shin et al. (2019): http://dna.caltech.edu/DNAresearch_publications.html#PathwayDecomposition -.. _Johnson et al. (2019): http://dna.caltech.edu/DNAresearch_publications.html#CRN-Bisimulation - +.. _Grun et al. (2014): http://dna.caltech.edu/DNAresearch_publications.html#Peppercorn +.. _Shin et al. (2014): http://dna.caltech.edu/DNAresearch_publications.html#PathwayDecomposition +.. _Johnson et al. (2016): http://dna.caltech.edu/DNAresearch_publications.html#CRN-Bisimulation Indices and tables ================== @@ -74,3 +372,4 @@ Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` + diff --git a/docs/interpreter.rst b/docs/interpreter.rst new file mode 100644 index 0000000..81634f1 --- /dev/null +++ b/docs/interpreter.rst @@ -0,0 +1,8 @@ +nuskell.interpreter +=================== + +API documentation of the nuskell.compiler library + +.. automodule:: nuskell.interpreter.interpreter + :members: + diff --git a/docs/objects.rst b/docs/objects.rst index 3a9571b..31391b7 100644 --- a/docs/objects.rst +++ b/docs/objects.rst @@ -1,6 +1,9 @@ nuskell.objects -=================== +=============== + +API documentation of the nuskell.objects library .. automodule:: nuskell.objects - :members: + :members: TestTube, TestTubeIO, NuskellComplex, NuskellDomain, NuskellReaction + diff --git a/docs/parser.rst b/docs/parser.rst new file mode 100644 index 0000000..bac53c3 --- /dev/null +++ b/docs/parser.rst @@ -0,0 +1,15 @@ +nuskell.parser +================= + +API documentation of the nuskell.parser library + +.. .. automodule:: nuskell.parser.ts_parser +.. :members: +.. +.. .. automodule:: nuskell.parser.crn_parser +.. :members: +.. +.. .. automodule:: nuskell.parser.dom_parser +.. :members: + + diff --git a/docs/tlstutorial.rst b/docs/tlstutorial.rst index 36bb8b6..45ab3e4 100644 --- a/docs/tlstutorial.rst +++ b/docs/tlstutorial.rst @@ -3,7 +3,6 @@ The `Nuskell` programming language ================================== - **Translation schemes** are design algorithms that translate a chemical reaction network (CRN) into a domain-level strand displacement (DSD) system. The `Nuskell` programming language is inspired by the functional programming @@ -11,7 +10,6 @@ language *Haskell* and provides DSD specific classes, functions and macros to generalize translations for arbitrary CRNs. This section describes the ``syntax`` of the `Nuskell` programming language in order to add new translation schemes to the scheme library. -A library of existing schemes can be found in the official Nuskell `repository`_. ------ Syntax @@ -315,4 +313,3 @@ Built-in functions written in the `Nuskell` programming language: function map2(f, y, x) = if len(x) == 0 then [] else [f(y, x[0])] + map2(f, y, tail(x)) -.. _repository: https://github.com/DNA-and-Natural-Algorithms-Group/nuskell diff --git a/docs/verifier.rst b/docs/verifier.rst new file mode 100644 index 0000000..11277f4 --- /dev/null +++ b/docs/verifier.rst @@ -0,0 +1,17 @@ +nuskell.verifier +================= + +API documentation of the nuskell.verifier library. Only the wrapper function +for all supported notions is documented at this point. + +.. automodule:: nuskell.verifier.verifier + :members: + +.. .. automodule:: nuskell.verifier.basis_finder +.. :members: +.. +.. .. automodule:: nuskell.verifier.crn_pathway_equivalence +.. :members: +.. +.. .. automodule:: nuskell.verifier.crn_bisimulation_equivalence +.. :members: diff --git a/nuskell/crnverifier.py b/nuskell/crnverifier.py index e3ea00b..3bfbfb2 100644 --- a/nuskell/crnverifier.py +++ b/nuskell/crnverifier.py @@ -18,11 +18,34 @@ compositional_hybrid_test, modular_crn_bisimulation_test) -class TimeoutError(Exception): - pass +from threading import Thread +import functools -def handler(signum, frame): - raise TimeoutError('Time over') +def timer_func(timeout): + def deco(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + res = [Exception('function [%s] timeout [%s seconds] exceeded!' % (func.__name__, timeout))] + def newFunc(): + try: + res[0] = func(*args, **kwargs) + except Exception as e: + res[0] = e + + t = Thread(target=newFunc) + t.daemon = True + try: + t.start() + t.join(timeout) + except Exception as je: + print('error starting thread') + raise je + ret = res[0] + if isinstance(ret, BaseException): + raise ret + return ret + return wrapper + return deco def verify(fcrn, icrn, formals, method, interpretation = None, timeout = 0): """Verify the equivalence of a formal CRN and its implementation CRN. @@ -53,8 +76,8 @@ def verify(fcrn, icrn, formals, method, interpretation = None, timeout = 0): fcrn = [list(rxn[:2]) for rxn in split_reversible_rxns(fcrn)] icrn = [list(rxn[:2]) for rxn in split_reversible_rxns(icrn)] - signal.signal(signal.SIGALRM, handler) - signal.alarm(timeout) + timer_func(timeout) + try: if 'crn-bisimulation' in method: if method[-2:] == '-ls': @@ -63,39 +86,37 @@ def verify(fcrn, icrn, formals, method, interpretation = None, timeout = 0): permissive_check = 'bruteforce' else: permissive_check = 'graphsearch' - v, i = crn_bisimulation_test(fcrn, - icrn, + v, i = crn_bisimulation_test(fcrn, + icrn, formals, interpretation = interpretation, - permissive = permissive_check) + permissive = permissive_check) elif method == 'pathway-decomposition': v = pathway_decomposition_eq([fcrn, icrn], formals) i = None elif method == 'compositional-hybrid': - v, i = compositional_hybrid_test(fcrn, - icrn, + v, i = compositional_hybrid_test(fcrn, + icrn, formals, interpretation) elif method == 'integrated-hybrid': - v, i = integrated_hybrid_test(fcrn, - icrn, + v, i = integrated_hybrid_test(fcrn, + icrn, formals, interpretation) else: raise RuntimeError('Unknown verification method.') - except TimeoutError: + except Exception: v, i = None, None finally: - signal.alarm(0) - return v, i + return v, i def verify_modules(fcrns, icrns, formals, method, interpretation = None, timeout = 0): """ Choose from different algorithms for modular CRN bisimulation. """ fcrns = [[list(rxn[:2]) for rxn in split_reversible_rxns(mod)] for mod in fcrns] icrns = [[list(rxn[:2]) for rxn in split_reversible_rxns(mod)] for mod in icrns] - signal.signal(signal.SIGALRM, handler) - signal.alarm(timeout) + timer_func(timeout) try: if 'crn-bisimulation' in method: if method[-2:] == '-ls': @@ -104,15 +125,14 @@ def verify_modules(fcrns, icrns, formals, method, interpretation = None, timeout permissive_check = 'bruteforce' else: permissive_check = 'graphsearch' - v, i = modular_crn_bisimulation_test(fcrns, - icrns, + v, i = modular_crn_bisimulation_test(fcrns, + icrns, formals, - interpretation = interpretation, + interpretation = interpretation, permissive = permissive_check) else: raise RuntimeError('Unsupported verification method.') except TimeoutError: v, i = None, None finally: - signal.alarm(0) - return v, i + return v, i diff --git a/nuskell/dsdcompiler/interpreter.py b/nuskell/dsdcompiler/interpreter.py index 36233c4..35fe059 100644 --- a/nuskell/dsdcompiler/interpreter.py +++ b/nuskell/dsdcompiler/interpreter.py @@ -477,8 +477,8 @@ def complement(args): # args[0] forces us to introduce additional lists ... for i in range(len(x)): x[i] = [x[i]] - return list(reversed(map(NuskellFunctions.complement, x))) - elif isinstance(x, NuskellDomain): + return list(reversed(map(self.complement, x))) + elif isinstance(x, Domain): log.warning(f'Untested function: {~x}') return ~x elif x == "(": diff --git a/nuskell/dsdenumerator.py b/nuskell/dsdenumerator.py index ade2253..d41c98c 100644 --- a/nuskell/dsdenumerator.py +++ b/nuskell/dsdenumerator.py @@ -324,10 +324,9 @@ def get_matching_complexes(regex, hist): def get_peppercorn_args(args): """Transfer options to self._enumerator object. - Do NOT change default values here. These are supposed to be the defaults of peppercorn! Defaults for nuskell or any other script using this library are - set with the argparse object of your script, e.g. nuskell/framework.py. + set with the argparse object of your script, e.g. nuskell: scripts/nuskell. """ kwargs = dict() diff --git a/nuskell/framework.py b/nuskell/framework.py index 6f16e33..0a947a9 100644 --- a/nuskell/framework.py +++ b/nuskell/framework.py @@ -317,8 +317,8 @@ def main(): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Parse and process input CRN # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # - input_crn = "".join(sys.stdin.readlines()) - fcrn, fsc = parse_crn_string(input_crn) + input_crn = "".join(sys.stdin.readlines()).replace("\"", '') + fcrn, fsc = parse_crn_string(input_crn.replace('"', '')) # ~~~~~~~~~~~~~~~~~~ # # Do the translation # diff --git a/nuskell/ioutils.py b/nuskell/ioutils.py index 17c8b70..870e9ae 100644 --- a/nuskell/ioutils.py +++ b/nuskell/ioutils.py @@ -10,9 +10,6 @@ NuskellMacrostate, NuskellReaction) -class NuskellObjectError(Exception): - pass - def get_domains(complexes): """ Return a set of domains present in the TestTube. """ domains = set() @@ -242,7 +239,6 @@ def pair_table(ss, chars=['.']): dnaexpr = [[]] pos = 0 - flag = None for e, d in enumerate(ptab): if d == '+': flag = 'top' if flag == 'bound' else flag diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fc2dd76 --- /dev/null +++ b/setup.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +from setuptools import setup + +with open("README.md", "r") as fh: + LONG_DESCRIPTION = fh.read() + +setup( + name = 'nuskell', + version = '0.8', + description = 'Domain-level strand displacement compiler', + long_description = LONG_DESCRIPTION, + long_description_content_type = 'text/markdown', + author = 'Stefan Badelt, Seung Woo Shin, Robert Johnson, Qing Dong, Erik Winfree', + author_email = 'winfree@caltech.edu', + maintainer = 'Stefan Badelt', + maintainer_email = 'bad-ants-fleet@posteo.eu', + url = 'http://www.github.com/DNA-and-Natural-Algorithms-Group/nuskell/', + license = 'MIT', + classifiers = [ + 'Development Status :: 4 - Beta', + 'Programming Language :: Python :: 3.8', + 'Intended Audience :: Science/Research', + ], + python_requires = '>=3.8', + install_requires = [ + 'natsort', + 'pyparsing', + 'dsdobjects>=0.8', + 'peppercornenumerator>=1.1', + 'crnverifier>=0.3'], + packages = ['nuskell', 'nuskell.dsdcompiler'], + include_package_data = True, + package_data = {'nuskell.dsdcompiler': ['schemes/literature/*.ts', + 'schemes/variants/*.ts']}, + test_suite = 'tests', + entry_points = { + 'console_scripts': [ + 'nuskell=nuskell.framework:main', + 'nuskellCMP=nuskell.compare_schemes:main' + ], + } +) + diff --git a/tests/test_schemes.py b/tests/test_schemes.py index 90cd7de..a180edc 100644 --- a/tests/test_schemes.py +++ b/tests/test_schemes.py @@ -38,7 +38,7 @@ try: import pandas as pd except ImportError as err: - print(f'Unittest: {__name__} needs pandas installed.') + log.warning(f'Unittest: {__name__} needs pandas installed.') SKIP = True def compare_snapshots(cmp_file, new_file, crns, schemes, args = None): @@ -104,10 +104,14 @@ def test_bigger_nuskellCMP(self): @unittest.skipIf(SKIP or SKIP_SLOW, "slow tests are disabled by default") class SystemSnapshotTests(unittest.TestCase): def setUp(self): + comp.SCHEME_DIRS = ['schemes/literature/'] self.lit = list(chain(*get_builtin_schemes().values())) + comp.SCHEME_DIRS = ['schemes/variants/'] self.var = list(chain(*get_builtin_schemes().values())) + comp.SCHEME_DIRS = ['schemes/literature/', 'schemes/variants/'] def tearDown(self): + comp.SCHEME_DIRS = ['schemes/literature/', 'schemes/variants/'] clear_memory() clear_pepper_memory() @@ -194,10 +198,14 @@ def test_bin_counter_01_var(self): @unittest.skipIf(SKIP or SKIP_SLOW, "slow tests are disabled by default") class IrreversibleRxnSnapshotTest(unittest.TestCase): def setUp(self): + comp.SCHEME_DIRS = ['schemes/literature/'] self.lit = list(chain(*get_builtin_schemes().values())) + comp.SCHEME_DIRS = ['schemes/variants/'] self.var = list(chain(*get_builtin_schemes().values())) + comp.SCHEME_DIRS = ['schemes/literature/', 'schemes/variants/'] def tearDown(self): + comp.SCHEME_DIRS = ['schemes/literature/', 'schemes/variants/'] clear_memory() clear_pepper_memory() @@ -248,10 +256,14 @@ def test_binary_var(self): @unittest.skipIf(SKIP or SKIP_SLOW, "slow tests are disabled by default") class ReversibleRxnSnapshotTest(unittest.TestCase): def setUp(self): + comp.SCHEME_DIRS = ['schemes/literature/'] self.lit = list(chain(*get_builtin_schemes().values())) + comp.SCHEME_DIRS = ['schemes/variants/'] self.var = list(chain(*get_builtin_schemes().values())) + comp.SCHEME_DIRS = ['schemes/literature/', 'schemes/variants/'] def tearDown(self): + comp.SCHEME_DIRS = ['schemes/literature/', 'schemes/variants/'] clear_memory() clear_pepper_memory()