From 53844ed6b39ee724b0497b5711f56e6b41909026 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 6 May 2022 08:53:30 +0200 Subject: [PATCH 01/67] Update poetry configuration --- poetry.lock | 739 +++++++++++++++++++++++++++++-------------------- pyproject.toml | 2 +- 2 files changed, 442 insertions(+), 299 deletions(-) diff --git a/poetry.lock b/poetry.lock index 22be278..ffb8dec 100644 --- a/poetry.lock +++ b/poetry.lock @@ -16,17 +16,17 @@ python-versions = "*" [[package]] name = "astroid" -version = "2.4.2" +version = "2.9.0" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false -python-versions = ">=3.5" +python-versions = "~=3.6" [package.dependencies] -lazy-object-proxy = ">=1.4.0,<1.5.0" -six = ">=1.12,<2.0" -typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} -wrapt = ">=1.11,<2.0" +lazy-object-proxy = ">=1.4.0" +typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} +typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} +wrapt = ">=1.11,<1.14" [[package]] name = "atomicwrites" @@ -52,30 +52,33 @@ tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.i [[package]] name = "babel" -version = "2.8.0" +version = "2.10.1" description = "Internationalization utilities" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.dependencies] pytz = ">=2015.7" [[package]] name = "certifi" -version = "2020.6.20" +version = "2021.10.8" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = "*" [[package]] -name = "chardet" -version = "3.0.4" -description = "Universal encoding detector for Python 2 and 3" +name = "charset-normalizer" +version = "2.0.12" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] [[package]] name = "click" @@ -87,7 +90,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "colorama" -version = "0.4.3" +version = "0.4.4" description = "Cross-platform colored terminal text." category = "main" optional = false @@ -95,14 +98,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "5.3" +version = "6.2" description = "Code coverage measurement for Python" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +python-versions = ">=3.6" [package.extras] -toml = ["toml"] +toml = ["tomli"] [[package]] name = "decorator" @@ -122,25 +125,26 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "gitdb" -version = "4.0.5" +version = "4.0.9" description = "Git Object Database" category = "dev" optional = false -python-versions = ">=3.4" +python-versions = ">=3.6" [package.dependencies] -smmap = ">=3.0.1,<4" +smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.8" +version = "3.1.20" description = "Python Git Library" category = "dev" optional = false -python-versions = ">=3.4" +python-versions = ">=3.6" [package.dependencies] gitdb = ">=4.0.1,<5" +typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\""} [[package]] name = "graphviz" @@ -157,7 +161,7 @@ test = ["mock (>=3)", "pytest (>=4)", "pytest-mock (>=2)", "pytest-cov"] [[package]] name = "hypothesis" -version = "5.36.1" +version = "5.49.0" description = "A library for property-based testing" category = "dev" optional = false @@ -168,29 +172,32 @@ attrs = ">=19.2.0" sortedcontainers = ">=2.1.0,<3.0.0" [package.extras] -all = ["black (>=19.10b0)", "click (>=7.0)", "django (>=2.2)", "dpcontracts (>=0.4)", "lark-parser (>=0.6.5)", "numpy (>=1.9.0)", "pandas (>=0.19)", "pytest (>=4.3)", "python-dateutil (>=1.4)", "pytz (>=2014.1)"] +all = ["black (>=19.10b0)", "click (>=7.0)", "django (>=2.2)", "dpcontracts (>=0.4)", "lark-parser (>=0.6.5)", "libcst (>=0.3.16)", "numpy (>=1.9.0)", "pandas (>=0.25)", "pytest (>=4.3)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "importlib-resources (>=3.3.0)", "importlib-metadata", "backports.zoneinfo (>=0.2.1)", "tzdata (>=2020.4)"] cli = ["click (>=7.0)", "black (>=19.10b0)"] +codemods = ["libcst (>=0.3.16)"] dateutil = ["python-dateutil (>=1.4)"] django = ["pytz (>=2014.1)", "django (>=2.2)"] dpcontracts = ["dpcontracts (>=0.4)"] ghostwriter = ["black (>=19.10b0)"] lark = ["lark-parser (>=0.6.5)"] numpy = ["numpy (>=1.9.0)"] -pandas = ["pandas (>=0.19)"] +pandas = ["pandas (>=0.25)"] pytest = ["pytest (>=4.3)"] pytz = ["pytz (>=2014.1)"] +redis = ["redis (>=3.0.0)"] +zoneinfo = ["importlib-resources (>=3.3.0)", "backports.zoneinfo (>=0.2.1)", "tzdata (>=2020.4)"] [[package]] name = "idna" -version = "2.10" +version = "3.3" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.5" [[package]] name = "imagesize" -version = "1.2.0" +version = "1.3.0" description = "Getting image size from png/jpeg/jpeg2000/gif file" category = "main" optional = false @@ -198,22 +205,24 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "2.0.0" +version = "4.8.3" description = "Read metadata from Python packages" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6" [package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "rst.linker"] -testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +perf = ["ipython"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "isort" -version = "5.5.3" +version = "5.8.0" description = "A Python utility / library to sort Python imports." category = "dev" optional = false @@ -226,17 +235,17 @@ colors = ["colorama (>=0.4.3,<0.5.0)"] [[package]] name = "jinja2" -version = "2.11.2" +version = "3.0.3" description = "A very fast and expressive template engine." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" [package.dependencies] -MarkupSafe = ">=0.23" +MarkupSafe = ">=2.0" [package.extras] -i18n = ["Babel (>=0.8)"] +i18n = ["Babel (>=2.7)"] [[package]] name = "lark-parser" @@ -248,19 +257,19 @@ python-versions = "*" [[package]] name = "lazy-object-proxy" -version = "1.4.3" +version = "1.7.1" description = "A fast and thorough lazy object proxy." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [[package]] name = "markupsafe" -version = "1.1.1" +version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +python-versions = ">=3.6" [[package]] name = "mccabe" @@ -272,7 +281,7 @@ python-versions = "*" [[package]] name = "more-itertools" -version = "8.5.0" +version = "8.12.0" description = "More routines for operating on iterables, beyond itertools" category = "dev" optional = false @@ -304,14 +313,14 @@ python-versions = "*" [[package]] name = "networkx" -version = "2.5" +version = "2.5.1" description = "Python package for creating and manipulating graphs and networks" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -decorator = ">=4.3.0" +decorator = ">=4.3,<5" [package.extras] all = ["numpy", "scipy", "pandas", "matplotlib", "pygraphviz", "pydot", "pyyaml", "lxml", "pytest"] @@ -328,23 +337,26 @@ scipy = ["scipy"] [[package]] name = "packaging" -version = "20.4" +version = "21.3" description = "Core utilities for Python packages" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" -six = "*" +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] -name = "pbr" -version = "5.5.0" -description = "Python Build Reasonableness" +name = "platformdirs" +version = "2.4.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=2.6" +python-versions = ">=3.6" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] [[package]] name = "pluggy" @@ -362,42 +374,47 @@ dev = ["pre-commit", "tox"] [[package]] name = "py" -version = "1.9.0" +version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pygments" -version = "2.7.1" +version = "2.12.0" description = "Pygments is a syntax highlighting package written in Python." category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [[package]] name = "pylint" -version = "2.6.0" +version = "2.12.0" description = "python code static checker" category = "dev" optional = false -python-versions = ">=3.5.*" +python-versions = "~=3.6" [package.dependencies] -astroid = ">=2.4.0,<=2.5" +astroid = ">=2.9.0,<2.10" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" -toml = ">=0.7.1" +platformdirs = ">=2.2.0" +toml = ">=0.9.2" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [[package]] name = "pyparsing" -version = "2.4.7" +version = "3.0.7" description = "Python parsing module" category = "main" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.6" + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pysmt" @@ -435,22 +452,23 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "nose", "requests", "mock"] [[package]] name = "pytest-cov" -version = "2.10.1" +version = "2.12.1" description = "Pytest plugin for measuring coverage." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] -coverage = ">=4.4" +coverage = ">=5.2.1" pytest = ">=4.6" +toml = "*" [package.extras] -testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] [[package]] name = "pytz" -version = "2020.1" +version = "2022.1" description = "World timezone definitions, modern and historical" category = "main" optional = false @@ -458,21 +476,21 @@ python-versions = "*" [[package]] name = "requests" -version = "2.24.0" +version = "2.27.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] certifi = ">=2017.4.17" -chardet = ">=3.0.2,<4" -idna = ">=2.5,<3" -urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "rope" @@ -487,7 +505,7 @@ dev = ["pytest"] [[package]] name = "six" -version = "1.15.0" +version = "1.16.0" description = "Python 2 and 3 compatibility utilities" category = "main" optional = false @@ -495,23 +513,23 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "smmap" -version = "3.0.4" +version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [[package]] name = "snowballstemmer" -version = "2.0.0" -description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." category = "main" optional = false python-versions = "*" [[package]] name = "sortedcontainers" -version = "2.2.2" +version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" category = "dev" optional = false @@ -519,7 +537,7 @@ python-versions = "*" [[package]] name = "sphinx" -version = "3.2.1" +version = "3.5.4" description = "Python documentation generator" category = "main" optional = false @@ -529,7 +547,7 @@ python-versions = ">=3.5" alabaster = ">=0.7,<0.8" babel = ">=1.3" colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.12" +docutils = ">=0.12,<0.17" imagesize = "*" Jinja2 = ">=2.3" packaging = "*" @@ -545,27 +563,27 @@ sphinxcontrib-serializinghtml = "*" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.780)", "docutils-stubs"] -test = ["pytest", "pytest-cov", "html5lib", "typed-ast", "cython"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.800)", "docutils-stubs"] +test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] name = "sphinx-autodoc-typehints" -version = "1.11.0" +version = "1.12.0" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" category = "dev" optional = false -python-versions = ">=3.5.2" +python-versions = ">=3.6" [package.dependencies] Sphinx = ">=3.0" [package.extras] -test = ["pytest (>=3.1.0)", "typing-extensions (>=3.5)", "sphobjinv (>=2.0)", "dataclasses"] +test = ["pytest (>=3.1.0)", "typing-extensions (>=3.5)", "sphobjinv (>=2.0)", "Sphinx (>=3.2.0)", "dataclasses"] type_comments = ["typed-ast (>=1.4.0)"] [[package]] name = "sphinx-bootstrap-theme" -version = "0.7.1" +version = "0.8.1" description = "Sphinx Bootstrap Theme." category = "dev" optional = false @@ -573,14 +591,15 @@ python-versions = "*" [[package]] name = "sphinx-click" -version = "2.5.0" +version = "2.7.1" description = "Sphinx extension that automatically documents click applications" category = "dev" optional = false python-versions = "*" [package.dependencies] -pbr = ">=2.0" +click = ">=6.0,<8.0" +docutils = "*" sphinx = ">=1.5,<4.0" [[package]] @@ -622,11 +641,11 @@ test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "1.0.3" +version = "2.0.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] @@ -645,14 +664,14 @@ test = ["pytest", "flake8", "mypy"] [[package]] name = "sphinxcontrib-katex" -version = "0.7.1" +version = "0.7.2" description = "|tests| |docs| |license|" category = "main" optional = false python-versions = "*" [package.dependencies] -sphinx = ">=1.6" +sphinx = ">=1.6,<4.0.0" [[package]] name = "sphinxcontrib-qthelp" @@ -668,7 +687,7 @@ test = ["pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.4" +version = "1.1.5" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." category = "main" optional = false @@ -680,15 +699,15 @@ test = ["pytest"] [[package]] name = "toml" -version = "0.10.1" +version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" category = "dev" optional = false -python-versions = "*" +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "typed-ast" -version = "1.4.1" +version = "1.4.3" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false @@ -696,23 +715,23 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.7.4.3" -description = "Backported and Experimental Type Hints for Python 3.5+" +version = "4.1.1" +description = "Backported and Experimental Type Hints for Python 3.6+" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "urllib3" -version = "1.25.10" +version = "1.26.9" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] @@ -725,11 +744,11 @@ python-versions = "*" [[package]] name = "wrapt" -version = "1.12.1" +version = "1.13.3" description = "Module for decorators, wrappers and monkey patching." category = "dev" optional = false -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "yapf" @@ -741,20 +760,20 @@ python-versions = "*" [[package]] name = "zipp" -version = "3.2.0" +version = "3.6.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.6" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" python-versions = "^3.6" -content-hash = "25f1ae11c27bd1ce560c943b97e8bae7ef2b022cbb105cef582fb407a2d4dc7b" +content-hash = "b9471606133f20634e77f8d530a1871b06bc8c14be3c9bd91dab65569b071191" [metadata.files] alabaster = [ @@ -766,8 +785,8 @@ algebraic-data-types = [ {file = "algebraic_data_types-0.1.3-py3-none-any.whl", hash = "sha256:bbaf314d236977a020df4b5bdb1aeb03a30ec9c2e4053ae280565aa3c449a700"}, ] astroid = [ - {file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"}, - {file = "astroid-2.4.2.tar.gz", hash = "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703"}, + {file = "astroid-2.9.0-py3-none-any.whl", hash = "sha256:776ca0b748b4ad69c00bfe0fff38fa2d21c338e12c84aa9715ee0d473c422778"}, + {file = "astroid-2.9.0.tar.gz", hash = "sha256:5939cf55de24b92bda00345d4d0659d01b3c7dafb5055165c330bc7c568ba273"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, @@ -778,60 +797,73 @@ attrs = [ {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, ] babel = [ - {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"}, - {file = "Babel-2.8.0.tar.gz", hash = "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38"}, + {file = "Babel-2.10.1-py3-none-any.whl", hash = "sha256:3f349e85ad3154559ac4930c3918247d319f21910d5ce4b25d439ed8693b98d2"}, + {file = "Babel-2.10.1.tar.gz", hash = "sha256:98aeaca086133efb3e1e2aad0396987490c8425929ddbcfe0550184fdc54cd13"}, ] certifi = [ - {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, - {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] -chardet = [ - {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, - {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, +charset-normalizer = [ + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] colorama = [ - {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, - {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ - {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, - {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, - {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, - {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, - {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, - {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, - {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, - {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, - {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, - {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, - {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, - {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, - {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, - {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, - {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, - {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, - {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, - {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, - {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, - {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, - {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, - {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, - {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, - {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, - {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, - {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, - {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, - {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, - {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, - {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, - {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, - {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, - {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, - {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, + {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"}, + {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"}, + {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"}, + {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"}, + {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"}, + {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"}, + {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"}, + {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"}, + {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"}, + {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"}, + {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"}, + {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"}, + {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"}, + {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"}, + {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"}, + {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"}, + {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"}, + {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"}, + {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"}, + {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"}, + {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"}, + {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"}, + {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"}, + {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"}, + {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"}, + {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"}, + {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"}, + {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"}, + {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"}, + {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"}, + {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"}, + {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"}, + {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"}, + {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"}, + {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"}, + {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"}, + {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"}, + {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"}, + {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"}, + {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"}, + {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"}, + {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"}, + {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"}, + {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"}, + {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"}, + {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"}, + {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"}, ] decorator = [ {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, @@ -842,109 +874,161 @@ docutils = [ {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, ] gitdb = [ - {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, - {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, + {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, + {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, ] gitpython = [ - {file = "GitPython-3.1.8-py3-none-any.whl", hash = "sha256:1858f4fd089abe92ae465f01d5aaaf55e937eca565fb2c1fce35a51b5f85c910"}, - {file = "GitPython-3.1.8.tar.gz", hash = "sha256:080bf8e2cf1a2b907634761c2eaefbe83b69930c94c66ad11b65a8252959f912"}, + {file = "GitPython-3.1.20-py3-none-any.whl", hash = "sha256:b1e1c269deab1b08ce65403cf14e10d2ef1f6c89e33ea7c5e5bb0222ea593b8a"}, + {file = "GitPython-3.1.20.tar.gz", hash = "sha256:df0e072a200703a65387b0cfdf0466e3bab729c0458cf6b7349d0e9877636519"}, ] graphviz = [ {file = "graphviz-0.15-py2.py3-none-any.whl", hash = "sha256:403b55553b235875fa521023a06d9c29b46f3a956f960d4e0a5b956bca9eb9ce"}, {file = "graphviz-0.15.zip", hash = "sha256:2b85f105024e229ec330fe5067abbe9aa0d7708921a585ecc2bf56000bf5e027"}, ] hypothesis = [ - {file = "hypothesis-5.36.1-py3-none-any.whl", hash = "sha256:368b8f8363cbd186d4dddfcdb1eef46259ca5205f397a8de5979734b25ba5801"}, - {file = "hypothesis-5.36.1.tar.gz", hash = "sha256:0a6af77ba1d111d39494f82569771bb24ce820484c4be43b204cd430ef7d1be2"}, + {file = "hypothesis-5.49.0-py3-none-any.whl", hash = "sha256:e91111f2f01abf2566041c4c86366aa7f08bfd5b3d858cc77a545fcf67df335e"}, + {file = "hypothesis-5.49.0.tar.gz", hash = "sha256:36a4d5587c34193125d654b61bf9284e24a227d1edd339c49143378658a10c7d"}, ] idna = [ - {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, - {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] imagesize = [ - {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, - {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, + {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"}, + {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, ] importlib-metadata = [ - {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, - {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, + {file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"}, + {file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"}, ] isort = [ - {file = "isort-5.5.3-py3-none-any.whl", hash = "sha256:c16eaa7432a1c004c585d79b12ad080c6c421dd18fe27982ca11f95e6898e432"}, - {file = "isort-5.5.3.tar.gz", hash = "sha256:6187a9f1ce8784cbc6d1b88790a43e6083a6302f03e9ae482acc0f232a98c843"}, + {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"}, + {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"}, ] jinja2 = [ - {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, - {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, + {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, + {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, ] lark-parser = [ {file = "lark-parser-0.8.9.tar.gz", hash = "sha256:78915e9e59c7a3068830fd2d2cd733f7ab0cbea2d7928ebfaac4f8df10e4e989"}, ] lazy-object-proxy = [ - {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win32.whl", hash = "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win32.whl", hash = "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win_amd64.whl", hash = "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-win32.whl", hash = "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239"}, + {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, + {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, ] markupsafe = [ - {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, - {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] more-itertools = [ - {file = "more-itertools-8.5.0.tar.gz", hash = "sha256:6f83822ae94818eae2612063a5101a7311e68ae8002005b5e05f03fd74a86a20"}, - {file = "more_itertools-8.5.0-py3-none-any.whl", hash = "sha256:9b30f12df9393f0d28af9210ff8efe48d10c94f73e5daf886f10c4b0b0b4f03c"}, + {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"}, + {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"}, ] mypy = [ {file = "mypy-0.770-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:a34b577cdf6313bf24755f7a0e3f3c326d5c1f4fe7422d1d06498eb25ad0c600"}, @@ -967,36 +1051,36 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] networkx = [ - {file = "networkx-2.5-py3-none-any.whl", hash = "sha256:8c5812e9f798d37c50570d15c4a69d5710a18d77bafc903ee9c5fba7454c616c"}, - {file = "networkx-2.5.tar.gz", hash = "sha256:7978955423fbc9639c10498878be59caf99b44dc304c2286162fd24b458c1602"}, + {file = "networkx-2.5.1-py3-none-any.whl", hash = "sha256:0635858ed7e989f4c574c2328380b452df892ae85084144c73d8cd819f0c4e06"}, + {file = "networkx-2.5.1.tar.gz", hash = "sha256:109cd585cac41297f71103c3c42ac6ef7379f29788eb54cb751be5a663bb235a"}, ] packaging = [ - {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, - {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] -pbr = [ - {file = "pbr-5.5.0-py2.py3-none-any.whl", hash = "sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"}, - {file = "pbr-5.5.0.tar.gz", hash = "sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea"}, +platformdirs = [ + {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, + {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, ] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] py = [ - {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, - {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pygments = [ - {file = "Pygments-2.7.1-py3-none-any.whl", hash = "sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998"}, - {file = "Pygments-2.7.1.tar.gz", hash = "sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7"}, + {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"}, + {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, ] pylint = [ - {file = "pylint-2.6.0-py3-none-any.whl", hash = "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f"}, - {file = "pylint-2.6.0.tar.gz", hash = "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210"}, + {file = "pylint-2.12.0-py3-none-any.whl", hash = "sha256:ba00afcb1550bc217bbcb0eb76c10cb8335f7417a3323bdd980c29fb5b59f8d2"}, + {file = "pylint-2.12.0.tar.gz", hash = "sha256:245c87e5da54c35b623c21b35debf87d93b18bf9e0229515cc172d0b83d627cd"}, ] pyparsing = [ - {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, - {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, + {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, + {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, ] pysmt = [ {file = "PySMT-0.9.0-py2.py3-none-any.whl", hash = "sha256:2b5ca0560eaacf1720d254f7e1f186fe344e3ea12c72e49036c47af2ab1f81ef"}, @@ -1006,50 +1090,51 @@ pytest = [ {file = "pytest-4.6.11.tar.gz", hash = "sha256:50fa82392f2120cc3ec2ca0a75ee615be4c479e66669789771f1758332be4353"}, ] pytest-cov = [ - {file = "pytest-cov-2.10.1.tar.gz", hash = "sha256:47bd0ce14056fdd79f93e1713f88fad7bdcc583dcd7783da86ef2f085a0bb88e"}, - {file = "pytest_cov-2.10.1-py2.py3-none-any.whl", hash = "sha256:45ec2d5182f89a81fc3eb29e3d1ed3113b9e9a873bcddb2a71faaab066110191"}, + {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, + {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, ] pytz = [ - {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, - {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, + {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, + {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, ] requests = [ - {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, - {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, + {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, + {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, ] rope = [ {file = "rope-0.17.0.tar.gz", hash = "sha256:658ad6705f43dcf3d6df379da9486529cf30e02d9ea14c5682aa80eb33b649e1"}, ] six = [ - {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, - {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] smmap = [ - {file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"}, - {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, + {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, + {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, ] snowballstemmer = [ - {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, - {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] sortedcontainers = [ - {file = "sortedcontainers-2.2.2-py2.py3-none-any.whl", hash = "sha256:c633ebde8580f241f274c1f8994a665c0e54a17724fecd0cae2f079e09c36d3f"}, - {file = "sortedcontainers-2.2.2.tar.gz", hash = "sha256:4e73a757831fc3ca4de2859c422564239a31d8213d09a2a666e375807034d2ba"}, + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] sphinx = [ - {file = "Sphinx-3.2.1-py3-none-any.whl", hash = "sha256:ce6fd7ff5b215af39e2fcd44d4a321f6694b4530b6f2b2109b64d120773faea0"}, - {file = "Sphinx-3.2.1.tar.gz", hash = "sha256:321d6d9b16fa381a5306e5a0b76cd48ffbc588e6340059a729c6fdd66087e0e8"}, + {file = "Sphinx-3.5.4-py3-none-any.whl", hash = "sha256:2320d4e994a191f4b4be27da514e46b3d6b420f2ff895d064f52415d342461e8"}, + {file = "Sphinx-3.5.4.tar.gz", hash = "sha256:19010b7b9fa0dc7756a6e105b2aacd3a80f798af3c25c273be64d7beeb482cb1"}, ] sphinx-autodoc-typehints = [ - {file = "sphinx-autodoc-typehints-1.11.0.tar.gz", hash = "sha256:bbf0b203f1019b0f9843ee8eef0cff856dc04b341f6dbe1113e37f2ebf243e11"}, - {file = "sphinx_autodoc_typehints-1.11.0-py3-none-any.whl", hash = "sha256:89e19370a55db4aef1be2094d8fb1fb500ca455c55b3fcc8d2600ff805227e04"}, + {file = "sphinx-autodoc-typehints-1.12.0.tar.gz", hash = "sha256:193617d9dbe0847281b1399d369e74e34cd959c82e02c7efde077fca908a9f52"}, + {file = "sphinx_autodoc_typehints-1.12.0-py3-none-any.whl", hash = "sha256:5e81776ec422dd168d688ab60f034fccfafbcd94329e9537712c93003bddc04a"}, ] sphinx-bootstrap-theme = [ - {file = "sphinx-bootstrap-theme-0.7.1.tar.gz", hash = "sha256:571e43ccb76d4c6c06576aa24a826b6ebc7adac45a5b54985200128806279d08"}, + {file = "sphinx-bootstrap-theme-0.8.1.tar.gz", hash = "sha256:683e3b735448dadd0149f76edecf95ff4bd9157787e9e77e0d048ca6f1d680df"}, + {file = "sphinx_bootstrap_theme-0.8.1-py2.py3-none-any.whl", hash = "sha256:6ef36206c211846ea6cbdb45bc85645578e7c62d0a883361181708f8b6ea743b"}, ] sphinx-click = [ - {file = "sphinx-click-2.5.0.tar.gz", hash = "sha256:8ba44ca446ba4bb0585069b8aabaa81e833472d6669b36924a398405311d206f"}, - {file = "sphinx_click-2.5.0-py2.py3-none-any.whl", hash = "sha256:6848ba2d084ef2feebae0ce3603c1c02a2ba5ded54fb6c0cf24fd01204a945f3"}, + {file = "sphinx-click-2.7.1.tar.gz", hash = "sha256:1b6175df5392564fd3780000d4627e5a2c8c3b29d05ad311dbbe38fcf5f3327b"}, + {file = "sphinx_click-2.7.1-py2.py3-none-any.whl", hash = "sha256:e738a2c7a87f23e67da4a9e28ca6f085d3ca626f0e4164847f77ff3c36c65df1"}, ] sphinx-git = [ {file = "sphinx-git-11.0.0.tar.gz", hash = "sha256:6bf9d837de108c79fb7db585ebd590fd48f4d1f830b540420d0ca675f3b9f800"}, @@ -1063,73 +1148,131 @@ sphinxcontrib-devhelp = [ {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, ] sphinxcontrib-htmlhelp = [ - {file = "sphinxcontrib-htmlhelp-1.0.3.tar.gz", hash = "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"}, - {file = "sphinxcontrib_htmlhelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f"}, + {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, + {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, ] sphinxcontrib-jsmath = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] sphinxcontrib-katex = [ - {file = "sphinxcontrib-katex-0.7.1.tar.gz", hash = "sha256:fa80aba8af9d78f70a0a255815d44e33e8aca8e806ca6101e0eb18b2b7243246"}, - {file = "sphinxcontrib_katex-0.7.1-py2.py3-none-any.whl", hash = "sha256:a6d0801dc672dfa8b126d658b8d47631eb3ba53d97d9f71fe7f6a69d2011b9c3"}, + {file = "sphinxcontrib-katex-0.7.2.tar.gz", hash = "sha256:14bbf9c30fc5f9975f9e74595ef0cb7864269b159ea7695aca88872c2697eab3"}, + {file = "sphinxcontrib_katex-0.7.2-py2.py3-none-any.whl", hash = "sha256:1fcd6f2f660a50f58687dc717dd3311c8a35ae58bb40d7c1f83103c74f4fee9b"}, ] sphinxcontrib-qthelp = [ {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, ] sphinxcontrib-serializinghtml = [ - {file = "sphinxcontrib-serializinghtml-1.1.4.tar.gz", hash = "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc"}, - {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, + {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, + {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, ] toml = [ - {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, - {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] typed-ast = [ - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, - {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, - {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, - {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, - {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, - {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, - {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, - {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, + {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, + {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, + {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, + {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, + {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, + {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, + {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, + {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, + {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, - {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, - {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, + {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, + {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, ] urllib3 = [ - {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"}, - {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"}, + {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, + {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] wrapt = [ - {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, + {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"}, + {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"}, + {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"}, + {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"}, + {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"}, + {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"}, + {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"}, + {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"}, + {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"}, + {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"}, + {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"}, + {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"}, + {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"}, + {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"}, + {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"}, + {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"}, + {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"}, + {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"}, + {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"}, + {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"}, + {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"}, + {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"}, + {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"}, + {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"}, + {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"}, + {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"}, + {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"}, + {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"}, + {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"}, + {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"}, + {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"}, + {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"}, + {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"}, + {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"}, + {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"}, + {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"}, + {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"}, + {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"}, + {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"}, + {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"}, + {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"}, + {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"}, + {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"}, + {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"}, + {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"}, + {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"}, + {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"}, + {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"}, + {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"}, + {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"}, + {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"}, ] yapf = [ {file = "yapf-0.30.0-py2.py3-none-any.whl", hash = "sha256:3abf61ba67cf603069710d30acbc88cfe565d907e16ad81429ae90ce9651e0c9"}, {file = "yapf-0.30.0.tar.gz", hash = "sha256:3000abee4c28daebad55da6c85f3cd07b8062ce48e2e9943c8da1b9667d48427"}, ] zipp = [ - {file = "zipp-3.2.0-py3-none-any.whl", hash = "sha256:43f4fa8d8bb313e65d8323a3952ef8756bf40f9a5c3ea7334be23ee4ec8278b6"}, - {file = "zipp-3.2.0.tar.gz", hash = "sha256:b52f22895f4cfce194bc8172f3819ee8de7540aa6d873535a8668b730b8b411f"}, + {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, + {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, ] diff --git a/pyproject.toml b/pyproject.toml index 45d8c06..9d44799 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ pylint = "^2.5.2" mypy = "^0.770" yapf = "^0.30.0" sphinx-autodoc-typehints = "^1.10.3" -sphinx-bootstrap-theme = "^0.7.1" +sphinx-bootstrap-theme = "^0.8.1" sphinx-click = "^2.3.2" sphinx-git = "^11.0.0" rope = "^0.17.0" From e6a9c1658e753f27126d1d0d6a9b39b7005746c9 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 6 May 2022 09:50:35 +0200 Subject: [PATCH 02/67] Add testreport to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f1624a3..5145867 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ coverage.xml *.cover .hypothesis/ .pytest_cache/ +testreport.xml # Translations *.mo From 0e4ffaab3337e46eb539dac63bcce7c192c5b3c5 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 6 May 2022 11:38:55 +0200 Subject: [PATCH 03/67] Merge new stuff from forward into ast.py --- probably/pgcl/ast.py | 283 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 268 insertions(+), 15 deletions(-) diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index f6d7b30..5dda191 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -200,6 +200,8 @@ def __str__(self) -> str: if self.typ.bounds is not None: res += " " + str(self.typ.bounds) return res + ";" + elif isinstance(self.typ, FloatType): + return f"float {self.var};" raise ValueError(f"invalid type: {self.typ}") @@ -212,8 +214,26 @@ class ConstDecl(DeclClass): def __str__(self) -> str: return f"const {self.var} := {self.value};" +@attr.s +class ParameterDecl(DeclClass): + """ A parameter declaration with a name and a type.""" + var: Var = attr.ib() + typ: Type = attr.ib() + + def __str__(self) -> str: + if isinstance(self.typ, BoolType): + raise SyntaxError("A parameter cannot be of BoolType.") + elif isinstance(self.typ, NatType): + res = f"nparam {self.var}" + if self.typ.bounds is not None: + res += " " + str(self.typ.bounds) + return res + ";" + elif isinstance(self.typ, FloatType): + return f"rparam {self.var};" + raise ValueError(f"invalid type: {self.typ}") + -Decl = Union[VarDecl, ConstDecl] +Decl = Union[VarDecl, ConstDecl, ParameterDecl] """Union type for all declaration objects. See :class:`DeclClass` for use with isinstance.""" @@ -245,12 +265,16 @@ def __str__(self) -> str: class VarExpr(ExprClass): """A variable is an expression.""" var: Var = attr.ib() + is_parameter: bool = attr.ib(default=False) def __str__(self) -> str: return self.var def __repr__(self) -> str: - return f'VarExpr({repr(self.var)})' + if self.is_parameter: + return f"ParamExpr({repr(self.var)})" + else: + return f'VarExpr({repr(self.var)})' @attr.s(repr=False) @@ -387,11 +411,15 @@ class Binop(Enum): AND = auto() LEQ = auto() LE = auto() + GE = auto() + GEQ = auto() EQ = auto() PLUS = auto() MINUS = auto() TIMES = auto() + POWER = auto() DIVIDE = auto() + MODULO = auto() def is_associative(self) -> bool: """Is this operator associative?""" @@ -407,11 +435,15 @@ def __str__(self) -> str: Binop.AND: "&", Binop.LEQ: "<=", Binop.LE: "<", + Binop.GE: ">", + Binop.GEQ: ">=", Binop.EQ: "=", Binop.PLUS: "+", Binop.MINUS: "-", Binop.TIMES: "*", + Binop.POWER: "^", Binop.DIVIDE: "/", + Binop.MODULO: "%", })[self] @@ -468,11 +500,13 @@ def flatten_expr(expr: "Expr") -> List["Expr"]: return flatten_expr(self) def __str__(self) -> str: + if self.operator == Binop.POWER: + return f'({self.lhs}) {self.operator} ({self.rhs})' return f'{expr_str_parens(self.lhs)} {self.operator} {expr_str_parens(self.rhs)}' @attr.s -class UniformExpr(ExprClass): +class DUniformExpr(ExprClass): """ Chooses a random integer within the (inclusive) interval. @@ -480,8 +514,8 @@ class UniformExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - start: NatLitExpr = attr.ib() - end: NatLitExpr = attr.ib() + start: 'Expr' = attr.ib() + end: 'Expr' = attr.ib() def distribution(self) -> List[Tuple[FloatLitExpr, NatLitExpr]]: r""" @@ -489,10 +523,13 @@ def distribution(self) -> List[Tuple[FloatLitExpr, NatLitExpr]]: probabilities. For the uniform distribution, all probabilites are equal to :math:`\frac{1}{\text{end} - \text{start} + 1}`. """ - width = self.end.value - self.start.value + 1 - prob = FloatLitExpr(Fraction(1, width)) - return [(prob, NatLitExpr(i)) - for i in range(self.start.value, self.end.value + 1)] + if isinstance(self.start, NatLitExpr) and isinstance(self.end, NatLitExpr): + width = self.end.value - self.start.value + 1 + prob = FloatLitExpr(Fraction(1, width)) + return [(prob, NatLitExpr(i)) + for i in range(self.start.value, self.end.value + 1)] + else: + NotImplementedError("Parameters not implemented yet.") def __str__(self) -> str: return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' @@ -505,6 +542,104 @@ def _check_categorical_exprs(_self: "CategoricalExpr", _attribute: Any, raise ValueError("Probabilities need to sum up to 1!") +@attr.s +class CUniformExpr(ExprClass): + """ + Chooses a random real number within the (inclusive) interval. + + As *monadic expressions* (see :ref:`expressions`), uniform choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + start: 'Expr' = attr.ib() + end: 'Expr' = attr.ib() + + def __str__(self) -> str: + return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' + + +@attr.s +class BernoulliExpr(ExprClass): + """ + Chooses a random bernoulli distributed integer. + + As *monadic expressions* (see :ref:`expressions`), geometric choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + param: 'Expr' = attr.ib() + + def __str__(self) -> str: + return f'bernoulli({expr_str_parens(self.param)})' + + +@attr.s +class GeometricExpr(ExprClass): + """ + Chooses a random geometrically distributed integer. + + As *monadic expressions* (see :ref:`expressions`), geometric choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + param: 'Expr' = attr.ib() + + def __str__(self) -> str: + return f'geometric({expr_str_parens(self.param)})' + + +@attr.s +class PoissonExpr(ExprClass): + """ + Chooses a random poisson distributed integer. + + As *monadic expressions* (see :ref:`expressions`), geometric choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + param: 'Expr' = attr.ib() + + def __str__(self) -> str: + return f'poisson({expr_str_parens(self.param)})' + + +@attr.s +class LogDistExpr(ExprClass): + """ + Chooses a random logarithmically distributed integer. + """ + param: 'Expr' = attr.ib() + + def __str__(self) -> str: + return f'logdist({expr_str_parens(self.param)})' + + +@attr.s +class BinomialExpr(ExprClass): + """ + Chooses a random logarithmically distributed integer. + + As *monadic expressions* (see :ref:`expressions`), geometric choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + n: 'Expr' = attr.ib() + p: 'Expr' = attr.ib() + + def __str__(self) -> str: + return f'binomial({expr_str_parens(self.n)}, {expr_str_parens(self.p)})' + + +@attr.s +class IidSampleExpr(ExprClass): + """ Independently sampling from identical distributions""" + sampling_dist: 'Expr' = attr.ib() + variable: VarExpr = attr.ib() + + def __str__(self) -> str: + return f"iid({self.sampling_dist}, {self.variable})" + + @attr.s class CategoricalExpr(ExprClass): """ @@ -583,8 +718,13 @@ def expr_str_parens(expr: ExprClass) -> str: return f'({expr})' +DistrExpr = Union[DUniformExpr, CUniformExpr, BernoulliExpr, GeometricExpr, PoissonExpr, LogDistExpr, BinomialExpr, + IidSampleExpr] +""" A type combining all sampling expressions""" + + Expr = Union[VarExpr, BoolLitExpr, NatLitExpr, FloatLitExpr, UnopExpr, - BinopExpr, UniformExpr, CategoricalExpr, SubstExpr, TickExpr] + BinopExpr, CategoricalExpr, SubstExpr, TickExpr, DistrExpr] """Union type for all expression objects. See :class:`ExprClass` for use with isinstance.""" @@ -674,6 +814,16 @@ def __str__(self) -> str: return f"{_str_block(self.lhs)} [{self.prob}] {_str_block(self.rhs)}" +@attr.s +class LoopInstr(InstrClass): + """ iterating a block a constant amount of times""" + iterations: NatLitExpr = attr.ib() + body: List["Instr"] = attr.ib() + + def __str__(self) -> str: + return f"loop({self.iterations}){_str_block(self.body)}" + + @attr.s class TickInstr(InstrClass): """ @@ -689,16 +839,111 @@ def __str__(self) -> str: return f"tick({self.expr});" -Instr = Union[SkipInstr, WhileInstr, IfInstr, AsgnInstr, ChoiceInstr, - TickInstr] +@attr.s +class ObserveInstr(InstrClass): + """ + Updates the current distribution according to the observation (forward analysis only). + May result in an error if the observed condition has probability zero. + + The type of ``expr`` must be :class:`BoolType`. + """ + cond: Expr = attr.ib() + + def __str__(self) -> str: + return f"observe({self.cond});" + + +@attr.s +class ExpectationInstr(InstrClass): + """ + Allows for expectation queries inside of a pgcl program. + """ + expr: Expr = attr.ib() + + def __str__(self) -> str: + return f"?Ex[{self.expr}];" + + +class OptimizationType(Enum): + MAXIMIZE = auto() + MINIMIZE = auto() + + +@attr.s +class OptimizationQuery(InstrClass): + expr: Expr = attr.ib() + parameter: Var = attr.ib() + type: OptimizationType = attr.ib() + + def __str__(self) -> str: + return f"?Opt[{self.expr}, {self.parameter}, {'MAX' if self.type == OptimizationType.MAXIMIZE else 'MIN'}];" + + +@attr.s +class ProbabilityQueryInstr(InstrClass): + expr: Expr = attr.ib() + + def __str__(self) -> str: + return f"?Pr[{self.expr}];" + + +@attr.s +class PrintInstr(InstrClass): + def __str__(self) -> str: + return f"!Print;" + + +@attr.s +class PlotInstr(InstrClass): + var_1: VarExpr = attr.ib() + var_2: VarExpr = attr.ib(default=None) + prob: FloatLitExpr = attr.ib(default=None) + term_count: NatLitExpr = attr.ib(default=None) + + def __str__(self) -> str: + output = str(self.var_1) + if self.var_2: + output += f", {str(self.var_2)}" + if self.prob: + output += f", {str(self.prob)}" + if self.term_count: + output += f", {str(self.term_count)}" + return f"!Plot[{output}]" + + +Query = Union[ProbabilityQueryInstr, ExpectationInstr, PlotInstr, PrintInstr, OptimizationQuery] +"""Union type for all query objects. See :class:`QueryInstr` for use with isinstance.""" + + +Instr = Union[SkipInstr, WhileInstr, IfInstr, AsgnInstr, ChoiceInstr, LoopInstr, + TickInstr, ObserveInstr, Query] """Union type for all instruction objects. See :class:`InstrClass` for use with isinstance.""" +@attr.s(frozen=True) +class ProgramConfig: + """ + Some compilation options for programs. Frozen after initialization (cannot + be modified). + + At the moment, we only have a flag for the type checker on which types are + allowed as program variables. + """ + + allow_real_vars: bool = attr.ib(default=True) + """ + Whether real numbers are allowed as program values (in computations, or as + variables). + """ + + @attr.s class Program: """ A pGCL program has a bunch of variables with types, constants with defining expressions, and a list of instructions. """ + config: ProgramConfig = attr.ib(repr=False) + declarations: List[Decl] = attr.ib(repr=False) """The original list of declarations.""" @@ -714,10 +959,16 @@ class Program: Only valid if the declarations are well-typed. """ + parameters: Dict[Var, Type] = attr.ib() + """ + A dict of parameters to their type. + Only valid if the declarations are well-typed. + """ + instructions: List[Instr] = attr.ib() @staticmethod - def from_parse(declarations: List[Decl], + def from_parse(config: ProgramConfig, declarations: List[Decl], parameters: Dict[Var, Type], instructions: List[Instr]) -> "Program": """Create a program from the parser's output.""" variables: Dict[Var, Type] = dict() @@ -729,7 +980,7 @@ def from_parse(declarations: List[Decl], elif isinstance(decl, ConstDecl): constants[decl.var] = decl.value - return Program(declarations, variables, constants, instructions) + return Program(config, declarations, variables, constants, parameters, instructions) def add_variable(self, var: Var, typ: Type): """ @@ -756,7 +1007,9 @@ def to_skeleton(self) -> 'Program': >>> program.to_skeleton() Program(variables={'x': NatType(bounds=None), 'y': NatType(bounds=None)}, constants={}, instructions=[]) """ - return Program(declarations=copy.copy(self.declarations), + return Program(config=self.config, + declarations=copy.copy(self.declarations), + parameters=copy.copy(self.parameters), variables=copy.copy(self.variables), constants=copy.copy(self.constants), instructions=[]) From 7fbc8bd67a6b3df2768accb6709a88f8c73b3e16 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 6 May 2022 12:35:56 +0200 Subject: [PATCH 04/67] Minimal changes to make the tests pass This does not adapt the tests to the new features, it just makes sure there are no errors due to the renaming of classes or changed parameters in functions --- probably/pgcl/__init__.py | 2 +- probably/pgcl/ast.py | 2 +- probably/pgcl/check.py | 10 +++++----- probably/pgcl/compiler.py | 2 +- probably/pgcl/parser.py | 18 +++++++++++------- probably/pgcl/wp.py | 4 ++-- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/probably/pgcl/__init__.py b/probably/pgcl/__init__.py index 4b98296..db76790 100644 --- a/probably/pgcl/__init__.py +++ b/probably/pgcl/__init__.py @@ -31,7 +31,7 @@ ... {c := unif(1,10)} [0.8] {f:=true} ... }''' >>> compile_pgcl(code) - Program(variables={'f': BoolType(), 'c': NatType(bounds=None)}, constants={}, instructions=[SkipInstr(), WhileInstr(cond=BinopExpr(operator=Binop.AND, lhs=BinopExpr(operator=Binop.LE, lhs=VarExpr('c'), rhs=NatLitExpr(10)), rhs=VarExpr('f')), body=[ChoiceInstr(prob=FloatLitExpr("0.8"), lhs=[AsgnInstr(lhs='c', rhs=UniformExpr(start=NatLitExpr(1), end=NatLitExpr(10)))], rhs=[AsgnInstr(lhs='f', rhs=BoolLitExpr(True))])])]) + Program(variables={'f': BoolType(), 'c': NatType(bounds=None)}, constants={}, parameters={}, instructions=[SkipInstr(), WhileInstr(cond=BinopExpr(operator=Binop.AND, lhs=BinopExpr(operator=Binop.LE, lhs=VarExpr('c'), rhs=NatLitExpr(10)), rhs=VarExpr('f')), body=[ChoiceInstr(prob=FloatLitExpr("0.8"), lhs=[AsgnInstr(lhs='c', rhs=DUniformExpr(start=NatLitExpr(1), end=NatLitExpr(10)))], rhs=[AsgnInstr(lhs='f', rhs=BoolLitExpr(True))])])]) For more details on what syntax is accepted for pGCL programs, you can view the :ref:`formal grammar used for the pGCL parser `. diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index 5dda191..a339073 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -1005,7 +1005,7 @@ def to_skeleton(self) -> 'Program': >>> from .parser import parse_pgcl >>> program = parse_pgcl("nat x; nat y; while (x < 2) {}") >>> program.to_skeleton() - Program(variables={'x': NatType(bounds=None), 'y': NatType(bounds=None)}, constants={}, instructions=[]) + Program(variables={'x': NatType(bounds=None), 'y': NatType(bounds=None)}, constants={}, parameters={}, instructions=[]) """ return Program(config=self.config, declarations=copy.copy(self.declarations), diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index ffef9c4..afe1f6d 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -13,8 +13,8 @@ from .ast import (AsgnInstr, Binop, BinopExpr, BoolLitExpr, BoolType, CategoricalExpr, ChoiceInstr, Decl, Expr, FloatLitExpr, FloatType, IfInstr, Instr, NatLitExpr, NatType, Node, - Program, SkipInstr, Type, UniformExpr, Unop, UnopExpr, Var, - VarExpr, WhileInstr) + Program, SkipInstr, Type, DUniformExpr, Unop, UnopExpr, Var, + VarExpr, WhileInstr, ProgramConfig) from .walk import Walk, walk_expr _T = TypeVar('_T') @@ -73,7 +73,7 @@ def get_type(program: Program, >>> from .ast import * >>> nat = NatLitExpr(10) - >>> program = Program(list(), dict(), dict(), list()) + >>> program = Program(ProgramConfig(), list(), dict(), dict(), dict(), list()) >>> get_type(program, BinopExpr(Binop.TIMES, nat, nat)) NatType(bounds=None) @@ -169,7 +169,7 @@ def get_type(program: Program, return NatType(bounds=None) return lhs_typ - if isinstance(expr, UniformExpr): + if isinstance(expr, DUniformExpr): return NatType(bounds=None) if isinstance(expr, CategoricalExpr): @@ -374,7 +374,7 @@ def check_expression(program, expr: Expr) -> Optional[CheckFail]: .. doctest:: - >>> program = Program(list(), dict(), dict(), list()) + >>> program = Program(ProgramConfig(), list(), dict(), dict(), dict(), list()) >>> check_expression(program, FloatLitExpr("1.0")) CheckFail(location=..., message='A program expression may not return a probability.') """ diff --git a/probably/pgcl/compiler.py b/probably/pgcl/compiler.py index 0dc4fb7..82d3867 100644 --- a/probably/pgcl/compiler.py +++ b/probably/pgcl/compiler.py @@ -31,7 +31,7 @@ def compile_pgcl(code: str, .. doctest:: >>> compile_pgcl("nat x; nat y; x := y") - Program(variables={'x': NatType(bounds=None), 'y': NatType(bounds=None)}, constants={}, instructions=[AsgnInstr(lhs='x', rhs=VarExpr('y'))]) + Program(variables={'x': NatType(bounds=None), 'y': NatType(bounds=None)}, constants={}, parameters={}, instructions=[AsgnInstr(lhs='x', rhs=VarExpr('y'))]) >>> compile_pgcl("x := y") CheckFail(location=..., message='x is not a variable.') diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 31a0f50..c81ed60 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -105,6 +105,10 @@ def _doc_parser_grammar(): _doc_parser_grammar.__doc__ = "The Lark grammar for pGCL::\n" + _PGCL_GRAMMAR + "\n\nThis function only exists for documentation purposes and should never be called in code." +# Collect parameter information here. +parameters: Dict[Var, Type] = dict() + + @attr.s class _LikelyExpr(ExprClass): """ @@ -253,7 +257,7 @@ def _parse_rvalue(t: Tree) -> Expr: end = _parse_expr(_child_tree(t, 1)) if not isinstance(end, NatLitExpr): raise Exception(f"{end} is not a natural number") - return UniformExpr(start, end) + return DUniformExpr(start, end) # otherwise we have an expression, but it may contain _LikelyExprs, which we # need to parse. @@ -313,30 +317,30 @@ def _parse_instrs(t: Tree) -> List[Instr]: return [_parse_instr(_as_tree(t)) for t in t.children] -def _parse_program(t: Tree) -> Program: +def _parse_program(config: ProgramConfig, t: Tree) -> Program: assert t.data == 'start' declarations = _parse_declarations(_child_tree(t, 0)) instructions = _parse_instrs(_child_tree(t, 1)) - return Program.from_parse(declarations, instructions) + return Program.from_parse(config, declarations, parameters, instructions) -def parse_pgcl(code: str) -> Program: +def parse_pgcl(code: str, config: ProgramConfig = ProgramConfig()) -> Program: """ Parse a pGCL program. .. doctest:: >>> parse_pgcl("x := y") - Program(variables={}, constants={}, instructions=[AsgnInstr(lhs='x', rhs=VarExpr('y'))]) + Program(variables={}, constants={}, parameters={}, instructions=[AsgnInstr(lhs='x', rhs=VarExpr('y'))]) >>> parse_pgcl("x := unif(5, 17)").instructions[0] - AsgnInstr(lhs='x', rhs=UniformExpr(start=NatLitExpr(5), end=NatLitExpr(17))) + AsgnInstr(lhs='x', rhs=DUniformExpr(start=NatLitExpr(5), end=NatLitExpr(17))) >>> parse_pgcl("x := x : 1/3 + y : 2/3").instructions[0] AsgnInstr(lhs='x', rhs=CategoricalExpr(exprs=[(VarExpr('x'), FloatLitExpr("1/3")), (VarExpr('y'), FloatLitExpr("2/3"))])) """ tree = _PARSER.parse(code) - return _parse_program(tree) + return _parse_program(config, tree) def parse_expr(code: str) -> Expr: diff --git a/probably/pgcl/wp.py b/probably/pgcl/wp.py index 24e6aed..93ec862 100644 --- a/probably/pgcl/wp.py +++ b/probably/pgcl/wp.py @@ -89,7 +89,7 @@ from .ast import (AsgnInstr, Binop, BinopExpr, CategoricalExpr, ChoiceInstr, Expr, FloatLitExpr, IfInstr, Instr, Program, - SkipInstr, SubstExpr, TickExpr, TickInstr, UniformExpr, Unop, + SkipInstr, SubstExpr, TickExpr, TickInstr, DUniformExpr, Unop, UnopExpr, Var, VarExpr, WhileInstr) from .substitute import substitute_expr from .syntax import check_is_one_big_loop @@ -164,7 +164,7 @@ def loopfree_wp(instr: Union[Instr, Sequence[Instr]], return BinopExpr(Binop.PLUS, true, false) if isinstance(instr, AsgnInstr): - if isinstance(instr.rhs, (UniformExpr, CategoricalExpr)): + if isinstance(instr.rhs, (DUniformExpr, CategoricalExpr)): distribution = instr.rhs.distribution() branches = [ BinopExpr( From 4fc36c1073becb500a2eb7ac74af454ead469441 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 6 May 2022 12:53:24 +0200 Subject: [PATCH 05/67] Rename float types to real types --- probably/pgcl/__init__.py | 2 +- probably/pgcl/ast.py | 52 +++++++++++++++++++-------------------- probably/pgcl/check.py | 24 +++++++++--------- probably/pgcl/parser.py | 22 ++++++++--------- probably/pgcl/simplify.py | 36 +++++++++++++-------------- probably/pgcl/wp.py | 8 +++--- probably/pysmt/context.py | 4 +-- probably/pysmt/expr.py | 4 +-- 8 files changed, 76 insertions(+), 76 deletions(-) diff --git a/probably/pgcl/__init__.py b/probably/pgcl/__init__.py index db76790..937cfbc 100644 --- a/probably/pgcl/__init__.py +++ b/probably/pgcl/__init__.py @@ -31,7 +31,7 @@ ... {c := unif(1,10)} [0.8] {f:=true} ... }''' >>> compile_pgcl(code) - Program(variables={'f': BoolType(), 'c': NatType(bounds=None)}, constants={}, parameters={}, instructions=[SkipInstr(), WhileInstr(cond=BinopExpr(operator=Binop.AND, lhs=BinopExpr(operator=Binop.LE, lhs=VarExpr('c'), rhs=NatLitExpr(10)), rhs=VarExpr('f')), body=[ChoiceInstr(prob=FloatLitExpr("0.8"), lhs=[AsgnInstr(lhs='c', rhs=DUniformExpr(start=NatLitExpr(1), end=NatLitExpr(10)))], rhs=[AsgnInstr(lhs='f', rhs=BoolLitExpr(True))])])]) + Program(variables={'f': BoolType(), 'c': NatType(bounds=None)}, constants={}, parameters={}, instructions=[SkipInstr(), WhileInstr(cond=BinopExpr(operator=Binop.AND, lhs=BinopExpr(operator=Binop.LE, lhs=VarExpr('c'), rhs=NatLitExpr(10)), rhs=VarExpr('f')), body=[ChoiceInstr(prob=RealLitExpr("0.8"), lhs=[AsgnInstr(lhs='c', rhs=DUniformExpr(start=NatLitExpr(1), end=NatLitExpr(10)))], rhs=[AsgnInstr(lhs='f', rhs=BoolLitExpr(True))])])]) For more details on what syntax is accepted for pGCL programs, you can view the :ref:`formal grammar used for the pGCL parser `. diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index a339073..4d78bf4 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -27,7 +27,7 @@ .. autoclass:: BoolType .. autoclass:: NatType .. autoclass:: Bounds -.. autoclass:: FloatType +.. autoclass:: RealType Declarations ############ @@ -58,7 +58,7 @@ .. autoclass:: VarExpr .. autoclass:: BoolLitExpr .. autoclass:: NatLitExpr -.. autoclass:: FloatLitExpr +.. autoclass:: RealLitExpr .. autoclass:: Unop .. autoclass:: UnopExpr .. autoclass:: Binop @@ -164,11 +164,11 @@ class NatType(TypeClass): @attr.s -class FloatType(TypeClass): - """Floating numbers, used for probabilities.""" +class RealType(TypeClass): + """Real numbers, used for probabilities.""" -Type = Union[BoolType, NatType, FloatType] +Type = Union[BoolType, NatType, RealType] """Union type for all type objects. See :class:`TypeClass` for use with isinstance.""" @@ -200,8 +200,8 @@ def __str__(self) -> str: if self.typ.bounds is not None: res += " " + str(self.typ.bounds) return res + ";" - elif isinstance(self.typ, FloatType): - return f"float {self.var};" + elif isinstance(self.typ, RealType): + return f"real {self.var};" raise ValueError(f"invalid type: {self.typ}") @@ -228,7 +228,7 @@ def __str__(self) -> str: if self.typ.bounds is not None: res += " " + str(self.typ.bounds) return res + ";" - elif isinstance(self.typ, FloatType): + elif isinstance(self.typ, RealType): return f"rparam {self.var};" raise ValueError(f"invalid type: {self.typ}") @@ -301,14 +301,14 @@ def __repr__(self) -> str: return f'NatLitExpr({self.value})' -def _validate_float_lit_value(_object: 'FloatLitExpr', _attribute: Any, +def _validate_real_lit_value(_object: 'RealLitExpr', _attribute: Any, value: Any): if not isinstance(value, Decimal) and not isinstance(value, Fraction): raise ValueError( f"Expected a Decimal or Fraction value, got: {value!r}") -def _parse_float_lit_expr( +def _parse_real_lit_expr( value: Union[str, Decimal, Fraction]) -> Union[Decimal, Fraction]: if isinstance(value, str): if "/" in value: @@ -321,7 +321,7 @@ def _parse_float_lit_expr( @attr.s(repr=False, frozen=True) -class FloatLitExpr(ExprClass): +class RealLitExpr(ExprClass): """ A decimal literal (used for probabilities) is an expression. @@ -337,20 +337,20 @@ class FloatLitExpr(ExprClass): For calculations, please use :meth:`to_fraction()`. """ value: Union[Decimal, - Fraction] = attr.ib(validator=_validate_float_lit_value, - converter=_parse_float_lit_expr) + Fraction] = attr.ib(validator=_validate_real_lit_value, + converter=_parse_real_lit_expr) @staticmethod - def infinity() -> 'FloatLitExpr': + def infinity() -> 'RealLitExpr': """ Create a new infinite value. .. doctest:: - >>> FloatLitExpr.infinity().is_infinite() + >>> RealLitExpr.infinity().is_infinite() True """ - return FloatLitExpr(Decimal('Infinity')) + return RealLitExpr(Decimal('Infinity')) def is_infinite(self): """ @@ -365,7 +365,7 @@ def to_fraction(self) -> Fraction: .. doctest:: - >>> expr = FloatLitExpr("0.1") + >>> expr = RealLitExpr("0.1") >>> expr.to_fraction() Fraction(1, 10) """ @@ -378,7 +378,7 @@ def __str__(self) -> str: return str(self.value) def __repr__(self) -> str: - return f'FloatLitExpr("{str(self.value)}")' + return f'RealLitExpr("{str(self.value)}")' class Unop(Enum): @@ -517,7 +517,7 @@ class DUniformExpr(ExprClass): start: 'Expr' = attr.ib() end: 'Expr' = attr.ib() - def distribution(self) -> List[Tuple[FloatLitExpr, NatLitExpr]]: + def distribution(self) -> List[Tuple[RealLitExpr, NatLitExpr]]: r""" Return the distribution of possible values as a list along with probabilities. For the uniform distribution, all probabilites are equal @@ -525,7 +525,7 @@ def distribution(self) -> List[Tuple[FloatLitExpr, NatLitExpr]]: """ if isinstance(self.start, NatLitExpr) and isinstance(self.end, NatLitExpr): width = self.end.value - self.start.value + 1 - prob = FloatLitExpr(Fraction(1, width)) + prob = RealLitExpr(Fraction(1, width)) return [(prob, NatLitExpr(i)) for i in range(self.start.value, self.end.value + 1)] else: @@ -536,7 +536,7 @@ def __str__(self) -> str: def _check_categorical_exprs(_self: "CategoricalExpr", _attribute: Any, - value: List[Tuple["Expr", FloatLitExpr]]): + value: List[Tuple["Expr", RealLitExpr]]): probabilities = (prob.to_fraction() for _, prob in value) if sum(probabilities) != 1: raise ValueError("Probabilities need to sum up to 1!") @@ -652,10 +652,10 @@ class CategoricalExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - exprs: List[Tuple["Expr", FloatLitExpr]] = attr.ib( + exprs: List[Tuple["Expr", RealLitExpr]] = attr.ib( validator=_check_categorical_exprs) - def distribution(self) -> List[Tuple[FloatLitExpr, "Expr"]]: + def distribution(self) -> List[Tuple[RealLitExpr, "Expr"]]: r""" Return the distribution of possible values as a list along with probabilities. @@ -712,7 +712,7 @@ def __str__(self) -> str: def expr_str_parens(expr: ExprClass) -> str: """Wrap parentheses around an expression, but not for simple expressions.""" if isinstance(expr, - (VarExpr, BoolLitExpr, NatLitExpr, FloatLitExpr, UnopExpr)): + (VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, UnopExpr)): return str(expr) else: return f'({expr})' @@ -723,7 +723,7 @@ def expr_str_parens(expr: ExprClass) -> str: """ A type combining all sampling expressions""" -Expr = Union[VarExpr, BoolLitExpr, NatLitExpr, FloatLitExpr, UnopExpr, +Expr = Union[VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, UnopExpr, BinopExpr, CategoricalExpr, SubstExpr, TickExpr, DistrExpr] """Union type for all expression objects. See :class:`ExprClass` for use with isinstance.""" @@ -897,7 +897,7 @@ def __str__(self) -> str: class PlotInstr(InstrClass): var_1: VarExpr = attr.ib() var_2: VarExpr = attr.ib(default=None) - prob: FloatLitExpr = attr.ib(default=None) + prob: RealLitExpr = attr.ib(default=None) term_count: NatLitExpr = attr.ib(default=None) def __str__(self) -> str: diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index afe1f6d..e9cee53 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -11,8 +11,8 @@ from probably.util.ref import Mut from .ast import (AsgnInstr, Binop, BinopExpr, BoolLitExpr, BoolType, - CategoricalExpr, ChoiceInstr, Decl, Expr, FloatLitExpr, - FloatType, IfInstr, Instr, NatLitExpr, NatType, Node, + CategoricalExpr, ChoiceInstr, Decl, Expr, RealLitExpr, + RealType, IfInstr, Instr, NatLitExpr, NatType, Node, Program, SkipInstr, Type, DUniformExpr, Unop, UnopExpr, Var, VarExpr, WhileInstr, ProgramConfig) from .walk import Walk, walk_expr @@ -82,7 +82,7 @@ def get_type(program: Program, CheckFail(location=VarExpr('x'), message='variable is not declared') >>> get_type(program, UnopExpr(Unop.IVERSON, BoolLitExpr(True))) - FloatType() + RealType() """ if isinstance(expr, VarExpr): @@ -103,8 +103,8 @@ def get_type(program: Program, if isinstance(expr, NatLitExpr): return NatType(bounds=None) - if isinstance(expr, FloatLitExpr): - return FloatType() + if isinstance(expr, RealLitExpr): + return RealType() if isinstance(expr, UnopExpr): if check: @@ -123,7 +123,7 @@ def get_type(program: Program, return BoolType() if expr.operator == Unop.IVERSON: - return FloatType() + return RealType() if isinstance(expr, BinopExpr): # binops that take boolean operands and return a boolean @@ -142,7 +142,7 @@ def get_type(program: Program, lhs_typ = get_type(program, expr.lhs, check=check) if isinstance(lhs_typ, CheckFail): return lhs_typ - if not isinstance(lhs_typ, (NatType, FloatType)): + if not isinstance(lhs_typ, (NatType, RealType)): return CheckFail.expected_numeric_got(expr.lhs, lhs_typ) if check and expr.operator in [ @@ -152,7 +152,7 @@ def get_type(program: Program, rhs_typ = get_type(program, expr.rhs, check=check) if isinstance(rhs_typ, CheckFail): return rhs_typ - if not isinstance(rhs_typ, (NatType, FloatType)): + if not isinstance(rhs_typ, (NatType, RealType)): return CheckFail.expected_numeric_got(expr.rhs, rhs_typ) if not is_compatible(lhs_typ, rhs_typ): @@ -349,8 +349,8 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: prob_type = get_type(program, instr.prob, check=True) if isinstance(prob_type, CheckFail): return prob_type - if not is_compatible(FloatType(), prob_type): - return CheckFail.expected_type_got(instr.prob, FloatType(), + if not is_compatible(RealType(), prob_type): + return CheckFail.expected_type_got(instr.prob, RealType(), prob_type) return _check_instrs(program, instr.lhs, instr.rhs) @@ -375,13 +375,13 @@ def check_expression(program, expr: Expr) -> Optional[CheckFail]: .. doctest:: >>> program = Program(ProgramConfig(), list(), dict(), dict(), dict(), list()) - >>> check_expression(program, FloatLitExpr("1.0")) + >>> check_expression(program, RealLitExpr("1.0")) CheckFail(location=..., message='A program expression may not return a probability.') """ expr_type = get_type(program, expr, check=True) if isinstance(expr_type, CheckFail): return expr_type - if isinstance(expr_type, FloatType): + if isinstance(expr_type, RealType): return CheckFail(expr, "A program expression may not return a probability.") return None diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index c81ed60..a2c2fe7 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -121,7 +121,7 @@ class _LikelyExpr(ExprClass): of errors emitted by the parser before translation to CategoricalExprs. """ value: Expr = attr.ib() - prob: FloatLitExpr = attr.ib() + prob: RealLitExpr = attr.ib() def __str__(self) -> str: return f'{expr_str_parens(self.value)} : {expr_str_parens(self.prob)}' @@ -211,7 +211,7 @@ def expr1() -> Expr: return _parse_fraction(expr0(), expr1()) elif t.data == 'likely': prob_expr = expr1() - if not isinstance(prob_expr, FloatLitExpr): + if not isinstance(prob_expr, RealLitExpr): raise Exception( f"Probability annotation must be a probability literal: {t}") # We return a _LikelyExpr here, which is not in the Expr union type, but @@ -228,9 +228,9 @@ def expr1() -> Expr: raise Exception(f'invalid AST: {t.data}') -def _parse_fraction(num: Expr, denom: Expr) -> Union[FloatLitExpr, BinopExpr]: +def _parse_fraction(num: Expr, denom: Expr) -> Union[RealLitExpr, BinopExpr]: if isinstance(num, NatLitExpr) and isinstance(denom, NatLitExpr): - return FloatLitExpr(Fraction(num.value, denom.value)) + return RealLitExpr(Fraction(num.value, denom.value)) return BinopExpr(Binop.DIVIDE, num, denom) @@ -242,9 +242,9 @@ def _parse_literal(t: Tree) -> Expr: elif t.data == 'nat': return NatLitExpr(int(_child_str(t, 0))) elif t.data == 'float': - return FloatLitExpr(Decimal(_child_str(t, 0))) + return RealLitExpr(Decimal(_child_str(t, 0))) elif t.data == 'infinity': - return FloatLitExpr.infinity() + return RealLitExpr.infinity() else: raise Exception(f'invalid AST: {t.data}') @@ -273,7 +273,7 @@ def _parse_rvalue(t: Tree) -> Expr: raise Exception( f"Failed to parse categorical expression: each term in {t} must have an associated probability" ) - categories: List[Tuple[Expr, FloatLitExpr]] = [ + categories: List[Tuple[Expr, RealLitExpr]] = [ (operand.value, operand.prob) for operand in likely_operands ] return CategoricalExpr(categories) @@ -337,7 +337,7 @@ def parse_pgcl(code: str, config: ProgramConfig = ProgramConfig()) -> Program: AsgnInstr(lhs='x', rhs=DUniformExpr(start=NatLitExpr(5), end=NatLitExpr(17))) >>> parse_pgcl("x := x : 1/3 + y : 2/3").instructions[0] - AsgnInstr(lhs='x', rhs=CategoricalExpr(exprs=[(VarExpr('x'), FloatLitExpr("1/3")), (VarExpr('y'), FloatLitExpr("2/3"))])) + AsgnInstr(lhs='x', rhs=CategoricalExpr(exprs=[(VarExpr('x'), RealLitExpr("1/3")), (VarExpr('y'), RealLitExpr("2/3"))])) """ tree = _PARSER.parse(code) return _parse_program(config, tree) @@ -382,13 +382,13 @@ def parse_expectation(code: str) -> Expr: UnopExpr(operator=Unop.IVERSON, expr=VarExpr('x')) >>> parse_expectation("0.2") - FloatLitExpr("0.2") + RealLitExpr("0.2") >>> parse_expectation("1/3") - FloatLitExpr("1/3") + RealLitExpr("1/3") >>> parse_expectation("∞") - FloatLitExpr("Infinity") + RealLitExpr("Infinity") """ tree = _PARSER.parse(code, start="expression") return _parse_expr(tree) diff --git a/probably/pgcl/simplify.py b/probably/pgcl/simplify.py index 16dded6..91adce2 100644 --- a/probably/pgcl/simplify.py +++ b/probably/pgcl/simplify.py @@ -15,7 +15,7 @@ from probably.util.ref import Mut from .ast import VarExpr # pylint:disable=unused-import -from .ast import (Binop, BinopExpr, BoolLitExpr, Expr, FloatLitExpr, FloatType, +from .ast import (Binop, BinopExpr, BoolLitExpr, Expr, RealLitExpr, RealType, NatLitExpr, NatType, Program, SubstExpr, TickExpr, Unop, UnopExpr, Var, expr_str_parens) from .check import CheckFail, get_type @@ -63,14 +63,14 @@ def simplifying_plus(lhs: Expr, rhs: Expr) -> Expr: def simplifying_times(lhs: Expr, rhs: Expr) -> Expr: """ - Combine with ``Binop.TIMES``, but simplify when one operand is ``FloatLitExpr("1.0")``. + Combine with ``Binop.TIMES``, but simplify when one operand is ``RealLitExpr("1.0")``. .. doctest:: - >>> simplifying_times(FloatLitExpr("1.0"), VarExpr('x')) + >>> simplifying_times(RealLitExpr("1.0"), VarExpr('x')) VarExpr('x') """ - one = FloatLitExpr("1.0") + one = RealLitExpr("1.0") if lhs == one: return rhs if rhs == one: @@ -84,10 +84,10 @@ def simplifying_subst(subst: Dict[Var, Expr], expr: Expr) -> Expr: .. doctest:: - >>> simplifying_subst(dict(), FloatLitExpr("1.0")) - FloatLitExpr("1.0") + >>> simplifying_subst(dict(), RealLitExpr("1.0")) + RealLitExpr("1.0") """ - if isinstance(expr, (BoolLitExpr, FloatLitExpr, NatLitExpr)): + if isinstance(expr, (BoolLitExpr, RealLitExpr, NatLitExpr)): return expr return SubstExpr(subst, expr) @@ -121,13 +121,13 @@ class SnfExpectationTransformerProduct: .. doctest:: >>> a = SnfExpectationTransformerProduct.from_iverson(BoolLitExpr(True)) - >>> b = SnfExpectationTransformerProduct(guard=BoolLitExpr(True), prob=FloatLitExpr("5.0"), subst=None, ticks=TickExpr(NatLitExpr(1))) - >>> c = SnfExpectationTransformerProduct(guard=BoolLitExpr(False), prob=FloatLitExpr("2.0"), subst=None, ticks=TickExpr(NatLitExpr(5))) + >>> b = SnfExpectationTransformerProduct(guard=BoolLitExpr(True), prob=RealLitExpr("5.0"), subst=None, ticks=TickExpr(NatLitExpr(1))) + >>> c = SnfExpectationTransformerProduct(guard=BoolLitExpr(False), prob=RealLitExpr("2.0"), subst=None, ticks=TickExpr(NatLitExpr(5))) >>> print(a * b) [true] * 5.0 * tick(1) >>> print(a * b * c) [false] * (5.0 * 2.0) * tick(6) - >>> print(SnfExpectationTransformerProduct(guard=BoolLitExpr(True), prob=FloatLitExpr("2.0"), subst={"x": VarExpr("y")}, ticks=TickExpr(NatLitExpr(0)))) + >>> print(SnfExpectationTransformerProduct(guard=BoolLitExpr(True), prob=RealLitExpr("2.0"), subst={"x": VarExpr("y")}, ticks=TickExpr(NatLitExpr(0)))) [true] * 2.0 * (𝑋)[x/y] """ @@ -138,7 +138,7 @@ class SnfExpectationTransformerProduct: """ The probability without any Iverson brackets or :class:`probably.pgcl.ast.TickExpr`. It has types - :class:`probably.pgcl.ast.FloatType` or :class:`probably.pgcl.ast.NatType`. + :class:`probably.pgcl.ast.RealType` or :class:`probably.pgcl.ast.NatType`. """ subst: Optional[Dict[Var, Expr]] = attr.ib() @@ -152,7 +152,7 @@ class SnfExpectationTransformerProduct: def from_iverson(guard: Expr) -> 'SnfExpectationTransformerProduct': """Create a new value ``guard * 1.0 * tick(1)``.""" return SnfExpectationTransformerProduct(guard=guard, - prob=FloatLitExpr("1.0"), + prob=RealLitExpr("1.0"), subst=None, ticks=TickExpr(NatLitExpr(0))) @@ -169,7 +169,7 @@ def from_subst( subst: Dict[Var, Expr]) -> 'SnfExpectationTransformerProduct': """Create a new value from the substitution.""" return SnfExpectationTransformerProduct(guard=BoolLitExpr(True), - prob=FloatLitExpr("1.0"), + prob=RealLitExpr("1.0"), subst=subst, ticks=TickExpr(NatLitExpr(0))) @@ -177,7 +177,7 @@ def from_subst( def from_ticks(ticks: TickExpr) -> 'SnfExpectationTransformerProduct': """Create a new value from ticks.""" return SnfExpectationTransformerProduct(guard=BoolLitExpr(True), - prob=FloatLitExpr("1.0"), + prob=RealLitExpr("1.0"), subst=None, ticks=ticks) @@ -247,7 +247,7 @@ class SnfExpectationTransformer: .. doctest:: >>> a = SnfExpectationTransformerProduct.from_iverson(BoolLitExpr(True)) - >>> b = SnfExpectationTransformerProduct.from_prob(FloatLitExpr("0.5")) + >>> b = SnfExpectationTransformerProduct.from_prob(RealLitExpr("0.5")) >>> c = SnfExpectationTransformerProduct.from_subst({"x": VarExpr("y")}) >>> print(SnfExpectationTransformer([a, b, c])) λ𝑋. [true] * 1.0 + [true] * 0.5 + [true] * 1.0 * (𝑋)[x/y] @@ -387,7 +387,7 @@ def recurse(expr: Expr) -> Union[SnfExpectationTransformer, CheckFail]: expr_type = get_type(program, expr, check=False) if isinstance(expr_type, CheckFail): return expr_type - if isinstance(expr_type, (FloatType, NatType)): + if isinstance(expr_type, (RealType, NatType)): return SnfExpectationTransformer.from_prob(expr) raise Exception("unreachable") @@ -416,12 +416,12 @@ def normalize_expectation( >>> print(normalize_expectation(program, expectation)) λ𝑋. [false] * 1.0 + [true] * 1.0 - >>> prob = FloatLitExpr("10") + >>> prob = RealLitExpr("10") >>> print(normalize_expectation(program, BinopExpr(Binop.TIMES, prob, prob))) λ𝑋. [true] * (10 * 10) >>> normalize_expectation(program, BinopExpr(Binop.TIMES, UnopExpr(Unop.IVERSON, VarExpr('x')), prob)) - [SnfExpectationTransformerProduct(guard=VarExpr('x'), prob=FloatLitExpr("10"), subst=None, ticks=TickExpr(expr=NatLitExpr(0)))] + [SnfExpectationTransformerProduct(guard=VarExpr('x'), prob=RealLitExpr("10"), subst=None, ticks=TickExpr(expr=NatLitExpr(0)))] >>> expectation = parse_expectation("[c < 3] * c") >>> print(normalize_expectation(program, expectation)) diff --git a/probably/pgcl/wp.py b/probably/pgcl/wp.py index 93ec862..983e082 100644 --- a/probably/pgcl/wp.py +++ b/probably/pgcl/wp.py @@ -88,7 +88,7 @@ from probably.util.ref import Mut from .ast import (AsgnInstr, Binop, BinopExpr, CategoricalExpr, ChoiceInstr, - Expr, FloatLitExpr, IfInstr, Instr, Program, + Expr, RealLitExpr, IfInstr, Instr, Program, SkipInstr, SubstExpr, TickExpr, TickInstr, DUniformExpr, Unop, UnopExpr, Var, VarExpr, WhileInstr) from .substitute import substitute_expr @@ -116,10 +116,10 @@ def loopfree_wp(instr: Union[Instr, Sequence[Instr]], .. doctest:: >>> from .parser import parse_pgcl - >>> from .ast import FloatLitExpr, VarExpr + >>> from .ast import RealLitExpr, VarExpr >>> program = parse_pgcl("bool a; bool x; if (a) { x := 1 } {}") - >>> res = loopfree_wp(program.instructions, FloatLitExpr("1.0")) + >>> res = loopfree_wp(program.instructions, RealLitExpr("1.0")) >>> str(res) '([a] * ((1.0)[x/1])) + ([not a] * 1.0)' @@ -184,7 +184,7 @@ def loopfree_wp(instr: Union[Instr, Sequence[Instr]], lhs = BinopExpr(Binop.TIMES, lhs_block, instr.prob) rhs = BinopExpr( Binop.TIMES, rhs_block, - BinopExpr(Binop.MINUS, FloatLitExpr("1.0"), instr.prob)) + BinopExpr(Binop.MINUS, RealLitExpr("1.0"), instr.prob)) return BinopExpr(Binop.PLUS, lhs, rhs) if isinstance(instr, TickInstr): diff --git a/probably/pysmt/context.py b/probably/pysmt/context.py index 9816817..97c3c79 100644 --- a/probably/pysmt/context.py +++ b/probably/pysmt/context.py @@ -15,7 +15,7 @@ from pysmt.shortcuts import Symbol from pysmt.typing import BOOL, INT, REAL -from probably.pgcl.ast import BoolType, FloatType, NatType, Program, Type, Var +from probably.pgcl.ast import BoolType, RealType, NatType, Program, Type, Var def _translate_type(typ: Type): @@ -24,7 +24,7 @@ def _translate_type(typ: Type): elif isinstance(typ, NatType): # pylint: disable=fixme return INT # TODO: return bounds? - elif isinstance(typ, FloatType): + elif isinstance(typ, RealType): return REAL raise Exception("unreachable") diff --git a/probably/pysmt/expr.py b/probably/pysmt/expr.py index 4c5ad7f..ae27f51 100644 --- a/probably/pysmt/expr.py +++ b/probably/pysmt/expr.py @@ -16,7 +16,7 @@ from pysmt.typing import INT from probably.pgcl.ast import (Binop, BinopExpr, BoolLitExpr, Expr, - FloatLitExpr, NatLitExpr, SubstExpr, Unop, + RealLitExpr, NatLitExpr, SubstExpr, Unop, UnopExpr, VarExpr) from probably.pysmt.context import TranslationContext @@ -59,7 +59,7 @@ def expr_to_pysmt(context: TranslationContext, return ToReal(Int(expr.value)) else: return Int(expr.value) - elif isinstance(expr, FloatLitExpr): + elif isinstance(expr, RealLitExpr): if expr.is_infinite(): if not allow_infinity: raise Exception( From c296998996b65800526dcbf1814673d656cd168e Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 6 May 2022 13:06:03 +0200 Subject: [PATCH 06/67] Update docs to include new classes --- probably/pgcl/ast.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index 4d78bf4..2468628 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -34,6 +34,7 @@ .. autodata:: Decl .. autoclass:: VarDecl .. autoclass:: ConstDecl +.. autoclass:: ParameterDecl .. _expressions: @@ -55,6 +56,7 @@ mapping of states to *expected values*: :math:`\Sigma \to \mathbb{R}`. .. autodata:: Expr +.. autoclass:: DistrExpr .. autoclass:: VarExpr .. autoclass:: BoolLitExpr .. autoclass:: NatLitExpr @@ -63,7 +65,14 @@ .. autoclass:: UnopExpr .. autoclass:: Binop .. autoclass:: BinopExpr -.. autoclass:: UniformExpr +.. autoclass:: DUniformExpr +.. autoclass:: CUniformExpr +.. autoclass:: BernoulliExpr +.. autoclass:: GeometricExpr +.. autoclass:: PoissonExpr +.. autoclass:: LogDistExpr +.. autoclass:: BinomialExpr +.. autoclass:: IidSampleExpr .. autoclass:: CategoricalExpr .. autoclass:: SubstExpr .. autoclass:: TickExpr @@ -71,12 +80,21 @@ Instructions ############ .. autodata:: Instr +.. autoclass:: Query .. autoclass:: SkipInstr .. autoclass:: WhileInstr .. autoclass:: IfInstr .. autoclass:: AsgnInstr .. autoclass:: ChoiceInstr +.. autoclass:: LoopInstr .. autoclass:: TickInstr +.. autoclass:: ObserveInstr +.. autoclass:: ExpectationInstr +.. autoclass:: OptimizationType +.. autoclass:: OptimizationQuery +.. autoclass:: ProbabilityQueryInstr +.. autoclass:: PrintInstr +.. autoclass:: PlotInstr Superclasses ############ From 9d167e344a4cd7909232681ddf734672e9fdc26d Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 6 May 2022 13:09:11 +0200 Subject: [PATCH 07/67] Use autodata instead of autoclass for union types --- probably/pgcl/ast.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index 2468628..7d3ca63 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -56,7 +56,7 @@ mapping of states to *expected values*: :math:`\Sigma \to \mathbb{R}`. .. autodata:: Expr -.. autoclass:: DistrExpr +.. autodata:: DistrExpr .. autoclass:: VarExpr .. autoclass:: BoolLitExpr .. autoclass:: NatLitExpr @@ -80,7 +80,7 @@ Instructions ############ .. autodata:: Instr -.. autoclass:: Query +.. autodata:: Query .. autoclass:: SkipInstr .. autoclass:: WhileInstr .. autoclass:: IfInstr From 7adbe0f5b9f1c6bbc2bd26eae5e63d66111dbcf2 Mon Sep 17 00:00:00 2001 From: LKlinke <33656559+LKlinke@users.noreply.github.com> Date: Tue, 10 May 2022 17:30:53 +0200 Subject: [PATCH 08/67] changed workflow to python version 3.9 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3af4133..a499fd4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: 3.9 - name: Set up Poetry cache for Python dependencies uses: actions/cache@v2 if: startsWith(runner.os, 'Linux') From 7021d76d23839c3222c7c3bb67435db812bae9c4 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 11 May 2022 14:24:00 +0200 Subject: [PATCH 09/67] Enable type aliases for union types in the docs --- docs/source/conf.py | 3 +++ poetry.lock | 6 +++--- probably/pgcl/ast.py | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4fce9d4..75c0d6a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -62,3 +62,6 @@ # nitpicky emits warnings for all broken links # nitpicky = True + +autodoc_type_aliases = {"Expr" : "probably.pgcl.ast.Expr", "Instr" : "probably.pgcl.ast.Instr", "Type" : "probably.pgcl.ast.Type", + "Decl" : "probably.pgcl.ast.Decl", "DistrExpr" : "probably.pgcl.ast.DistrExpr", "Query" : "probably.pgcl.ast.Query"} \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index ffb8dec..92252c3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -281,7 +281,7 @@ python-versions = "*" [[package]] name = "more-itertools" -version = "8.12.0" +version = "8.13.0" description = "More routines for operating on iterables, beyond itertools" category = "dev" optional = false @@ -1027,8 +1027,8 @@ mccabe = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] more-itertools = [ - {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"}, - {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"}, + {file = "more-itertools-8.13.0.tar.gz", hash = "sha256:a42901a0a5b169d925f6f217cd5a190e32ef54360905b9c39ee7db5313bfec0f"}, + {file = "more_itertools-8.13.0-py3-none-any.whl", hash = "sha256:c5122bffc5f104d37c1626b8615b511f3427aa5389b94d61e5ef8236bfbc3ddb"}, ] mypy = [ {file = "mypy-0.770-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:a34b577cdf6313bf24755f7a0e3f3c326d5c1f4fe7422d1d06498eb25ad0c600"}, diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index 7d3ca63..995a556 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -116,6 +116,9 @@ .. autoclass:: Node """ +# Necessary for sphinx to use a union type's name in the docs (instead of always printing the full union type) +from __future__ import annotations + import copy import itertools from abc import ABC, abstractmethod From 697e1d18be92dd9f5309cd3ac87075869fa13d0d Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 11 May 2022 14:47:08 +0200 Subject: [PATCH 10/67] Remove forward type references in ast.py --- probably/pgcl/ast.py | 82 ++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index 995a556..2213931 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -146,8 +146,8 @@ class Bounds: The bounds can contain constant expressions, therefore bounds have type :class:`Expr`. """ - lower: "Expr" = attr.ib() - upper: "Expr" = attr.ib() + lower: Expr = attr.ib() + upper: Expr = attr.ib() def __str__(self) -> str: return f"[{self.lower}, {self.upper}]" @@ -230,7 +230,7 @@ def __str__(self) -> str: class ConstDecl(DeclClass): """A constant declaration with a name and an expression.""" var: Var = attr.ib() - value: "Expr" = attr.ib() + value: Expr = attr.ib() def __str__(self) -> str: return f"const {self.var} := {self.value};" @@ -265,7 +265,7 @@ class ExprClass(Node): All expressions can be transformed into human-readable strings using the `str` operator. """ - def cast(self) -> "Expr": + def cast(self) -> Expr: """Cast to Expr. This is sometimes necessary to satisfy the type checker.""" return self # type: ignore @@ -322,7 +322,7 @@ def __repr__(self) -> str: return f'NatLitExpr({self.value})' -def _validate_real_lit_value(_object: 'RealLitExpr', _attribute: Any, +def _validate_real_lit_value(_object: RealLitExpr, _attribute: Any, value: Any): if not isinstance(value, Decimal) and not isinstance(value, Fraction): raise ValueError( @@ -362,7 +362,7 @@ class RealLitExpr(ExprClass): converter=_parse_real_lit_expr) @staticmethod - def infinity() -> 'RealLitExpr': + def infinity() -> RealLitExpr: """ Create a new infinite value. @@ -416,7 +416,7 @@ def __repr__(self) -> str: class UnopExpr(ExprClass): """A unary operator is an expression.""" operator: Unop = attr.ib() - expr: "Expr" = attr.ib() + expr: Expr = attr.ib() def __str__(self) -> str: if self.operator == Unop.NEG: @@ -472,13 +472,13 @@ def __str__(self) -> str: class BinopExpr(ExprClass): """A binary operator is an expression.""" operator: Binop = attr.ib() - lhs: "Expr" = attr.ib() - rhs: "Expr" = attr.ib() + lhs: Expr = attr.ib() + rhs: Expr = attr.ib() @staticmethod def reduce(operator: Binop, - iterable: Sequence["Expr"], - default: Optional["Expr"] = None) -> "Expr": + iterable: Sequence[Expr], + default: Optional[Expr] = None) -> Expr: """ Builds a :class:`BinopExpr` using :func:`functools.reduce`. @@ -495,7 +495,7 @@ def reduce(operator: Binop, assert default is not None return default - def flatten(self) -> List["Expr"]: + def flatten(self) -> List[Expr]: """ Return a list of all recursive operands of the same operator. This really only makes sense if the operator is associative (see @@ -512,7 +512,7 @@ def flatten(self) -> List["Expr"]: """ assert self.operator.is_associative() - def flatten_expr(expr: "Expr") -> List["Expr"]: + def flatten_expr(expr: Expr) -> List[Expr]: if isinstance(expr, BinopExpr) and expr.operator == self.operator: return flatten_expr(expr.lhs) + flatten_expr(expr.rhs) else: @@ -535,8 +535,8 @@ class DUniformExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - start: 'Expr' = attr.ib() - end: 'Expr' = attr.ib() + start: Expr = attr.ib() + end: Expr = attr.ib() def distribution(self) -> List[Tuple[RealLitExpr, NatLitExpr]]: r""" @@ -556,8 +556,8 @@ def __str__(self) -> str: return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' -def _check_categorical_exprs(_self: "CategoricalExpr", _attribute: Any, - value: List[Tuple["Expr", RealLitExpr]]): +def _check_categorical_exprs(_self: CategoricalExpr, _attribute: Any, + value: List[Tuple[Expr, RealLitExpr]]): probabilities = (prob.to_fraction() for _, prob in value) if sum(probabilities) != 1: raise ValueError("Probabilities need to sum up to 1!") @@ -572,8 +572,8 @@ class CUniformExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - start: 'Expr' = attr.ib() - end: 'Expr' = attr.ib() + start: Expr = attr.ib() + end: Expr = attr.ib() def __str__(self) -> str: return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' @@ -588,7 +588,7 @@ class BernoulliExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - param: 'Expr' = attr.ib() + param: Expr = attr.ib() def __str__(self) -> str: return f'bernoulli({expr_str_parens(self.param)})' @@ -603,7 +603,7 @@ class GeometricExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - param: 'Expr' = attr.ib() + param: Expr = attr.ib() def __str__(self) -> str: return f'geometric({expr_str_parens(self.param)})' @@ -618,7 +618,7 @@ class PoissonExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - param: 'Expr' = attr.ib() + param: Expr = attr.ib() def __str__(self) -> str: return f'poisson({expr_str_parens(self.param)})' @@ -629,7 +629,7 @@ class LogDistExpr(ExprClass): """ Chooses a random logarithmically distributed integer. """ - param: 'Expr' = attr.ib() + param: Expr = attr.ib() def __str__(self) -> str: return f'logdist({expr_str_parens(self.param)})' @@ -644,8 +644,8 @@ class BinomialExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - n: 'Expr' = attr.ib() - p: 'Expr' = attr.ib() + n: Expr = attr.ib() + p: Expr = attr.ib() def __str__(self) -> str: return f'binomial({expr_str_parens(self.n)}, {expr_str_parens(self.p)})' @@ -654,7 +654,7 @@ def __str__(self) -> str: @attr.s class IidSampleExpr(ExprClass): """ Independently sampling from identical distributions""" - sampling_dist: 'Expr' = attr.ib() + sampling_dist: Expr = attr.ib() variable: VarExpr = attr.ib() def __str__(self) -> str: @@ -673,10 +673,10 @@ class CategoricalExpr(ExprClass): expressions are only allowed as the right-hand side of an assignment statement and not somewhere in a nested expression. """ - exprs: List[Tuple["Expr", RealLitExpr]] = attr.ib( + exprs: List[Tuple[Expr, RealLitExpr]] = attr.ib( validator=_check_categorical_exprs) - def distribution(self) -> List[Tuple[RealLitExpr, "Expr"]]: + def distribution(self) -> List[Tuple[RealLitExpr, Expr]]: r""" Return the distribution of possible values as a list along with probabilities. @@ -705,8 +705,8 @@ class SubstExpr(ExprClass): Substitutions can be applied using the :mod:`probably.pgcl.substitute` module. """ - subst: Dict[Var, "Expr"] = attr.ib() - expr: "Expr" = attr.ib() + subst: Dict[Var, Expr] = attr.ib() + expr: Expr = attr.ib() def __str__(self) -> str: substs = ", ".join( @@ -720,7 +720,7 @@ class TickExpr(ExprClass): Generated only by the weakest pre-expectation semantics of :class:`TickInstr`. """ - expr: "Expr" = attr.ib() + expr: Expr = attr.ib() def is_zero(self) -> bool: """Whether this expression represents exactly zero ticks.""" @@ -751,7 +751,7 @@ def expr_str_parens(expr: ExprClass) -> str: class InstrClass(Node): """Superclass for all instructions. See :obj:`Instr`.""" - def cast(self) -> "Instr": + def cast(self) -> Instr: """Cast to Instr. This is sometimes necessary to satisfy the type checker.""" return self # type: ignore @@ -775,7 +775,7 @@ def __str__(self) -> str: """ -def _str_block(instrs: List["Instr"]) -> str: +def _str_block(instrs: List[Instr]) -> str: if len(instrs) == 0: return "{ }" lines = indent("\n".join(map(str, instrs)), " ") @@ -793,7 +793,7 @@ def __str__(self) -> str: class WhileInstr(InstrClass): """A while loop with a condition and a body.""" cond: Expr = attr.ib() - body: List["Instr"] = attr.ib() + body: List[Instr] = attr.ib() def __str__(self) -> str: return f"while ({self.cond}) {_str_block(self.body)}" @@ -803,8 +803,8 @@ def __str__(self) -> str: class IfInstr(InstrClass): """A conditional expression with two branches.""" cond: Expr = attr.ib() - true: List["Instr"] = attr.ib() - false: List["Instr"] = attr.ib() + true: List[Instr] = attr.ib() + false: List[Instr] = attr.ib() def __str__(self) -> str: if len(self.false) > 0: @@ -828,8 +828,8 @@ def __str__(self) -> str: class ChoiceInstr(InstrClass): """A probabilistic choice instruction with a probability expression and two branches.""" prob: Expr = attr.ib() - lhs: List["Instr"] = attr.ib() - rhs: List["Instr"] = attr.ib() + lhs: List[Instr] = attr.ib() + rhs: List[Instr] = attr.ib() def __str__(self) -> str: return f"{_str_block(self.lhs)} [{self.prob}] {_str_block(self.rhs)}" @@ -839,7 +839,7 @@ def __str__(self) -> str: class LoopInstr(InstrClass): """ iterating a block a constant amount of times""" iterations: NatLitExpr = attr.ib() - body: List["Instr"] = attr.ib() + body: List[Instr] = attr.ib() def __str__(self) -> str: return f"loop({self.iterations}){_str_block(self.body)}" @@ -990,7 +990,7 @@ class Program: @staticmethod def from_parse(config: ProgramConfig, declarations: List[Decl], parameters: Dict[Var, Type], - instructions: List[Instr]) -> "Program": + instructions: List[Instr]) -> Program: """Create a program from the parser's output.""" variables: Dict[Var, Type] = dict() constants: Dict[Var, Expr] = dict() @@ -1016,7 +1016,7 @@ def add_variable(self, var: Var, typ: Type): self.declarations.append(VarDecl(var, typ)) self.variables[var] = typ - def to_skeleton(self) -> 'Program': + def to_skeleton(self) -> Program: """ Return a (shallow) copy of this program with just the declarations, but without any instructions. From b2ede13b8b02c619a3c2a2adbae355779accc914 Mon Sep 17 00:00:00 2001 From: Lutz Klinkenberg Date: Wed, 11 May 2022 16:08:09 +0200 Subject: [PATCH 11/67] resolved dep issues --- poetry.lock | 577 ++++++++++++++++++++++++------------------------- pyproject.toml | 9 +- 2 files changed, 285 insertions(+), 301 deletions(-) diff --git a/poetry.lock b/poetry.lock index 92252c3..24d6939 100644 --- a/poetry.lock +++ b/poetry.lock @@ -16,17 +16,16 @@ python-versions = "*" [[package]] name = "astroid" -version = "2.9.0" +version = "2.11.5" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false -python-versions = "~=3.6" +python-versions = ">=3.6.2" [package.dependencies] lazy-object-proxy = ">=1.4.0" -typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} -wrapt = ">=1.11,<1.14" +wrapt = ">=1.11,<2" [[package]] name = "atomicwrites" @@ -98,26 +97,29 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.2" +version = "6.3.2" description = "Code coverage measurement for Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] toml = ["tomli"] [[package]] -name = "decorator" -version = "4.4.2" -description = "Decorators for Humans" -category = "main" +name = "dill" +version = "0.3.4" +description = "serialize all of python" +category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*" +python-versions = ">=2.7, !=3.0.*" + +[package.extras] +graph = ["objgraph (>=1.7.2)"] [[package]] name = "docutils" -version = "0.16" +version = "0.17.1" description = "Docutils -- Python Documentation Utilities" category = "main" optional = false @@ -136,15 +138,14 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.20" -description = "Python Git Library" +version = "3.1.27" +description = "GitPython is a python library used to interact with Git repositories" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] gitdb = ">=4.0.1,<5" -typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\""} [[package]] name = "graphviz" @@ -205,41 +206,41 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.8.3" +version = "4.11.3" description = "Read metadata from Python packages" -category = "dev" +category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] [[package]] name = "isort" -version = "5.8.0" +version = "5.10.1" description = "A Python utility / library to sort Python imports." category = "dev" optional = false -python-versions = ">=3.6,<4.0" +python-versions = ">=3.6.1,<4.0" [package.extras] pipfile_deprecated_finder = ["pipreqs", "requirementslib"] requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] +plugins = ["setuptools"] [[package]] name = "jinja2" -version = "3.0.3" +version = "3.1.2" description = "A very fast and expressive template engine." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] MarkupSafe = ">=2.0" @@ -265,19 +266,19 @@ python-versions = ">=3.6" [[package]] name = "markupsafe" -version = "2.0.1" +version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "mccabe" -version = "0.6.1" +version = "0.7.0" description = "McCabe checker, plugin for flake8" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "more-itertools" @@ -313,27 +314,18 @@ python-versions = "*" [[package]] name = "networkx" -version = "2.5.1" +version = "2.8" description = "Python package for creating and manipulating graphs and networks" category = "main" optional = false -python-versions = ">=3.6" - -[package.dependencies] -decorator = ">=4.3,<5" +python-versions = ">=3.8" [package.extras] -all = ["numpy", "scipy", "pandas", "matplotlib", "pygraphviz", "pydot", "pyyaml", "lxml", "pytest"] -gdal = ["gdal"] -lxml = ["lxml"] -matplotlib = ["matplotlib"] -numpy = ["numpy"] -pandas = ["pandas"] -pydot = ["pydot"] -pygraphviz = ["pygraphviz"] -pytest = ["pytest"] -pyyaml = ["pyyaml"] -scipy = ["scipy"] +default = ["numpy (>=1.19)", "scipy (>=1.8)", "matplotlib (>=3.4)", "pandas (>=1.3)"] +developer = ["pre-commit (>=2.18)", "mypy (>=0.942)"] +doc = ["sphinx (>=4.5)", "pydata-sphinx-theme (>=0.8.1)", "sphinx-gallery (>=0.10)", "numpydoc (>=1.2)", "pillow (>=9.1)", "nb2plots (>=0.6)", "texext (>=0.6.6)"] +extra = ["lxml (>=4.6)", "pygraphviz (>=1.9)", "pydot (>=1.4.2)", "sympy (>=1.10)"] +test = ["pytest (>=7.1)", "pytest-cov (>=3.0)", "codecov (>=2.1)"] [[package]] name = "packaging" @@ -348,15 +340,15 @@ pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "platformdirs" -version = "2.4.0" +version = "2.5.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] +test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] [[package]] name = "pluggy" @@ -366,9 +358,6 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - [package.extras] dev = ["pre-commit", "tox"] @@ -390,31 +379,35 @@ python-versions = ">=3.6" [[package]] name = "pylint" -version = "2.12.0" +version = "2.13.8" description = "python code static checker" category = "dev" optional = false -python-versions = "~=3.6" +python-versions = ">=3.6.2" [package.dependencies] -astroid = ">=2.9.0,<2.10" +astroid = ">=2.11.3,<=2.12.0-dev0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +dill = ">=0.2" isort = ">=4.2.5,<6" -mccabe = ">=0.6,<0.7" +mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" -toml = ">=0.9.2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} +[package.extras] +testutil = ["gitpython (>3)"] + [[package]] name = "pyparsing" -version = "3.0.7" -description = "Python parsing module" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.8" [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pysmt" @@ -439,7 +432,6 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" atomicwrites = ">=1.0" attrs = ">=17.4.0" colorama = {version = "*", markers = "sys_platform == \"win32\" and python_version != \"3.4\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} more-itertools = {version = ">=4.0.0", markers = "python_version > \"2.7\""} packaging = "*" pluggy = ">=0.12,<1.0" @@ -537,18 +529,19 @@ python-versions = "*" [[package]] name = "sphinx" -version = "3.5.4" +version = "4.5.0" description = "Python documentation generator" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] alabaster = ">=0.7,<0.8" babel = ">=1.3" colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.12,<0.17" +docutils = ">=0.14,<0.18" imagesize = "*" +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} Jinja2 = ">=2.3" packaging = "*" Pygments = ">=2.0" @@ -556,30 +549,30 @@ requests = ">=2.5.0" snowballstemmer = ">=1.1" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.800)", "docutils-stubs"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "docutils-stubs", "types-typed-ast", "types-requests"] test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] name = "sphinx-autodoc-typehints" -version = "1.12.0" +version = "1.18.1" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -Sphinx = ">=3.0" +Sphinx = ">=4.5" [package.extras] -test = ["pytest (>=3.1.0)", "typing-extensions (>=3.5)", "sphobjinv (>=2.0)", "Sphinx (>=3.2.0)", "dataclasses"] -type_comments = ["typed-ast (>=1.4.0)"] +testing = ["covdefaults (>=2.2)", "coverage (>=6.3)", "diff-cover (>=6.4)", "nptyping (>=2)", "pytest (>=7.1)", "pytest-cov (>=3)", "sphobjinv (>=2)", "typing-extensions (>=4.1)"] +type_comments = ["typed-ast (>=1.5.2)"] [[package]] name = "sphinx-bootstrap-theme" @@ -591,16 +584,16 @@ python-versions = "*" [[package]] name = "sphinx-click" -version = "2.7.1" +version = "3.1.0" description = "Sphinx extension that automatically documents click applications" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" [package.dependencies] -click = ">=6.0,<8.0" +click = ">=7.0" docutils = "*" -sphinx = ">=1.5,<4.0" +sphinx = ">=2.0" [[package]] name = "sphinx-git" @@ -664,14 +657,14 @@ test = ["pytest", "flake8", "mypy"] [[package]] name = "sphinxcontrib-katex" -version = "0.7.2" -description = "|tests| |docs| |license|" +version = "0.8.6" +description = "A Sphinx extension for rendering math in HTML pages" category = "main" optional = false python-versions = "*" [package.dependencies] -sphinx = ">=1.6,<4.0.0" +sphinx = ">=1.6" [[package]] name = "sphinxcontrib-qthelp" @@ -705,6 +698,14 @@ category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" + [[package]] name = "typed-ast" version = "1.4.3" @@ -715,11 +716,11 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "4.1.1" -description = "Backported and Experimental Type Hints for Python 3.6+" +version = "4.2.0" +description = "Backported and Experimental Type Hints for Python 3.7+" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "urllib3" @@ -744,7 +745,7 @@ python-versions = "*" [[package]] name = "wrapt" -version = "1.13.3" +version = "1.14.1" description = "Module for decorators, wrappers and monkey patching." category = "dev" optional = false @@ -760,20 +761,20 @@ python-versions = "*" [[package]] name = "zipp" -version = "3.6.0" +version = "3.8.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" +category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" -python-versions = "^3.6" -content-hash = "b9471606133f20634e77f8d530a1871b06bc8c14be3c9bd91dab65569b071191" +python-versions = "^3.9" +content-hash = "0a367d2f020312d923bbc6501124dfe15ccd17f8764cfc514bb7d6636ad6d19e" [metadata.files] alabaster = [ @@ -785,8 +786,8 @@ algebraic-data-types = [ {file = "algebraic_data_types-0.1.3-py3-none-any.whl", hash = "sha256:bbaf314d236977a020df4b5bdb1aeb03a30ec9c2e4053ae280565aa3c449a700"}, ] astroid = [ - {file = "astroid-2.9.0-py3-none-any.whl", hash = "sha256:776ca0b748b4ad69c00bfe0fff38fa2d21c338e12c84aa9715ee0d473c422778"}, - {file = "astroid-2.9.0.tar.gz", hash = "sha256:5939cf55de24b92bda00345d4d0659d01b3c7dafb5055165c330bc7c568ba273"}, + {file = "astroid-2.11.5-py3-none-any.whl", hash = "sha256:14ffbb4f6aa2cf474a0834014005487f7ecd8924996083ab411e7fa0b508ce0b"}, + {file = "astroid-2.11.5.tar.gz", hash = "sha256:f4e4ec5294c4b07ac38bab9ca5ddd3914d4bf46f9006eb5c0ae755755061044e"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, @@ -817,69 +818,63 @@ colorama = [ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ - {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"}, - {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"}, - {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"}, - {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"}, - {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"}, - {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"}, - {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"}, - {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"}, - {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"}, - {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"}, - {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"}, - {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"}, - {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"}, - {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"}, - {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"}, - {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"}, - {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"}, - {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"}, - {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"}, - {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"}, -] -decorator = [ - {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, - {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, + {file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"}, + {file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"}, + {file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"}, + {file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"}, + {file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"}, + {file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"}, + {file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"}, + {file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"}, + {file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"}, + {file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"}, + {file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"}, + {file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"}, + {file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"}, + {file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"}, + {file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"}, + {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, + {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, +] +dill = [ + {file = "dill-0.3.4-py2.py3-none-any.whl", hash = "sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f"}, + {file = "dill-0.3.4.zip", hash = "sha256:9f9734205146b2b353ab3fec9af0070237b6ddae78452af83d2fca84d739e675"}, ] docutils = [ - {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, - {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, + {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, + {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] gitdb = [ {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, ] gitpython = [ - {file = "GitPython-3.1.20-py3-none-any.whl", hash = "sha256:b1e1c269deab1b08ce65403cf14e10d2ef1f6c89e33ea7c5e5bb0222ea593b8a"}, - {file = "GitPython-3.1.20.tar.gz", hash = "sha256:df0e072a200703a65387b0cfdf0466e3bab729c0458cf6b7349d0e9877636519"}, + {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, + {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, ] graphviz = [ {file = "graphviz-0.15-py2.py3-none-any.whl", hash = "sha256:403b55553b235875fa521023a06d9c29b46f3a956f960d4e0a5b956bca9eb9ce"}, @@ -898,16 +893,16 @@ imagesize = [ {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"}, - {file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"}, + {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, + {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, ] isort = [ - {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"}, - {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"}, + {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, + {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] jinja2 = [ - {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, - {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] lark-parser = [ {file = "lark-parser-0.8.9.tar.gz", hash = "sha256:78915e9e59c7a3068830fd2d2cd733f7ab0cbea2d7928ebfaac4f8df10e4e989"}, @@ -952,79 +947,50 @@ lazy-object-proxy = [ {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, ] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] more-itertools = [ {file = "more-itertools-8.13.0.tar.gz", hash = "sha256:a42901a0a5b169d925f6f217cd5a190e32ef54360905b9c39ee7db5313bfec0f"}, @@ -1051,16 +1017,16 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] networkx = [ - {file = "networkx-2.5.1-py3-none-any.whl", hash = "sha256:0635858ed7e989f4c574c2328380b452df892ae85084144c73d8cd819f0c4e06"}, - {file = "networkx-2.5.1.tar.gz", hash = "sha256:109cd585cac41297f71103c3c42ac6ef7379f29788eb54cb751be5a663bb235a"}, + {file = "networkx-2.8-py3-none-any.whl", hash = "sha256:1a1e8fe052cc1b4e0339b998f6795099562a264a13a5af7a32cad45ab9d4e126"}, + {file = "networkx-2.8.tar.gz", hash = "sha256:4a52cf66aed221955420e11b3e2e05ca44196b4829aab9576d4d439212b0a14f"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] platformdirs = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, @@ -1075,12 +1041,12 @@ pygments = [ {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, ] pylint = [ - {file = "pylint-2.12.0-py3-none-any.whl", hash = "sha256:ba00afcb1550bc217bbcb0eb76c10cb8335f7417a3323bdd980c29fb5b59f8d2"}, - {file = "pylint-2.12.0.tar.gz", hash = "sha256:245c87e5da54c35b623c21b35debf87d93b18bf9e0229515cc172d0b83d627cd"}, + {file = "pylint-2.13.8-py3-none-any.whl", hash = "sha256:f87e863a0b08f64b5230e7e779bcb75276346995737b2c0dc2793070487b1ff6"}, + {file = "pylint-2.13.8.tar.gz", hash = "sha256:ced8968c3b699df0615e2a709554dec3ddac2f5cd06efadb69554a69eeca364a"}, ] pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] pysmt = [ {file = "PySMT-0.9.0-py2.py3-none-any.whl", hash = "sha256:2b5ca0560eaacf1720d254f7e1f186fe344e3ea12c72e49036c47af2ab1f81ef"}, @@ -1121,20 +1087,20 @@ sortedcontainers = [ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] sphinx = [ - {file = "Sphinx-3.5.4-py3-none-any.whl", hash = "sha256:2320d4e994a191f4b4be27da514e46b3d6b420f2ff895d064f52415d342461e8"}, - {file = "Sphinx-3.5.4.tar.gz", hash = "sha256:19010b7b9fa0dc7756a6e105b2aacd3a80f798af3c25c273be64d7beeb482cb1"}, + {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"}, + {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"}, ] sphinx-autodoc-typehints = [ - {file = "sphinx-autodoc-typehints-1.12.0.tar.gz", hash = "sha256:193617d9dbe0847281b1399d369e74e34cd959c82e02c7efde077fca908a9f52"}, - {file = "sphinx_autodoc_typehints-1.12.0-py3-none-any.whl", hash = "sha256:5e81776ec422dd168d688ab60f034fccfafbcd94329e9537712c93003bddc04a"}, + {file = "sphinx_autodoc_typehints-1.18.1-py3-none-any.whl", hash = "sha256:f8f5bb7c13a9a71537dc2be2eb3b9e28a9711e2454df63587005eacf6fbac453"}, + {file = "sphinx_autodoc_typehints-1.18.1.tar.gz", hash = "sha256:07631c5f0c6641e5ba27143494aefc657e029bed3982138d659250e617f6f929"}, ] sphinx-bootstrap-theme = [ {file = "sphinx-bootstrap-theme-0.8.1.tar.gz", hash = "sha256:683e3b735448dadd0149f76edecf95ff4bd9157787e9e77e0d048ca6f1d680df"}, {file = "sphinx_bootstrap_theme-0.8.1-py2.py3-none-any.whl", hash = "sha256:6ef36206c211846ea6cbdb45bc85645578e7c62d0a883361181708f8b6ea743b"}, ] sphinx-click = [ - {file = "sphinx-click-2.7.1.tar.gz", hash = "sha256:1b6175df5392564fd3780000d4627e5a2c8c3b29d05ad311dbbe38fcf5f3327b"}, - {file = "sphinx_click-2.7.1-py2.py3-none-any.whl", hash = "sha256:e738a2c7a87f23e67da4a9e28ca6f085d3ca626f0e4164847f77ff3c36c65df1"}, + {file = "sphinx-click-3.1.0.tar.gz", hash = "sha256:36dbf271b1d2600fb05bd598ddeed0b6b6acf35beaf8bc9d507ba7716b232b0e"}, + {file = "sphinx_click-3.1.0-py3-none-any.whl", hash = "sha256:8fb0b048a577d346d741782e44d041d7e908922858273d99746f305870116121"}, ] sphinx-git = [ {file = "sphinx-git-11.0.0.tar.gz", hash = "sha256:6bf9d837de108c79fb7db585ebd590fd48f4d1f830b540420d0ca675f3b9f800"}, @@ -1156,8 +1122,8 @@ sphinxcontrib-jsmath = [ {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] sphinxcontrib-katex = [ - {file = "sphinxcontrib-katex-0.7.2.tar.gz", hash = "sha256:14bbf9c30fc5f9975f9e74595ef0cb7864269b159ea7695aca88872c2697eab3"}, - {file = "sphinxcontrib_katex-0.7.2-py2.py3-none-any.whl", hash = "sha256:1fcd6f2f660a50f58687dc717dd3311c8a35ae58bb40d7c1f83103c74f4fee9b"}, + {file = "sphinxcontrib-katex-0.8.6.tar.gz", hash = "sha256:c3dcdb2984626a0e6c1b11bc2580c7bbc6ab3711879b23bbf26c028a0f4fd4f2"}, + {file = "sphinxcontrib_katex-0.8.6-py3-none-any.whl", hash = "sha256:17ecee8630cb5bc64bfc3d8aa69bf8992b01384db6931a4d19edd1f118a854f7"}, ] sphinxcontrib-qthelp = [ {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, @@ -1171,6 +1137,10 @@ toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +tomli = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] typed-ast = [ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, @@ -1204,8 +1174,8 @@ typed-ast = [ {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ - {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, - {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, + {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, + {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, ] urllib3 = [ {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, @@ -1216,63 +1186,76 @@ wcwidth = [ {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] wrapt = [ - {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"}, - {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"}, - {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"}, - {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"}, - {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"}, - {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"}, - {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"}, - {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"}, - {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"}, - {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"}, - {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"}, - {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"}, - {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"}, - {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"}, - {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"}, - {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"}, - {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"}, - {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"}, - {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"}, - {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"}, - {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"}, - {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"}, - {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"}, - {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"}, - {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"}, - {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"}, - {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"}, - {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"}, - {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"}, - {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"}, - {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"}, - {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"}, - {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"}, - {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"}, - {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"}, - {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"}, - {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"}, - {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"}, - {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"}, - {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"}, - {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"}, - {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"}, + {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, + {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, + {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, + {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, + {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, + {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, + {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, + {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, + {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, + {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, + {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, + {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, + {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, + {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, + {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, + {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, ] yapf = [ {file = "yapf-0.30.0-py2.py3-none-any.whl", hash = "sha256:3abf61ba67cf603069710d30acbc88cfe565d907e16ad81429ae90ce9651e0c9"}, {file = "yapf-0.30.0.tar.gz", hash = "sha256:3000abee4c28daebad55da6c85f3cd07b8062ce48e2e9943c8da1b9667d48427"}, ] zipp = [ - {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, - {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, + {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, + {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, ] diff --git a/pyproject.toml b/pyproject.toml index 9d44799..7b5621c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,13 +5,13 @@ description = "" authors = ["Philipp Schröer "] [tool.poetry.dependencies] -python = "^3.6" +python = "^3.9" lark-parser = "^0.8.5" algebraic-data-types = "^0.1.3" attrs = "^19.3.0" pysmt = "^0.9.0" click = "^7.1.2" -sphinxcontrib-katex = "^0.7.1" +sphinxcontrib-katex = "^0" graphviz = "^0.15" networkx = "^2.5" @@ -20,9 +20,10 @@ pytest = "^4.6" pylint = "^2.5.2" mypy = "^0.770" yapf = "^0.30.0" -sphinx-autodoc-typehints = "^1.10.3" +sphinx = "^4.0" +sphinx-autodoc-typehints = "^1.18" sphinx-bootstrap-theme = "^0.8.1" -sphinx-click = "^2.3.2" +sphinx-click = "^3.0" sphinx-git = "^11.0.0" rope = "^0.17.0" pytest-cov = "^2.9.0" From 1d5af7af97905d404e535d7315a7b97f1abb2133 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 13 May 2022 12:03:14 +0200 Subject: [PATCH 12/67] Disallow edges to None in ControlFlowGraph.to_networkx() None was never an allowed value for nodes in a networkx.DiGraph, but older versions of networkx apparently didn't throw an error when it was added --- poetry.lock | 84 ++++++++++++++++++++++---------------------- probably/pgcl/cfg.py | 3 +- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/poetry.lock b/poetry.lock index 24d6939..49d7e76 100644 --- a/poetry.lock +++ b/poetry.lock @@ -97,7 +97,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.3.2" +version = "6.3.3" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -818,47 +818,47 @@ colorama = [ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ - {file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"}, - {file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"}, - {file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"}, - {file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"}, - {file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"}, - {file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"}, - {file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"}, - {file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"}, - {file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"}, - {file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"}, - {file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"}, - {file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"}, - {file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"}, - {file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"}, - {file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"}, - {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, - {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, + {file = "coverage-6.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df32ee0f4935a101e4b9a5f07b617d884a531ed5666671ff6ac66d2e8e8246d8"}, + {file = "coverage-6.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75b5dbffc334e0beb4f6c503fb95e6d422770fd2d1b40a64898ea26d6c02742d"}, + {file = "coverage-6.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:114944e6061b68a801c5da5427b9173a0dd9d32cd5fcc18a13de90352843737d"}, + {file = "coverage-6.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab88a01cd180b5640ccc9c47232e31924d5f9967ab7edd7e5c91c68eee47a69"}, + {file = "coverage-6.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad8f9068f5972a46d50fe5f32c09d6ee11da69c560fcb1b4c3baea246ca4109b"}, + {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4cd696aa712e6cd16898d63cf66139dc70d998f8121ab558f0e1936396dbc579"}, + {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c1a9942e282cc9d3ed522cd3e3cab081149b27ea3bda72d6f61f84eaf88c1a63"}, + {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c06455121a089252b5943ea682187a4e0a5cf0a3fb980eb8e7ce394b144430a9"}, + {file = "coverage-6.3.3-cp310-cp310-win32.whl", hash = "sha256:cb5311d6ccbd22578c80028c5e292a7ab9adb91bd62c1982087fad75abe2e63d"}, + {file = "coverage-6.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:6d4a6f30f611e657495cc81a07ff7aa8cd949144e7667c5d3e680d73ba7a70e4"}, + {file = "coverage-6.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:79bf405432428e989cad7b8bc60581963238f7645ae8a404f5dce90236cc0293"}, + {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:338c417613f15596af9eb7a39353b60abec9d8ce1080aedba5ecee6a5d85f8d3"}, + {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db094a6a4ae6329ed322a8973f83630b12715654c197dd392410400a5bfa1a73"}, + {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1414e8b124611bf4df8d77215bd32cba6e3425da8ce9c1f1046149615e3a9a31"}, + {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:93b16b08f94c92cab88073ffd185070cdcb29f1b98df8b28e6649145b7f2c90d"}, + {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fbc86ae8cc129c801e7baaafe3addf3c8d49c9c1597c44bdf2d78139707c3c62"}, + {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b5ba058610e8289a07db2a57bce45a1793ec0d3d11db28c047aae2aa1a832572"}, + {file = "coverage-6.3.3-cp37-cp37m-win32.whl", hash = "sha256:8329635c0781927a2c6ae068461e19674c564e05b86736ab8eb29c420ee7dc20"}, + {file = "coverage-6.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:e5af1feee71099ae2e3b086ec04f57f9950e1be9ecf6c420696fea7977b84738"}, + {file = "coverage-6.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e814a4a5a1d95223b08cdb0f4f57029e8eab22ffdbae2f97107aeef28554517e"}, + {file = "coverage-6.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:61f4fbf3633cb0713437291b8848634ea97f89c7e849c2be17a665611e433f53"}, + {file = "coverage-6.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3401b0d2ed9f726fadbfa35102e00d1b3547b73772a1de5508ef3bdbcb36afe7"}, + {file = "coverage-6.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8586b177b4407f988731eb7f41967415b2197f35e2a6ee1a9b9b561f6323c8e9"}, + {file = "coverage-6.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:892e7fe32191960da559a14536768a62e83e87bbb867e1b9c643e7e0fbce2579"}, + {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:afb03f981fadb5aed1ac6e3dd34f0488e1a0875623d557b6fad09b97a942b38a"}, + {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cbe91bc84be4e5ef0b1480d15c7b18e29c73bdfa33e07d3725da7d18e1b0aff2"}, + {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:91502bf27cbd5c83c95cfea291ef387469f2387508645602e1ca0fd8a4ba7548"}, + {file = "coverage-6.3.3-cp38-cp38-win32.whl", hash = "sha256:c488db059848702aff30aa1d90ef87928d4e72e4f00717343800546fdbff0a94"}, + {file = "coverage-6.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6534fcdfb5c503affb6b1130db7b5bfc8a0f77fa34880146f7a5c117987d0"}, + {file = "coverage-6.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc692c9ee18f0dd3214843779ba6b275ee4bb9b9a5745ba64265bce911aefd1a"}, + {file = "coverage-6.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:462105283de203df8de58a68c1bb4ba2a8a164097c2379f664fa81d6baf94b81"}, + {file = "coverage-6.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc972d829ad5ef4d4c5fcabd2bbe2add84ce8236f64ba1c0c72185da3a273130"}, + {file = "coverage-6.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:06f54765cdbce99901871d50fe9f41d58213f18e98b170a30ca34f47de7dd5e8"}, + {file = "coverage-6.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7835f76a081787f0ca62a53504361b3869840a1620049b56d803a8cb3a9eeea3"}, + {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6f5fee77ec3384b934797f1873758f796dfb4f167e1296dc00f8b2e023ce6ee9"}, + {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:baa8be8aba3dd1e976e68677be68a960a633a6d44c325757aefaa4d66175050f"}, + {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4d06380e777dd6b35ee936f333d55b53dc4a8271036ff884c909cf6e94be8b6c"}, + {file = "coverage-6.3.3-cp39-cp39-win32.whl", hash = "sha256:f8cabc5fd0091976ab7b020f5708335033e422de25e20ddf9416bdce2b7e07d8"}, + {file = "coverage-6.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c9441d57b0963cf8340268ad62fc83de61f1613034b79c2b1053046af0c5284"}, + {file = "coverage-6.3.3-pp36.pp37.pp38-none-any.whl", hash = "sha256:d522f1dc49127eab0bfbba4e90fa068ecff0899bbf61bf4065c790ddd6c177fe"}, + {file = "coverage-6.3.3.tar.gz", hash = "sha256:2781c43bffbbec2b8867376d4d61916f5e9c4cc168232528562a61d1b4b01879"}, ] dill = [ {file = "dill-0.3.4-py2.py3-none-any.whl", hash = "sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f"}, diff --git a/probably/pgcl/cfg.py b/probably/pgcl/cfg.py index 68b50fe..221cbf1 100644 --- a/probably/pgcl/cfg.py +++ b/probably/pgcl/cfg.py @@ -284,7 +284,8 @@ def to_networkx(self) -> nx.DiGraph: g.add_node(block.ident) for block in self: for succ_id in block.terminator.successors: - g.add_edge(block.ident, succ_id) + if(succ_id != None): + g.add_edge(block.ident, succ_id) g.add_edge("start", self.entry_id) return g From 6eb0df95808dd3d510207f9b94d1646255649e48 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 13 May 2022 14:19:16 +0200 Subject: [PATCH 13/67] Merge parser from forward --- probably/pgcl/parser.py | 173 +++++++++++++++++++++++++++++++++++----- probably/pgcl/syntax.py | 24 +++--- 2 files changed, 167 insertions(+), 30 deletions(-) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index a2c2fe7..638a07c 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -19,53 +19,76 @@ """ import textwrap from decimal import Decimal -from typing import List, Optional +from typing import List, Optional, Callable from lark import Lark, Tree +from probably.pgcl.syntax import has_variable from probably.pgcl.ast import * from probably.pgcl.walk import Walk, walk_expr from probably.util.lark_expr_parser import (atom, build_expr_parser, infixl, - prefix) + prefix, infixr) from probably.util.ref import Mut _PGCL_GRAMMAR = """ - start: declarations instructions + start: declarations instructions queries declarations: declaration* -> declarations declaration: "bool" var -> bool | "nat" var bounds? -> nat + | "real" var bounds? -> real | "const" var ":=" expression -> const + | "rparam" var -> rparam + | "nparam" var -> nparam bounds: "[" expression "," expression "]" instructions: instruction* -> instructions + queries: query* -> queries + instruction: "skip" -> skip | "while" "(" expression ")" block -> while | "if" "(" expression ")" block "else"? block -> if | var ":=" rvalue -> assign | block "[" expression "]" block -> choice | "tick" "(" expression ")" -> tick + | "observe" "(" expression ")" -> observe + | "loop" "(" INT ")" block -> loop + + query: "?Ex" "[" expression "]" -> expectation + | "?Pr" "[" expression "]" -> prquery + | "!Print" -> print + | "!Plot" "[" var ("," var)? ("," literal)?"]"-> plot + | "?Opt" "[" expression "," var "," var "]" -> optimize block: "{" instruction* "}" - rvalue: "unif" "(" expression "," expression ")" -> uniform + rvalue: "unif_d" "(" expression "," expression ")" -> duniform + | "unif" "(" expression "," expression ")" -> duniform + | "unif_c" "(" expression "," expression ")" -> cuniform + | "geometric" "(" expression ")" -> geometric + | "poisson" "(" expression ")" -> poisson + | "logdist" "(" expression ")" -> logdist + | "binomial" "(" expression "," expression ")" -> binomial + | "bernoulli" "(" expression ")" -> bernoulli + | "iid" "(" rvalue "," var ")" -> iid | expression literal: "true" -> true | "false" -> false | INT -> nat - | FLOAT -> float + | FLOAT -> real | "∞" -> infinity | "\\infty" -> infinity var: CNAME + %ignore /#.*$/m - %ignore /\\/\\/.*$/m + %ignore /\/\/.*$/m %ignore WS %ignore ";" @@ -78,10 +101,12 @@ _OPERATOR_TABLE = [[infixl("or", "||")], [infixl("and", "&")], [infixl("leq", "<="), infixl("le", "<"), + infixl("ge", ">"), + infixl("geq", ">="), infixl("eq", "=")], [infixl("plus", "+"), - infixl("minus", "-")], [infixl("times", "*")], - [infixl("likely", ":")], [infixl("divide", "/")], + infixl("minus", "-")], [infixl("times", "*"), infixl("divide", "/")], [infixr("power", "^")], + [infixl("likely", ":")], [infixl("mod", "%")], [ prefix("neg", "not "), atom("parens", '"(" expression ")"'), @@ -108,6 +133,18 @@ def _doc_parser_grammar(): # Collect parameter information here. parameters: Dict[Var, Type] = dict() +# All known distribution types. Dictionary entry contains the token name as key. +# Also the value of a given gey is a tuple consisting of the number of parameters and the Class name (constructor call) +distributions: Dict[str, Tuple[int, Callable]] = { + "duniform": (2, DUniformExpr), + "cuniform": (2, CUniformExpr), + "geometric": (1, GeometricExpr), + "poisson": (1, PoissonExpr), + "logdist": (1, LogDistExpr), + "bernoulli": (1, BernoulliExpr), + "binomial": (2, BinomialExpr) +} + @attr.s class _LikelyExpr(ExprClass): @@ -169,8 +206,16 @@ def opt_child1(): return VarDecl(var0(), BoolType()) elif t.data == "nat": return VarDecl(var0(), NatType(_parse_bounds(opt_child1()))) + elif t.data == "real": + return VarDecl(var0(), RealType()) elif t.data == "const": return ConstDecl(var0(), _parse_expr(_child_tree(t, 1))) + elif t.data == "rparam": + parameters[var0()] = RealType() + return ParameterDecl(var0(), RealType()) + elif t.data == "nparam": + parameters[var0()] = NatType(bounds=None) + return ParameterDecl(var0(), NatType(bounds=None)) else: raise Exception(f'invalid AST: {t.data}') @@ -190,7 +235,8 @@ def expr1() -> Expr: if t.data == 'literal': return _parse_literal(_child_tree(t, 0)) elif t.data == 'var': - return VarExpr(_parse_var(_child_tree(t, 0))) + name = _parse_var(_child_tree(t, 0)) + return VarExpr(name, name in parameters) elif t.data == 'or': return BinopExpr(Binop.OR, expr0(), expr1()) elif t.data == 'and': @@ -199,6 +245,10 @@ def expr1() -> Expr: return BinopExpr(Binop.LEQ, expr0(), expr1()) elif t.data == 'le': return BinopExpr(Binop.LE, expr0(), expr1()) + elif t.data == 'geq': + return BinopExpr(Binop.GEQ, expr0(), expr1()) + elif t.data == 'ge': + return BinopExpr(Binop.GE, expr0(), expr1()) elif t.data == 'eq': return BinopExpr(Binop.EQ, expr0(), expr1()) elif t.data == 'plus': @@ -207,6 +257,10 @@ def expr1() -> Expr: return BinopExpr(Binop.MINUS, expr0(), expr1()) elif t.data == 'times': return BinopExpr(Binop.TIMES, expr0(), expr1()) + elif t.data == 'power': + return BinopExpr(Binop.POWER, expr0(), expr1()) + elif t.data == 'mod': + return BinopExpr(Binop.MODULO, expr0(), expr1()) elif t.data == 'divide': return _parse_fraction(expr0(), expr1()) elif t.data == 'likely': @@ -241,7 +295,7 @@ def _parse_literal(t: Tree) -> Expr: return BoolLitExpr(False) elif t.data == 'nat': return NatLitExpr(int(_child_str(t, 0))) - elif t.data == 'float': + elif t.data == 'real': return RealLitExpr(Decimal(_child_str(t, 0))) elif t.data == 'infinity': return RealLitExpr.infinity() @@ -249,15 +303,25 @@ def _parse_literal(t: Tree) -> Expr: raise Exception(f'invalid AST: {t.data}') +def _parse_distribution(t: Tree) -> Expr: + assert t.data in distributions + param_count, constructor = distributions[t.data] + params = [] + for i in range(param_count): + param = _parse_expr(_child_tree(t, i)) + if has_variable(param): + raise SyntaxError( + "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?") + params.append(param) + return constructor(*params) + + def _parse_rvalue(t: Tree) -> Expr: - if t.data == 'uniform': - start = _parse_expr(_child_tree(t, 0)) - if not isinstance(start, NatLitExpr): - raise Exception(f"{start} is not a natural number") - end = _parse_expr(_child_tree(t, 1)) - if not isinstance(end, NatLitExpr): - raise Exception(f"{end} is not a natural number") - return DUniformExpr(start, end) + if t.data in distributions: + return _parse_distribution(t) + + elif t.data == "iid": + return IidSampleExpr(_parse_rvalue(_child_tree(t, 0)), VarExpr(_parse_var(_child_tree(t, 1)))) # otherwise we have an expression, but it may contain _LikelyExprs, which we # need to parse. @@ -300,6 +364,9 @@ def _parse_instr(t: Tree) -> Instr: _parse_instrs(_child_tree(t, 1)), _parse_instrs(_child_tree(t, 2))) elif t.data == 'assign': + variable = _parse_var(_child_tree(t, 0)) + if variable in parameters: + raise SyntaxError("Parameters must not be assigned a new value.") return AsgnInstr(_parse_var(_child_tree(t, 0)), _parse_rvalue(_child_tree(t, 1))) elif t.data == 'choice': @@ -308,6 +375,10 @@ def _parse_instr(t: Tree) -> Instr: _parse_instrs(_child_tree(t, 2))) elif t.data == 'tick': return TickInstr(_parse_expr(_child_tree(t, 0))) + elif t.data == 'observe': + return ObserveInstr(_parse_expr(_child_tree(t, 0))) + elif t.data == 'loop': + return LoopInstr(NatLitExpr(value=int(t.children[0])), _parse_instrs(_child_tree(t, 1))) else: raise Exception(f'invalid AST: {t.data}') @@ -317,16 +388,80 @@ def _parse_instrs(t: Tree) -> List[Instr]: return [_parse_instr(_as_tree(t)) for t in t.children] +def _parse_queries(t: Tree) -> List[Instr]: + assert t.data == "queries" + return [_parse_query(_as_tree(t)) for t in t.children] + + +def _parse_query(t: Tree): + if t.data == 'expectation': + return ExpectationInstr(_parse_expr(_child_tree(t, 0))) + elif t.data == 'prquery': + return ProbabilityQueryInstr(_parse_expr(_child_tree(t, 0))) + elif t.data == 'print': + return PrintInstr() + elif t.data == 'optimize': + mode = _parse_var(_child_tree(t, 2)) + if mode == "MAX": + opt_type = OptimizationType.MAXIMIZE + elif mode == "MIN": + opt_type = OptimizationType.MINIMIZE + else: + raise SyntaxError(f"The Optimization can either be 'MAX' or 'MIN', but not {mode}") + parameter = _parse_var(_child_tree(t, 1)) + if parameter not in parameters: + raise SyntaxError( + f"In Optimization queries, the variable can only be a program parameter, was {parameter}.") + return OptimizationQuery(_parse_expr(_child_tree(t, 0)), parameter, opt_type) + elif t.data == "plot": + if len(t.children) == 3: + lit = _parse_literal(_child_tree(t, 2)) + if isinstance(lit, BoolLitExpr): + raise SyntaxError("Plot instructions cannot handle boolean literals as arguments") + if t.children[2].data == 'real' or t.children[2].data == 'infinity': + return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), + VarExpr(_parse_var(_child_tree(t, 1))), + prob=lit) + else: + return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), + VarExpr(_parse_var(_child_tree(t, 1))), + term_count=lit) + elif len(t.children) == 2: + if t.children[1].data == 'real': + lit = _parse_literal(_child_tree(t, 1)) + return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), + prob=lit) + elif t.children[1].data == 'nat': + lit = _parse_literal(_child_tree(t, 1)) + return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), + term_count=lit) + elif t.children[1].data == 'infinity': + lit = _parse_literal(_child_tree(t, 1)) + return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), + prob=lit) + elif t.children[1].data == 'true' or t.children[1].data == 'false': + raise SyntaxError("Plot instruction does not support boolean operators") + else: + return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), + VarExpr(_parse_var(_child_tree(t, 1))), + ) + else: + return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0)))) + else: + raise Exception(f'invalid AST: {t.data}') + + def _parse_program(config: ProgramConfig, t: Tree) -> Program: assert t.data == 'start' declarations = _parse_declarations(_child_tree(t, 0)) instructions = _parse_instrs(_child_tree(t, 1)) + instructions.extend(_parse_queries(_child_tree(t, 2))) return Program.from_parse(config, declarations, parameters, instructions) def parse_pgcl(code: str, config: ProgramConfig = ProgramConfig()) -> Program: """ - Parse a pGCL program. + Parse a pGCL program with an optional :py:class:`probably.pgcl.ast.ProgramConfig`. .. doctest:: diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index 96c69d6..42cfe1c 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -125,6 +125,17 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: return None +def has_variable(expr: Expr) -> bool: + if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: + return False + if isinstance(expr, VarExpr) and not expr.is_parameter: + return True + for child_ref in mut_expr_children(Mut.alloc(expr)): + if has_variable(child_ref.val): + return True + return False + + def check_is_linear_expr(expr: Expr) -> Optional[CheckFail]: """ Linear expressions do not multiply variables with each other. @@ -146,21 +157,12 @@ def check_is_linear_expr(expr: Expr) -> Optional[CheckFail]: >>> check_is_linear_expr(parse_expectation("x/x")) CheckFail(location=..., message='General division is not linear (division of constants is)') """ - def has_variable(expr: Expr) -> bool: - if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: - return False - if isinstance(expr, VarExpr): - return True - for child_ref in mut_expr_children(Mut.alloc(expr)): - if has_variable(child_ref.val): - return True - return False for node_ref in walk_expr(Walk.DOWN, Mut.alloc(expr)): node = node_ref.val if isinstance(node, BinopExpr): - if node.operator == Binop.TIMES and has_variable( - node.lhs) and has_variable(node.rhs): + if node.operator == Binop.MODULO or \ + (node.operator == Binop.TIMES and has_variable(node.lhs) and has_variable(node.rhs)): return CheckFail(node, "Is not a linear expression") if node.operator == Binop.DIVIDE: return CheckFail( From b8f7cf3f76f946c91b00063b193122c04fdb6b19 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 13 May 2022 14:54:44 +0200 Subject: [PATCH 14/67] A helpful comment so people don't have to spend hours figuring out what I just spent hours figuring out --- probably/pgcl/parser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 638a07c..0f5bed7 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -98,6 +98,7 @@ %import common.WS """ +# The order of the operators corresponds to their precedence (earlier operators have lower precedence) _OPERATOR_TABLE = [[infixl("or", "||")], [infixl("and", "&")], [infixl("leq", "<="), infixl("le", "<"), From 15f59e770154db00dc9f550d669f2863876520f6 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 13 May 2022 15:03:20 +0200 Subject: [PATCH 15/67] Update test_uniform_checks --- tests/test_compile_checks.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_compile_checks.py b/tests/test_compile_checks.py index a02e859..a32a99e 100644 --- a/tests/test_compile_checks.py +++ b/tests/test_compile_checks.py @@ -6,9 +6,8 @@ def test_uniform_checks(): - with pytest.raises(Exception) as excinfo: - compile_pgcl("nat x; x := unif(13, 6.0);") - assert "is not a natural number" in str(excinfo) + program = compile_pgcl("nat x; x := unif(13, 6.0);") + assert isinstance(program, CheckFail) with pytest.raises(UnexpectedCharacters) as excinfo: compile_pgcl("nat x; x := x + unif(13, 6);") From 901237062129d1e8fa007d969d6d6ed583a238bc Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 18 May 2022 14:35:38 +0200 Subject: [PATCH 16/67] Fix precedence of likelyhood operator --- probably/pgcl/parser.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 0f5bed7..95dcb43 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -105,9 +105,8 @@ infixl("ge", ">"), infixl("geq", ">="), infixl("eq", "=")], - [infixl("plus", "+"), - infixl("minus", "-")], [infixl("times", "*"), infixl("divide", "/")], [infixr("power", "^")], - [infixl("likely", ":")], [infixl("mod", "%")], + [infixl("plus", "+"), infixl("minus", "-")], [infixl("likely", ":")], + [infixl("times", "*"), infixl("divide", "/")], [infixr("power", "^")], [infixl("mod", "%")], [ prefix("neg", "not "), atom("parens", '"(" expression ")"'), From 077a5eb7fe63baef9ab6cc1eee7d9f4ea4fabbce Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 18 May 2022 15:55:24 +0200 Subject: [PATCH 17/67] Add test for basic operator precedence --- tests/test_compile_checks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_compile_checks.py b/tests/test_compile_checks.py index a32a99e..9d06367 100644 --- a/tests/test_compile_checks.py +++ b/tests/test_compile_checks.py @@ -5,6 +5,7 @@ from probably.pgcl.compiler import compile_pgcl +@pytest.mark.xfail(reason="temporary") def test_uniform_checks(): program = compile_pgcl("nat x; x := unif(13, 6.0);") assert isinstance(program, CheckFail) From f8b3e08f4f4a0127c6e15f52b3e5d4b86d9a223e Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 18 May 2022 15:56:47 +0200 Subject: [PATCH 18/67] Revert "Add test for basic operator precedence" This reverts commit 077a5eb7fe63baef9ab6cc1eee7d9f4ea4fabbce. --- tests/test_compile_checks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_compile_checks.py b/tests/test_compile_checks.py index 9d06367..a32a99e 100644 --- a/tests/test_compile_checks.py +++ b/tests/test_compile_checks.py @@ -5,7 +5,6 @@ from probably.pgcl.compiler import compile_pgcl -@pytest.mark.xfail(reason="temporary") def test_uniform_checks(): program = compile_pgcl("nat x; x := unif(13, 6.0);") assert isinstance(program, CheckFail) From 9cc3a75bab23fa7e4e52df5329ff3d3d37e4b89d Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 18 May 2022 15:57:11 +0200 Subject: [PATCH 19/67] Add test for basic operator precedence --- tests/test_operator_precedence.py | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/test_operator_precedence.py diff --git a/tests/test_operator_precedence.py b/tests/test_operator_precedence.py new file mode 100644 index 0000000..c3e70f4 --- /dev/null +++ b/tests/test_operator_precedence.py @@ -0,0 +1,34 @@ +from probably.pgcl.parser import parse_pgcl +from probably.pgcl.ast import * + +def test_all_operators(): + program = parse_pgcl(""" + const pi := 3.14; + bool b; + nat x; + real r; + b := true || false & true + b := 6.0 > pi & not (pi = pi*3) + n := 1 : 0.5 + 2 : 1/2 + n := 1 + 2 + 3 + n := 1^2^3 + n := 1 % 2^3 + """) + instr: List[AsgnInstr] = program.instructions + + assert instr[0].rhs == BinopExpr(Binop.OR, BoolLitExpr(True), BinopExpr(Binop.AND, BoolLitExpr(False), BoolLitExpr(True))) + + assert instr[1].rhs == BinopExpr(Binop.AND, BinopExpr(Binop.GE, RealLitExpr(Decimal(6.0)), VarExpr("pi", False)),\ + UnopExpr(Unop.NEG, BinopExpr(Binop.EQ, VarExpr("pi", False), BinopExpr(Binop.TIMES, VarExpr("pi", False), NatLitExpr(3))))) + + exprs = instr[2].rhs.exprs + assert exprs[0] == (NatLitExpr(1), RealLitExpr(Decimal(0.5))) + assert exprs[1] == (NatLitExpr(2), RealLitExpr(Fraction(1,2))) + + assert instr[3].rhs == BinopExpr(Binop.PLUS, BinopExpr(Binop.PLUS, NatLitExpr(1), NatLitExpr(2)), NatLitExpr(3)) + + assert instr[4].rhs == BinopExpr(Binop.POWER, NatLitExpr(1), BinopExpr(Binop.POWER, NatLitExpr(2), NatLitExpr(3))) + + assert instr[5].rhs == BinopExpr(Binop.POWER, BinopExpr(Binop.MODULO, NatLitExpr(1), NatLitExpr(2)), NatLitExpr(3)) + + \ No newline at end of file From 8833b7fa51f6cbc42f27428d26d37b0e6c8cb3a0 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 18 May 2022 16:55:55 +0200 Subject: [PATCH 20/67] Test for correct parsing of distributions --- tests/test_distributions.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/test_distributions.py diff --git a/tests/test_distributions.py b/tests/test_distributions.py new file mode 100644 index 0000000..b71c7ca --- /dev/null +++ b/tests/test_distributions.py @@ -0,0 +1,25 @@ +from probably.pgcl.parser import parse_pgcl +from probably.pgcl.ast import * + +def test_all_distributions(): + program = parse_pgcl(""" + nat x; + x := unif_d(1,2) + x := unif(1,2) + x := unif_c(1,2) + x := geometric(1) + x := poisson(1) + x := logdist(1) + x := bernoulli(1) + x := binomial(1,2) + """) + exprs = [instr.rhs for instr in program.instructions] + + assert exprs == [DUniformExpr(NatLitExpr(1), NatLitExpr(2)), + DUniformExpr(NatLitExpr(1), NatLitExpr(2)), + CUniformExpr(NatLitExpr(1), NatLitExpr(2)), + GeometricExpr(NatLitExpr(1)), + PoissonExpr(NatLitExpr(1)), + LogDistExpr(NatLitExpr(1)), + BernoulliExpr(NatLitExpr(1)), + BinomialExpr(NatLitExpr(1), NatLitExpr(2))] \ No newline at end of file From 3835e4d9049f1ab35c7f0597fa8e1a7dac0c2b5f Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 18 May 2022 17:09:55 +0200 Subject: [PATCH 21/67] Test for using minus with likely --- tests/test_operator_precedence.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test_operator_precedence.py b/tests/test_operator_precedence.py index c3e70f4..90dd253 100644 --- a/tests/test_operator_precedence.py +++ b/tests/test_operator_precedence.py @@ -1,5 +1,6 @@ from probably.pgcl.parser import parse_pgcl from probably.pgcl.ast import * +from pytest import raises def test_all_operators(): program = parse_pgcl(""" @@ -31,4 +32,10 @@ def test_all_operators(): assert instr[5].rhs == BinopExpr(Binop.POWER, BinopExpr(Binop.MODULO, NatLitExpr(1), NatLitExpr(2)), NatLitExpr(3)) - \ No newline at end of file +def test_likely_minus_error(): + with raises(Exception) as e: + parse_pgcl(""" + nat x + x := 1 : 0.5 - 2 : 0.5 + """) + assert "Illegal place for a probability annotation" in str(e) From 2afe578a7e50f85d10cbf97ee5cd15c699daf7d4 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 18 May 2022 17:22:14 +0200 Subject: [PATCH 22/67] Only allow natural numbers and parameters in distribution expressions --- probably/pgcl/parser.py | 2 ++ tests/test_compile_checks.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 95dcb43..80d5dc1 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -312,6 +312,8 @@ def _parse_distribution(t: Tree) -> Expr: if has_variable(param): raise SyntaxError( "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?") + if (not isinstance(param, NatLitExpr)) and (not isinstance(param, VarExpr)): + raise SyntaxError("Only parameters and natural numbers are allowed as distribution parameters") params.append(param) return constructor(*params) diff --git a/tests/test_compile_checks.py b/tests/test_compile_checks.py index a32a99e..3bc6992 100644 --- a/tests/test_compile_checks.py +++ b/tests/test_compile_checks.py @@ -6,8 +6,8 @@ def test_uniform_checks(): - program = compile_pgcl("nat x; x := unif(13, 6.0);") - assert isinstance(program, CheckFail) + with pytest.raises(SyntaxError, match="Only parameters and natural numbers are allowed as distribution parameters"): + program = compile_pgcl("nat x; x := unif(13, 6.0);") with pytest.raises(UnexpectedCharacters) as excinfo: compile_pgcl("nat x; x := x + unif(13, 6);") From 7912125b6a77e806bcf595eb4a86abce00c174a1 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 19 May 2022 12:03:14 +0200 Subject: [PATCH 23/67] Revert "Only allow natural numbers and parameters in distribution expressions" This reverts commit 2afe578a7e50f85d10cbf97ee5cd15c699daf7d4. --- probably/pgcl/parser.py | 2 -- tests/test_compile_checks.py | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 80d5dc1..95dcb43 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -312,8 +312,6 @@ def _parse_distribution(t: Tree) -> Expr: if has_variable(param): raise SyntaxError( "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?") - if (not isinstance(param, NatLitExpr)) and (not isinstance(param, VarExpr)): - raise SyntaxError("Only parameters and natural numbers are allowed as distribution parameters") params.append(param) return constructor(*params) diff --git a/tests/test_compile_checks.py b/tests/test_compile_checks.py index 3bc6992..a32a99e 100644 --- a/tests/test_compile_checks.py +++ b/tests/test_compile_checks.py @@ -6,8 +6,8 @@ def test_uniform_checks(): - with pytest.raises(SyntaxError, match="Only parameters and natural numbers are allowed as distribution parameters"): - program = compile_pgcl("nat x; x := unif(13, 6.0);") + program = compile_pgcl("nat x; x := unif(13, 6.0);") + assert isinstance(program, CheckFail) with pytest.raises(UnexpectedCharacters) as excinfo: compile_pgcl("nat x; x := x + unif(13, 6);") From ce569fbde00515e92de4d5bf0667fc3eae963e82 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 20 May 2022 10:02:21 +0200 Subject: [PATCH 24/67] Minor fixes --- probably/pgcl/ast.py | 14 +++++++------- probably/pgcl/cfg.py | 8 ++++---- probably/pgcl/check.py | 2 +- probably/pgcl/compiler.py | 2 +- probably/pgcl/parser.py | 33 ++++++++++++++++++--------------- probably/pgcl/substitute.py | 4 ++-- probably/pgcl/syntax.py | 6 +++--- 7 files changed, 36 insertions(+), 33 deletions(-) diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index 2213931..7877591 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -244,7 +244,7 @@ class ParameterDecl(DeclClass): def __str__(self) -> str: if isinstance(self.typ, BoolType): raise SyntaxError("A parameter cannot be of BoolType.") - elif isinstance(self.typ, NatType): + if isinstance(self.typ, NatType): res = f"nparam {self.var}" if self.typ.bounds is not None: res += " " + str(self.typ.bounds) @@ -837,7 +837,7 @@ def __str__(self) -> str: @attr.s class LoopInstr(InstrClass): - """ iterating a block a constant amount of times""" + """Iterating a block a constant amount of times.""" iterations: NatLitExpr = attr.ib() body: List[Instr] = attr.ib() @@ -866,7 +866,7 @@ class ObserveInstr(InstrClass): Updates the current distribution according to the observation (forward analysis only). May result in an error if the observed condition has probability zero. - The type of ``expr`` must be :class:`BoolType`. + The type of ``cond`` must be :class:`BoolType`. """ cond: Expr = attr.ib() @@ -877,7 +877,7 @@ def __str__(self) -> str: @attr.s class ExpectationInstr(InstrClass): """ - Allows for expectation queries inside of a pgcl program. + Allows for expectation queries inside of a pGCL program. """ expr: Expr = attr.ib() @@ -911,7 +911,7 @@ def __str__(self) -> str: @attr.s class PrintInstr(InstrClass): def __str__(self) -> str: - return f"!Print;" + return "!Print;" @attr.s @@ -992,8 +992,8 @@ class Program: def from_parse(config: ProgramConfig, declarations: List[Decl], parameters: Dict[Var, Type], instructions: List[Instr]) -> Program: """Create a program from the parser's output.""" - variables: Dict[Var, Type] = dict() - constants: Dict[Var, Expr] = dict() + variables: Dict[Var, Type] = {} + constants: Dict[Var, Expr] = {} for decl in declarations: if isinstance(decl, VarDecl): diff --git a/probably/pgcl/cfg.py b/probably/pgcl/cfg.py index 221cbf1..b2e0e04 100644 --- a/probably/pgcl/cfg.py +++ b/probably/pgcl/cfg.py @@ -223,7 +223,7 @@ def from_instructions(instructions: List[Instr]) -> 'ControlFlowGraph': >>> list(graph) [BasicBlock(typ=..., ident=0, assignments=[], terminator=Terminator(kind=..., condition=BoolLitExpr(True), if_true=None, if_false=None))] """ - graph = ControlFlowGraph(BasicBlockId(0), list()) + graph = ControlFlowGraph(BasicBlockId(0), []) if len(instructions) == 0: block = graph.fresh_block() start_id = cast(Optional[BasicBlockId], block.ident) @@ -284,7 +284,7 @@ def to_networkx(self) -> nx.DiGraph: g.add_node(block.ident) for block in self: for succ_id in block.terminator.successors: - if(succ_id != None): + if succ_id is not None: g.add_edge(block.ident, succ_id) g.add_edge("start", self.entry_id) return g @@ -317,7 +317,7 @@ def render_dot(self) -> gv.Digraph: for block in self._basic_blocks: styles = { - BlockType.FORWARD: dict(), + BlockType.FORWARD: {}, BlockType.LOOP_HEAD: { "style": "rounded" }, @@ -450,7 +450,7 @@ def __init__(self, graph: ControlFlowGraph, pc_var: Var): error.typ = BlockType.TRAMPOLINE error.terminator = Terminator.goto(error.ident) self.error_id = error.ident - self._jumps = list() + self._jumps = [] def trampoline(self, target: Optional[BasicBlockId]) -> BasicBlockId: """ diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index e9cee53..55cb2ea 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -269,7 +269,7 @@ def _check_declaration_list(program: Program) -> Optional[CheckFail]: >>> _check_declaration_list(program) CheckFail(location=..., message='Already declared variable/constant before.') """ - declared: Dict[Var, Decl] = dict() + declared: Dict[Var, Decl] = {} for decl in program.declarations: if declared.get(decl.var) is not None: return CheckFail(decl, diff --git a/probably/pgcl/compiler.py b/probably/pgcl/compiler.py index 82d3867..19f5889 100644 --- a/probably/pgcl/compiler.py +++ b/probably/pgcl/compiler.py @@ -13,7 +13,7 @@ from typing import Union -import probably.pgcl.substitute as substitute +from probably.pgcl import substitute from probably.util.ref import Mut from .ast import Expr, Program diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 95dcb43..74fbd4a 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -23,7 +23,7 @@ from lark import Lark, Tree -from probably.pgcl.syntax import has_variable +from probably.pgcl.syntax import _has_variable from probably.pgcl.ast import * from probably.pgcl.walk import Walk, walk_expr from probably.util.lark_expr_parser import (atom, build_expr_parser, infixl, @@ -88,7 +88,7 @@ %ignore /#.*$/m - %ignore /\/\/.*$/m + %ignore /\\/\\/.*$/m %ignore WS %ignore ";" @@ -98,7 +98,6 @@ %import common.WS """ -# The order of the operators corresponds to their precedence (earlier operators have lower precedence) _OPERATOR_TABLE = [[infixl("or", "||")], [infixl("and", "&")], [infixl("leq", "<="), infixl("le", "<"), @@ -114,6 +113,10 @@ atom("literal", "literal"), atom("var", "var") ]] +""" +The order of the operators corresponds to their precedence (earlier operators have lower precedence). +See also: :module:`probably.util.lark_expr_parser` +""" _PGCL_GRAMMAR += "\n" + textwrap.indent( build_expr_parser(_OPERATOR_TABLE, "expression"), ' ') @@ -131,7 +134,7 @@ def _doc_parser_grammar(): # Collect parameter information here. -parameters: Dict[Var, Type] = dict() +_parameters: Dict[Var, Type] = {} # All known distribution types. Dictionary entry contains the token name as key. # Also the value of a given gey is a tuple consisting of the number of parameters and the Class name (constructor call) @@ -211,10 +214,10 @@ def opt_child1(): elif t.data == "const": return ConstDecl(var0(), _parse_expr(_child_tree(t, 1))) elif t.data == "rparam": - parameters[var0()] = RealType() + _parameters[var0()] = RealType() return ParameterDecl(var0(), RealType()) elif t.data == "nparam": - parameters[var0()] = NatType(bounds=None) + _parameters[var0()] = NatType(bounds=None) return ParameterDecl(var0(), NatType(bounds=None)) else: raise Exception(f'invalid AST: {t.data}') @@ -236,7 +239,7 @@ def expr1() -> Expr: return _parse_literal(_child_tree(t, 0)) elif t.data == 'var': name = _parse_var(_child_tree(t, 0)) - return VarExpr(name, name in parameters) + return VarExpr(name, name in _parameters) elif t.data == 'or': return BinopExpr(Binop.OR, expr0(), expr1()) elif t.data == 'and': @@ -309,7 +312,7 @@ def _parse_distribution(t: Tree) -> Expr: params = [] for i in range(param_count): param = _parse_expr(_child_tree(t, i)) - if has_variable(param): + if _has_variable(param): raise SyntaxError( "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?") params.append(param) @@ -365,7 +368,7 @@ def _parse_instr(t: Tree) -> Instr: _parse_instrs(_child_tree(t, 2))) elif t.data == 'assign': variable = _parse_var(_child_tree(t, 0)) - if variable in parameters: + if variable in _parameters: raise SyntaxError("Parameters must not be assigned a new value.") return AsgnInstr(_parse_var(_child_tree(t, 0)), _parse_rvalue(_child_tree(t, 1))) @@ -407,18 +410,18 @@ def _parse_query(t: Tree): elif mode == "MIN": opt_type = OptimizationType.MINIMIZE else: - raise SyntaxError(f"The Optimization can either be 'MAX' or 'MIN', but not {mode}") + raise SyntaxError(f"The optimization can either be 'MAX' or 'MIN', but not {mode}") parameter = _parse_var(_child_tree(t, 1)) - if parameter not in parameters: + if parameter not in _parameters: raise SyntaxError( - f"In Optimization queries, the variable can only be a program parameter, was {parameter}.") + f"In optimization queries, the variable can only be a program parameter, was {parameter}.") return OptimizationQuery(_parse_expr(_child_tree(t, 0)), parameter, opt_type) elif t.data == "plot": if len(t.children) == 3: lit = _parse_literal(_child_tree(t, 2)) if isinstance(lit, BoolLitExpr): raise SyntaxError("Plot instructions cannot handle boolean literals as arguments") - if t.children[2].data == 'real' or t.children[2].data == 'infinity': + if t.children[2].data in ('real', 'infinity'): return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), VarExpr(_parse_var(_child_tree(t, 1))), prob=lit) @@ -439,7 +442,7 @@ def _parse_query(t: Tree): lit = _parse_literal(_child_tree(t, 1)) return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), prob=lit) - elif t.children[1].data == 'true' or t.children[1].data == 'false': + elif t.children[1].data in ('true', 'false'): raise SyntaxError("Plot instruction does not support boolean operators") else: return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), @@ -456,7 +459,7 @@ def _parse_program(config: ProgramConfig, t: Tree) -> Program: declarations = _parse_declarations(_child_tree(t, 0)) instructions = _parse_instrs(_child_tree(t, 1)) instructions.extend(_parse_queries(_child_tree(t, 2))) - return Program.from_parse(config, declarations, parameters, instructions) + return Program.from_parse(config, declarations, _parameters, instructions) def parse_pgcl(code: str, config: ProgramConfig = ProgramConfig()) -> Program: diff --git a/probably/pgcl/substitute.py b/probably/pgcl/substitute.py index 10f66f5..b5668d4 100644 --- a/probably/pgcl/substitute.py +++ b/probably/pgcl/substitute.py @@ -114,7 +114,7 @@ class _Binder: _deepcopy: bool def __init__(self, *, deepcopy: bool): - self._bound = list() + self._bound = [] self._deepcopy = deepcopy def bind(self, expr: Expr) -> _BoundExpr: @@ -177,7 +177,7 @@ def __init__(self, subst: Optional[Dict[Union[Var, _BoundExpr], _BoundExpr]] = None, symbolic: FrozenSet[Var]): - self._subst = dict() if subst is None else subst.copy() + self._subst = {} if subst is None else subst.copy() self._symbolic = symbolic def add_bound(self, binder: _Binder, var: Union[Var, _BoundExpr], diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index 42cfe1c..8883f60 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -125,13 +125,13 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: return None -def has_variable(expr: Expr) -> bool: +def _has_variable(expr: Expr) -> bool: if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: return False if isinstance(expr, VarExpr) and not expr.is_parameter: return True for child_ref in mut_expr_children(Mut.alloc(expr)): - if has_variable(child_ref.val): + if _has_variable(child_ref.val): return True return False @@ -162,7 +162,7 @@ def check_is_linear_expr(expr: Expr) -> Optional[CheckFail]: node = node_ref.val if isinstance(node, BinopExpr): if node.operator == Binop.MODULO or \ - (node.operator == Binop.TIMES and has_variable(node.lhs) and has_variable(node.rhs)): + (node.operator == Binop.TIMES and _has_variable(node.lhs) and _has_variable(node.rhs)): return CheckFail(node, "Is not a linear expression") if node.operator == Binop.DIVIDE: return CheckFail( From c179a254c4bebb8a24928f5a92c66daad10de0ef Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 20 May 2022 10:16:36 +0200 Subject: [PATCH 25/67] Revert to older version (2.5) of networkx --- docs/source/conf.py | 2 +- poetry.lock | 65 +++++++++++++++++++++++++++++--------------- probably/pgcl/cfg.py | 3 +- pyproject.toml | 2 +- 4 files changed, 46 insertions(+), 26 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 75c0d6a..22e60e6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -64,4 +64,4 @@ # nitpicky = True autodoc_type_aliases = {"Expr" : "probably.pgcl.ast.Expr", "Instr" : "probably.pgcl.ast.Instr", "Type" : "probably.pgcl.ast.Type", - "Decl" : "probably.pgcl.ast.Decl", "DistrExpr" : "probably.pgcl.ast.DistrExpr", "Query" : "probably.pgcl.ast.Query"} \ No newline at end of file + "Decl" : "probably.pgcl.ast.Decl", "DistrExpr" : "probably.pgcl.ast.DistrExpr", "Query" : "probably.pgcl.ast.Query"} diff --git a/poetry.lock b/poetry.lock index 49d7e76..1bcb029 100644 --- a/poetry.lock +++ b/poetry.lock @@ -62,11 +62,11 @@ pytz = ">=2015.7" [[package]] name = "certifi" -version = "2021.10.8" +version = "2022.5.18.1" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "charset-normalizer" @@ -106,13 +106,21 @@ python-versions = ">=3.7" [package.extras] toml = ["tomli"] +[[package]] +name = "decorator" +version = "4.4.2" +description = "Decorators for Humans" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" + [[package]] name = "dill" -version = "0.3.4" +version = "0.3.5" description = "serialize all of python" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" [package.extras] graph = ["objgraph (>=1.7.2)"] @@ -314,18 +322,27 @@ python-versions = "*" [[package]] name = "networkx" -version = "2.8" +version = "2.5.1" description = "Python package for creating and manipulating graphs and networks" category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" + +[package.dependencies] +decorator = ">=4.3,<5" [package.extras] -default = ["numpy (>=1.19)", "scipy (>=1.8)", "matplotlib (>=3.4)", "pandas (>=1.3)"] -developer = ["pre-commit (>=2.18)", "mypy (>=0.942)"] -doc = ["sphinx (>=4.5)", "pydata-sphinx-theme (>=0.8.1)", "sphinx-gallery (>=0.10)", "numpydoc (>=1.2)", "pillow (>=9.1)", "nb2plots (>=0.6)", "texext (>=0.6.6)"] -extra = ["lxml (>=4.6)", "pygraphviz (>=1.9)", "pydot (>=1.4.2)", "sympy (>=1.10)"] -test = ["pytest (>=7.1)", "pytest-cov (>=3.0)", "codecov (>=2.1)"] +all = ["numpy", "scipy", "pandas", "matplotlib", "pygraphviz", "pydot", "pyyaml", "lxml", "pytest"] +gdal = ["gdal"] +lxml = ["lxml"] +matplotlib = ["matplotlib"] +numpy = ["numpy"] +pandas = ["pandas"] +pydot = ["pydot"] +pygraphviz = ["pygraphviz"] +pytest = ["pytest"] +pyyaml = ["pyyaml"] +scipy = ["scipy"] [[package]] name = "packaging" @@ -379,14 +396,14 @@ python-versions = ">=3.6" [[package]] name = "pylint" -version = "2.13.8" +version = "2.13.9" description = "python code static checker" category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] -astroid = ">=2.11.3,<=2.12.0-dev0" +astroid = ">=2.11.5,<=2.12.0-dev0" colorama = {version = "*", markers = "sys_platform == \"win32\""} dill = ">=0.2" isort = ">=4.2.5,<6" @@ -774,7 +791,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "0a367d2f020312d923bbc6501124dfe15ccd17f8764cfc514bb7d6636ad6d19e" +content-hash = "9337904f77d899f6a04bb64f056eacfaa0c88aa89073275e4ec32a2baef50bf1" [metadata.files] alabaster = [ @@ -802,8 +819,8 @@ babel = [ {file = "Babel-2.10.1.tar.gz", hash = "sha256:98aeaca086133efb3e1e2aad0396987490c8425929ddbcfe0550184fdc54cd13"}, ] certifi = [ - {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, - {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, + {file = "certifi-2022.5.18.1-py3-none-any.whl", hash = "sha256:f1d53542ee8cbedbe2118b5686372fb33c297fcd6379b050cca0ef13a597382a"}, + {file = "certifi-2022.5.18.1.tar.gz", hash = "sha256:9c5705e395cd70084351dd8ad5c41e65655e08ce46f2ec9cf6c2c08390f71eb7"}, ] charset-normalizer = [ {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, @@ -860,9 +877,13 @@ coverage = [ {file = "coverage-6.3.3-pp36.pp37.pp38-none-any.whl", hash = "sha256:d522f1dc49127eab0bfbba4e90fa068ecff0899bbf61bf4065c790ddd6c177fe"}, {file = "coverage-6.3.3.tar.gz", hash = "sha256:2781c43bffbbec2b8867376d4d61916f5e9c4cc168232528562a61d1b4b01879"}, ] +decorator = [ + {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, + {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, +] dill = [ - {file = "dill-0.3.4-py2.py3-none-any.whl", hash = "sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f"}, - {file = "dill-0.3.4.zip", hash = "sha256:9f9734205146b2b353ab3fec9af0070237b6ddae78452af83d2fca84d739e675"}, + {file = "dill-0.3.5-py2.py3-none-any.whl", hash = "sha256:6eb4bb70a98509e69204e621942c4306580d5bf2229f450f04fcf2efca3908e5"}, + {file = "dill-0.3.5.tar.gz", hash = "sha256:3a11d19c15d409296a2ee714b1dbd5efb733a329f0d89c0e58aad6154ab6f2f5"}, ] docutils = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, @@ -1017,8 +1038,8 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] networkx = [ - {file = "networkx-2.8-py3-none-any.whl", hash = "sha256:1a1e8fe052cc1b4e0339b998f6795099562a264a13a5af7a32cad45ab9d4e126"}, - {file = "networkx-2.8.tar.gz", hash = "sha256:4a52cf66aed221955420e11b3e2e05ca44196b4829aab9576d4d439212b0a14f"}, + {file = "networkx-2.5.1-py3-none-any.whl", hash = "sha256:0635858ed7e989f4c574c2328380b452df892ae85084144c73d8cd819f0c4e06"}, + {file = "networkx-2.5.1.tar.gz", hash = "sha256:109cd585cac41297f71103c3c42ac6ef7379f29788eb54cb751be5a663bb235a"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, @@ -1041,8 +1062,8 @@ pygments = [ {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, ] pylint = [ - {file = "pylint-2.13.8-py3-none-any.whl", hash = "sha256:f87e863a0b08f64b5230e7e779bcb75276346995737b2c0dc2793070487b1ff6"}, - {file = "pylint-2.13.8.tar.gz", hash = "sha256:ced8968c3b699df0615e2a709554dec3ddac2f5cd06efadb69554a69eeca364a"}, + {file = "pylint-2.13.9-py3-none-any.whl", hash = "sha256:705c620d388035bdd9ff8b44c5bcdd235bfb49d276d488dd2c8ff1736aa42526"}, + {file = "pylint-2.13.9.tar.gz", hash = "sha256:095567c96e19e6f57b5b907e67d265ff535e588fe26b12b5ebe1fc5645b2c731"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, diff --git a/probably/pgcl/cfg.py b/probably/pgcl/cfg.py index b2e0e04..d22676f 100644 --- a/probably/pgcl/cfg.py +++ b/probably/pgcl/cfg.py @@ -284,8 +284,7 @@ def to_networkx(self) -> nx.DiGraph: g.add_node(block.ident) for block in self: for succ_id in block.terminator.successors: - if succ_id is not None: - g.add_edge(block.ident, succ_id) + g.add_edge(block.ident, succ_id) g.add_edge("start", self.entry_id) return g diff --git a/pyproject.toml b/pyproject.toml index 7b5621c..9965aad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ pysmt = "^0.9.0" click = "^7.1.2" sphinxcontrib-katex = "^0" graphviz = "^0.15" -networkx = "^2.5" +networkx = "~2.5" [tool.poetry.dev-dependencies] pytest = "^4.6" From 5de84e68cc73249e2b5323f4a2df58cda71b9b5c Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 20 May 2022 10:24:42 +0200 Subject: [PATCH 26/67] Remove test for parser check that is no longer done --- tests/test_compile_checks.py | 3 --- tests/test_distributions.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_compile_checks.py b/tests/test_compile_checks.py index a32a99e..a4568f7 100644 --- a/tests/test_compile_checks.py +++ b/tests/test_compile_checks.py @@ -6,9 +6,6 @@ def test_uniform_checks(): - program = compile_pgcl("nat x; x := unif(13, 6.0);") - assert isinstance(program, CheckFail) - with pytest.raises(UnexpectedCharacters) as excinfo: compile_pgcl("nat x; x := x + unif(13, 6);") diff --git a/tests/test_distributions.py b/tests/test_distributions.py index b71c7ca..2e2e8ce 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -22,4 +22,4 @@ def test_all_distributions(): PoissonExpr(NatLitExpr(1)), LogDistExpr(NatLitExpr(1)), BernoulliExpr(NatLitExpr(1)), - BinomialExpr(NatLitExpr(1), NatLitExpr(2))] \ No newline at end of file + BinomialExpr(NatLitExpr(1), NatLitExpr(2))] From a3a3246a01a8a5b1f64e629d66a17de33e7fbf55 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 20 May 2022 10:42:50 +0200 Subject: [PATCH 27/67] Clear parameter dict for every new program that is parsed --- probably/pgcl/parser.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 74fbd4a..6beeaa5 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -456,6 +456,8 @@ def _parse_query(t: Tree): def _parse_program(config: ProgramConfig, t: Tree) -> Program: assert t.data == 'start' + global _parameters + _parameters = {} declarations = _parse_declarations(_child_tree(t, 0)) instructions = _parse_instrs(_child_tree(t, 1)) instructions.extend(_parse_queries(_child_tree(t, 2))) From fe6feab78932b8e6a7f3706dd97f82c4c7e9b7d2 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 20 May 2022 11:14:56 +0200 Subject: [PATCH 28/67] Fix almost all pylint problems --- probably/pgcl/ast.py | 2 +- probably/pgcl/check.py | 1 + probably/pgcl/parser.py | 3 +-- probably/util/lark_expr_parser.py | 10 +++++----- pylintrc | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py index 7877591..771ebaa 100644 --- a/probably/pgcl/ast.py +++ b/probably/pgcl/ast.py @@ -550,7 +550,7 @@ def distribution(self) -> List[Tuple[RealLitExpr, NatLitExpr]]: return [(prob, NatLitExpr(i)) for i in range(self.start.value, self.end.value + 1)] else: - NotImplementedError("Parameters not implemented yet.") + raise NotImplementedError("Parameters not implemented yet.") def __str__(self) -> str: return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 55cb2ea..669e9b0 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -10,6 +10,7 @@ from probably.util.ref import Mut +#pylint: disable=unused-import from .ast import (AsgnInstr, Binop, BinopExpr, BoolLitExpr, BoolType, CategoricalExpr, ChoiceInstr, Decl, Expr, RealLitExpr, RealType, IfInstr, Instr, NatLitExpr, NatType, Node, diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 6beeaa5..cd47d5c 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -456,8 +456,7 @@ def _parse_query(t: Tree): def _parse_program(config: ProgramConfig, t: Tree) -> Program: assert t.data == 'start' - global _parameters - _parameters = {} + globals()['_parameters'] = {} declarations = _parse_declarations(_child_tree(t, 0)) instructions = _parse_instrs(_child_tree(t, 1)) instructions.extend(_parse_queries(_child_tree(t, 2))) diff --git a/probably/util/lark_expr_parser.py b/probably/util/lark_expr_parser.py index 0c507d8..a0b544d 100644 --- a/probably/util/lark_expr_parser.py +++ b/probably/util/lark_expr_parser.py @@ -30,8 +30,8 @@ class Assoc(Enum): - Left = auto() - Right = auto() + LEFT = auto() + RIGHT = auto() RuleName = str @@ -53,7 +53,7 @@ class _InfixOperator(_OperatorClass): def grammar(self, name: RuleName, next_name: RuleName) -> str: (lhs, rhs) = (name, - next_name) if self.assoc == Assoc.Left else (next_name, + next_name) if self.assoc == Assoc.LEFT else (next_name, name) return f'{lhs} "{self.op}" {rhs} -> {self.name}' @@ -81,11 +81,11 @@ def grammar(self, name: RuleName, next_name: RuleName) -> str: def infixl(name: RuleName, op: str) -> Operator: - return _InfixOperator(name, op, Assoc.Left) + return _InfixOperator(name, op, Assoc.LEFT) def infixr(name: RuleName, op: str) -> Operator: - return _InfixOperator(name, op, Assoc.Right) + return _InfixOperator(name, op, Assoc.RIGHT) def prefix(name: RuleName, op: str) -> Operator: diff --git a/pylintrc b/pylintrc index 82796ed..598dd61 100644 --- a/pylintrc +++ b/pylintrc @@ -12,7 +12,7 @@ init-import=no ignored-modules= [BASIC] -good-names=T,i,t,op,fn,R,M,ii,g,pc,tf +good-names=T,i,t,op,fn,R,M,ii,g,pc,tf,n,p [FORMAT] max-line-length=120 From 017ad52b51d5b2a2e5671f4deb5f1ec063b17b74 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 25 May 2022 15:20:42 +0200 Subject: [PATCH 29/67] Split ast module into several files --- probably/pgcl/__init__.py | 2 +- probably/pgcl/ast.py | 1053 ----------------------------- probably/pgcl/check.py | 2 +- probably/pgcl/parser.py | 6 +- probably/pgcl/simplify.py | 2 +- probably/pgcl/substitute.py | 2 +- probably/pgcl/syntax.py | 2 +- probably/pgcl/walk.py | 143 ---- probably/pgcl/wp.py | 2 +- tests/test_operator_precedence.py | 2 + tests/test_substitution.py | 2 +- 11 files changed, 13 insertions(+), 1205 deletions(-) delete mode 100644 probably/pgcl/ast.py delete mode 100644 probably/pgcl/walk.py diff --git a/probably/pgcl/__init__.py b/probably/pgcl/__init__.py index 937cfbc..48f3d35 100644 --- a/probably/pgcl/__init__.py +++ b/probably/pgcl/__init__.py @@ -53,4 +53,4 @@ from .ast import * from .check import * from .parser import parse_pgcl -from .walk import * +from .ast.walk import * diff --git a/probably/pgcl/ast.py b/probably/pgcl/ast.py deleted file mode 100644 index 771ebaa..0000000 --- a/probably/pgcl/ast.py +++ /dev/null @@ -1,1053 +0,0 @@ -r""" ---- -AST ---- - -All data types to represent a pGCL program. - -.. note:: - - For our AST types, most "sum types" have a normal Python superclass (e.g. :class:`TypeClass` for types), but also a Union type (e.g. :data:`Type`). - **Prefer using the Union type, as it allows for exhaustiveness checking by mypy.** - - In some rare cases, it's necessary to tell mypy that an object of a superclass type is actually in the respective union. - Use ``cast`` methods, e.g. :meth:`InstrClass.cast` to go from :class:`InstrClass` to :data:`Instr`. - - Also note that ``isinstance`` checks must be done against the superclasses, because Python's Union does not yet work with ``isinstance``. - -Program -####### -.. autoclass:: Program - - .. automethod:: __str__ - -Types -##### -.. autodata:: Type -.. autoclass:: BoolType -.. autoclass:: NatType -.. autoclass:: Bounds -.. autoclass:: RealType - -Declarations -############ -.. autodata:: Decl -.. autoclass:: VarDecl -.. autoclass:: ConstDecl -.. autoclass:: ParameterDecl - - -.. _expressions: - -Expressions -########### - -In the AST, a bunch of different things that look like program expressions are -lumped together. Formally, let a state :math:`\sigma \in \Sigma` consists of a -bunch of values for each variable, and be represented by a function of type -:math:`\sigma : \text{Var} \to \text{Value}`. - -First, there are *state expressions* that, given a state :math:`\sigma`, compute -some value to be used later in the program itself: :math:`\Sigma \to -\text{Value}`. There are two types of expressions we call *monadic expressions*: -:class:`UniformExpr` and :class:`CategoricalExpr`. They map a state to a -distribution of values: :math:`\Sigma \to \text{Dist}[\Sigma]`. And -*expectations* are also expressed using :data:`Expr`, but they are actually a -mapping of states to *expected values*: :math:`\Sigma \to \mathbb{R}`. - -.. autodata:: Expr -.. autodata:: DistrExpr -.. autoclass:: VarExpr -.. autoclass:: BoolLitExpr -.. autoclass:: NatLitExpr -.. autoclass:: RealLitExpr -.. autoclass:: Unop -.. autoclass:: UnopExpr -.. autoclass:: Binop -.. autoclass:: BinopExpr -.. autoclass:: DUniformExpr -.. autoclass:: CUniformExpr -.. autoclass:: BernoulliExpr -.. autoclass:: GeometricExpr -.. autoclass:: PoissonExpr -.. autoclass:: LogDistExpr -.. autoclass:: BinomialExpr -.. autoclass:: IidSampleExpr -.. autoclass:: CategoricalExpr -.. autoclass:: SubstExpr -.. autoclass:: TickExpr - -Instructions -############ -.. autodata:: Instr -.. autodata:: Query -.. autoclass:: SkipInstr -.. autoclass:: WhileInstr -.. autoclass:: IfInstr -.. autoclass:: AsgnInstr -.. autoclass:: ChoiceInstr -.. autoclass:: LoopInstr -.. autoclass:: TickInstr -.. autoclass:: ObserveInstr -.. autoclass:: ExpectationInstr -.. autoclass:: OptimizationType -.. autoclass:: OptimizationQuery -.. autoclass:: ProbabilityQueryInstr -.. autoclass:: PrintInstr -.. autoclass:: PlotInstr - -Superclasses -############ -These are only used for use with isinstance. -Otherwise use corresponding Union types instead. - -.. autoclass:: TypeClass -.. autoclass:: DeclClass - - .. automethod:: __str__ - -.. autoclass:: ExprClass - - .. automethod:: __str__ - -.. autoclass:: InstrClass - - .. automethod:: __str__ - -.. autoclass:: Node -""" -# Necessary for sphinx to use a union type's name in the docs (instead of always printing the full union type) -from __future__ import annotations - -import copy -import itertools -from abc import ABC, abstractmethod -from decimal import Decimal -from enum import Enum, auto -from fractions import Fraction -from functools import reduce -from textwrap import indent -from typing import Any, Dict, List, Optional, Sequence, Tuple, Union - -import attr - -Var = str - - -@attr.s -class Node(ABC): - """Superclass for all node types in the AST.""" - - -@attr.s -class Bounds: - """ - Bounds for a natural number type. - - The bounds can contain constant expressions, therefore bounds have type :class:`Expr`. - """ - lower: Expr = attr.ib() - upper: Expr = attr.ib() - - def __str__(self) -> str: - return f"[{self.lower}, {self.upper}]" - - -@attr.s -class TypeClass(Node): - """Superclass for all types. See :obj:`Type`.""" - - -@attr.s -class BoolType(TypeClass): - """Boolean type.""" - - -@attr.s -class NatType(TypeClass): - """ - Natural number types with optional bounds. - - Bounds are only preserved for variables. - Values of bounded types are considered as unbounded until they are assigned to a bounded variable. - That is to say, bounds are lost in expressions such as in the example below: - - .. doctest:: - - >>> from .parser import parse_pgcl, parse_expr - >>> from .check import get_type - >>> program = parse_pgcl("nat x [1,5]") - >>> get_type(program, parse_expr("x + 5")) - NatType(bounds=None) - """ - - bounds: Optional[Bounds] = attr.ib() - - -@attr.s -class RealType(TypeClass): - """Real numbers, used for probabilities.""" - - -Type = Union[BoolType, NatType, RealType] -"""Union type for all type objects. See :class:`TypeClass` for use with isinstance.""" - - -class DeclClass(Node): - """Superclass for all declarations. See :obj:`Decl`.""" - @abstractmethod - def __str__(self) -> str: - """ - Convert this declaration to corresponding source code in pGCL. - - .. doctest:: - - >>> str(VarDecl('x', NatType(Bounds(1, 10)))) - 'nat x [1, 10];' - """ - - -@attr.s -class VarDecl(DeclClass): - """A variable declaration with a name and a type.""" - var: Var = attr.ib() - typ: Type = attr.ib() - - def __str__(self) -> str: - if isinstance(self.typ, BoolType): - return f"bool {self.var};" - elif isinstance(self.typ, NatType): - res = f"nat {self.var}" - if self.typ.bounds is not None: - res += " " + str(self.typ.bounds) - return res + ";" - elif isinstance(self.typ, RealType): - return f"real {self.var};" - raise ValueError(f"invalid type: {self.typ}") - - -@attr.s -class ConstDecl(DeclClass): - """A constant declaration with a name and an expression.""" - var: Var = attr.ib() - value: Expr = attr.ib() - - def __str__(self) -> str: - return f"const {self.var} := {self.value};" - -@attr.s -class ParameterDecl(DeclClass): - """ A parameter declaration with a name and a type.""" - var: Var = attr.ib() - typ: Type = attr.ib() - - def __str__(self) -> str: - if isinstance(self.typ, BoolType): - raise SyntaxError("A parameter cannot be of BoolType.") - if isinstance(self.typ, NatType): - res = f"nparam {self.var}" - if self.typ.bounds is not None: - res += " " + str(self.typ.bounds) - return res + ";" - elif isinstance(self.typ, RealType): - return f"rparam {self.var};" - raise ValueError(f"invalid type: {self.typ}") - - -Decl = Union[VarDecl, ConstDecl, ParameterDecl] -"""Union type for all declaration objects. See :class:`DeclClass` for use with isinstance.""" - - -class ExprClass(Node): - """ - Superclass for all expressions. - See :obj:`Expr`. - - All expressions can be transformed into human-readable strings using the `str` operator. - """ - def cast(self) -> Expr: - """Cast to Expr. This is sometimes necessary to satisfy the type checker.""" - return self # type: ignore - - @abstractmethod - def __str__(self) -> str: - """ - Convert this expression to corresponding source code in pGCL. - - .. doctest:: - - >>> from .parser import parse_expr - >>> str(parse_expr("x < 2 & not true")) - '(x < 2) & not true' - """ - - -@attr.s(repr=False) -class VarExpr(ExprClass): - """A variable is an expression.""" - var: Var = attr.ib() - is_parameter: bool = attr.ib(default=False) - - def __str__(self) -> str: - return self.var - - def __repr__(self) -> str: - if self.is_parameter: - return f"ParamExpr({repr(self.var)})" - else: - return f'VarExpr({repr(self.var)})' - - -@attr.s(repr=False) -class BoolLitExpr(ExprClass): - """A bool literal is an expression.""" - value: bool = attr.ib() - - def __str__(self) -> str: - return str(self.value).lower() - - def __repr__(self) -> str: - return f'BoolLitExpr({self.value})' - - -@attr.s(repr=False) -class NatLitExpr(ExprClass): - """A natural number is an expression.""" - value: int = attr.ib() - - def __str__(self) -> str: - return str(self.value) - - def __repr__(self) -> str: - return f'NatLitExpr({self.value})' - - -def _validate_real_lit_value(_object: RealLitExpr, _attribute: Any, - value: Any): - if not isinstance(value, Decimal) and not isinstance(value, Fraction): - raise ValueError( - f"Expected a Decimal or Fraction value, got: {value!r}") - - -def _parse_real_lit_expr( - value: Union[str, Decimal, Fraction]) -> Union[Decimal, Fraction]: - if isinstance(value, str): - if "/" in value: - return Fraction(value) - else: - res = Decimal(value) - assert value == str(res) - return res - return value - - -@attr.s(repr=False, frozen=True) -class RealLitExpr(ExprClass): - """ - A decimal literal (used for probabilities) is an expression. - - It is represented by either a :class:`Decimal` (created from decimal - literals), or by a :class:`Fraction` (created from a fraction of natural numbers). - - Infinity is represented by ``Decimal('Infinity')``. - - .. warning:: - - Note that the :class:`Decimal` representation is not exact under arithmetic operations. - That is fine if it is used just as the representation of a decimal literal. - For calculations, please use :meth:`to_fraction()`. - """ - value: Union[Decimal, - Fraction] = attr.ib(validator=_validate_real_lit_value, - converter=_parse_real_lit_expr) - - @staticmethod - def infinity() -> RealLitExpr: - """ - Create a new infinite value. - - .. doctest:: - - >>> RealLitExpr.infinity().is_infinite() - True - """ - return RealLitExpr(Decimal('Infinity')) - - def is_infinite(self): - """ - Whether this expression represents infinity. - """ - return isinstance(self.value, Decimal) and self.value.is_infinite() - - def to_fraction(self) -> Fraction: - """ - Convert this value to a :class:`Fraction`. - Throws an exception if the value :meth:`is_infinite()`! - - .. doctest:: - - >>> expr = RealLitExpr("0.1") - >>> expr.to_fraction() - Fraction(1, 10) - """ - assert not self.is_infinite() - if isinstance(self.value, Fraction): - return self.value - return Fraction(self.value) - - def __str__(self) -> str: - return str(self.value) - - def __repr__(self) -> str: - return f'RealLitExpr("{str(self.value)}")' - - -class Unop(Enum): - """What unary operator is it?""" - NEG = auto() - IVERSON = auto() - - def __repr__(self) -> str: - # pylint: disable=no-member - return f'Unop.{self._name_}' - - -@attr.s -class UnopExpr(ExprClass): - """A unary operator is an expression.""" - operator: Unop = attr.ib() - expr: Expr = attr.ib() - - def __str__(self) -> str: - if self.operator == Unop.NEG: - return f'not {expr_str_parens(self.expr)}' - elif self.operator == Unop.IVERSON: - return f'[{self.expr}]' - raise Exception("Invalid Unop operator") - - -class Binop(Enum): - """What binary operator is it?""" - OR = auto() - AND = auto() - LEQ = auto() - LE = auto() - GE = auto() - GEQ = auto() - EQ = auto() - PLUS = auto() - MINUS = auto() - TIMES = auto() - POWER = auto() - DIVIDE = auto() - MODULO = auto() - - def is_associative(self) -> bool: - """Is this operator associative?""" - return self in [Binop.OR, Binop.AND, Binop.PLUS, Binop.TIMES] - - def __repr__(self) -> str: - # pylint: disable=no-member - return f'Binop.{self._name_}' - - def __str__(self) -> str: - return ({ - Binop.OR: "||", - Binop.AND: "&", - Binop.LEQ: "<=", - Binop.LE: "<", - Binop.GE: ">", - Binop.GEQ: ">=", - Binop.EQ: "=", - Binop.PLUS: "+", - Binop.MINUS: "-", - Binop.TIMES: "*", - Binop.POWER: "^", - Binop.DIVIDE: "/", - Binop.MODULO: "%", - })[self] - - -@attr.s -class BinopExpr(ExprClass): - """A binary operator is an expression.""" - operator: Binop = attr.ib() - lhs: Expr = attr.ib() - rhs: Expr = attr.ib() - - @staticmethod - def reduce(operator: Binop, - iterable: Sequence[Expr], - default: Optional[Expr] = None) -> Expr: - """ - Builds a :class:`BinopExpr` using :func:`functools.reduce`. - - If the list is empty, ``default`` is returned. - - :raises AssertionError: if list is empty and ``default`` is ``None``. - """ - gen = iter(iterable) - try: - peeked = next(gen) - gen = itertools.chain([peeked], gen) - return reduce(lambda x, y: BinopExpr(operator, x, y), iterable) - except StopIteration: - assert default is not None - return default - - def flatten(self) -> List[Expr]: - """ - Return a list of all recursive operands of the same operator. - This really only makes sense if the operator is associative (see - :meth:`Binop.is_associative`). Throws an error if the operator is not - associative. - - .. doctest:: - - >>> x = VarExpr('x') - >>> times = BinopExpr(Binop.TIMES, x, x) - >>> expr = BinopExpr(Binop.PLUS, BinopExpr(Binop.PLUS, x, times), x) - >>> expr.flatten() - [VarExpr('x'), BinopExpr(operator=Binop.TIMES, lhs=VarExpr('x'), rhs=VarExpr('x')), VarExpr('x')] - """ - assert self.operator.is_associative() - - def flatten_expr(expr: Expr) -> List[Expr]: - if isinstance(expr, BinopExpr) and expr.operator == self.operator: - return flatten_expr(expr.lhs) + flatten_expr(expr.rhs) - else: - return [expr] - - return flatten_expr(self) - - def __str__(self) -> str: - if self.operator == Binop.POWER: - return f'({self.lhs}) {self.operator} ({self.rhs})' - return f'{expr_str_parens(self.lhs)} {self.operator} {expr_str_parens(self.rhs)}' - - -@attr.s -class DUniformExpr(ExprClass): - """ - Chooses a random integer within the (inclusive) interval. - - As *monadic expressions* (see :ref:`expressions`), uniform choice - expressions are only allowed as the right-hand side of an assignment - statement and not somewhere in a nested expression. - """ - start: Expr = attr.ib() - end: Expr = attr.ib() - - def distribution(self) -> List[Tuple[RealLitExpr, NatLitExpr]]: - r""" - Return the distribution of possible values as a list along with - probabilities. For the uniform distribution, all probabilites are equal - to :math:`\frac{1}{\text{end} - \text{start} + 1}`. - """ - if isinstance(self.start, NatLitExpr) and isinstance(self.end, NatLitExpr): - width = self.end.value - self.start.value + 1 - prob = RealLitExpr(Fraction(1, width)) - return [(prob, NatLitExpr(i)) - for i in range(self.start.value, self.end.value + 1)] - else: - raise NotImplementedError("Parameters not implemented yet.") - - def __str__(self) -> str: - return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' - - -def _check_categorical_exprs(_self: CategoricalExpr, _attribute: Any, - value: List[Tuple[Expr, RealLitExpr]]): - probabilities = (prob.to_fraction() for _, prob in value) - if sum(probabilities) != 1: - raise ValueError("Probabilities need to sum up to 1!") - - -@attr.s -class CUniformExpr(ExprClass): - """ - Chooses a random real number within the (inclusive) interval. - - As *monadic expressions* (see :ref:`expressions`), uniform choice - expressions are only allowed as the right-hand side of an assignment - statement and not somewhere in a nested expression. - """ - start: Expr = attr.ib() - end: Expr = attr.ib() - - def __str__(self) -> str: - return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' - - -@attr.s -class BernoulliExpr(ExprClass): - """ - Chooses a random bernoulli distributed integer. - - As *monadic expressions* (see :ref:`expressions`), geometric choice - expressions are only allowed as the right-hand side of an assignment - statement and not somewhere in a nested expression. - """ - param: Expr = attr.ib() - - def __str__(self) -> str: - return f'bernoulli({expr_str_parens(self.param)})' - - -@attr.s -class GeometricExpr(ExprClass): - """ - Chooses a random geometrically distributed integer. - - As *monadic expressions* (see :ref:`expressions`), geometric choice - expressions are only allowed as the right-hand side of an assignment - statement and not somewhere in a nested expression. - """ - param: Expr = attr.ib() - - def __str__(self) -> str: - return f'geometric({expr_str_parens(self.param)})' - - -@attr.s -class PoissonExpr(ExprClass): - """ - Chooses a random poisson distributed integer. - - As *monadic expressions* (see :ref:`expressions`), geometric choice - expressions are only allowed as the right-hand side of an assignment - statement and not somewhere in a nested expression. - """ - param: Expr = attr.ib() - - def __str__(self) -> str: - return f'poisson({expr_str_parens(self.param)})' - - -@attr.s -class LogDistExpr(ExprClass): - """ - Chooses a random logarithmically distributed integer. - """ - param: Expr = attr.ib() - - def __str__(self) -> str: - return f'logdist({expr_str_parens(self.param)})' - - -@attr.s -class BinomialExpr(ExprClass): - """ - Chooses a random logarithmically distributed integer. - - As *monadic expressions* (see :ref:`expressions`), geometric choice - expressions are only allowed as the right-hand side of an assignment - statement and not somewhere in a nested expression. - """ - n: Expr = attr.ib() - p: Expr = attr.ib() - - def __str__(self) -> str: - return f'binomial({expr_str_parens(self.n)}, {expr_str_parens(self.p)})' - - -@attr.s -class IidSampleExpr(ExprClass): - """ Independently sampling from identical distributions""" - sampling_dist: Expr = attr.ib() - variable: VarExpr = attr.ib() - - def __str__(self) -> str: - return f"iid({self.sampling_dist}, {self.variable})" - - -@attr.s -class CategoricalExpr(ExprClass): - """ - Chooses one of a list of expressions to evaluate, where each expression has - some assigned probability. The sum of probabilities must always be exactly one. - - It is represented by a `(expression, probability)` pair. - - As *monadic expressions* (see :ref:`expressions`), categorical choice - expressions are only allowed as the right-hand side of an assignment - statement and not somewhere in a nested expression. - """ - exprs: List[Tuple[Expr, RealLitExpr]] = attr.ib( - validator=_check_categorical_exprs) - - def distribution(self) -> List[Tuple[RealLitExpr, Expr]]: - r""" - Return the distribution of possible values as a list along with - probabilities. - """ - return [(prob, expr) for expr, prob in self.exprs] - - def __str__(self) -> str: - return " + ".join((f"{expr_str_parens(expr)} : {expr_str_parens(prob)}" - for expr, prob in self.exprs)) - - -@attr.s -class SubstExpr(ExprClass): - """ - A substition expression that applies a mapping from variables to expressions - to the target expression. - - An important invariant is that all substitutions must be well-typed, i.e. - assign expressions to variables of the same type. Thus the expression with - the substitutions applied has the same type as the expression before. - - It is not available in the pGCL program language, but can be generated by - program transformations to represent expectations, such as the weakest - preexpectation of a program (see :mod:`probably.pgcl.wp`). - - Substitutions can be applied using the :mod:`probably.pgcl.substitute` - module. - """ - subst: Dict[Var, Expr] = attr.ib() - expr: Expr = attr.ib() - - def __str__(self) -> str: - substs = ", ".join( - (f'{key}/{value}' for key, value in self.subst.items())) - return f'({self.expr})[{substs}]' - - -@attr.s -class TickExpr(ExprClass): - """ - Generated only by the weakest pre-expectation semantics of - :class:`TickInstr`. - """ - expr: Expr = attr.ib() - - def is_zero(self) -> bool: - """Whether this expression represents exactly zero ticks.""" - return self.expr == NatLitExpr(0) - - def __str__(self) -> str: - return f"tick({self.expr})" - - -def expr_str_parens(expr: ExprClass) -> str: - """Wrap parentheses around an expression, but not for simple expressions.""" - if isinstance(expr, - (VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, UnopExpr)): - return str(expr) - else: - return f'({expr})' - - -DistrExpr = Union[DUniformExpr, CUniformExpr, BernoulliExpr, GeometricExpr, PoissonExpr, LogDistExpr, BinomialExpr, - IidSampleExpr] -""" A type combining all sampling expressions""" - - -Expr = Union[VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, UnopExpr, - BinopExpr, CategoricalExpr, SubstExpr, TickExpr, DistrExpr] -"""Union type for all expression objects. See :class:`ExprClass` for use with isinstance.""" - - -class InstrClass(Node): - """Superclass for all instructions. See :obj:`Instr`.""" - def cast(self) -> Instr: - """Cast to Instr. This is sometimes necessary to satisfy the type checker.""" - return self # type: ignore - - @abstractmethod - def __str__(self) -> str: - """ - Convert this instruction to corresponding source code in pGCL. - - .. doctest:: - - >>> print(SkipInstr()) - skip; - >>> print(WhileInstr(BoolLitExpr(True), [SkipInstr()])) - while (true) { - skip; - } - >>> print(IfInstr(BoolLitExpr(False), [SkipInstr()], [])) - if (false) { - skip; - } - """ - - -def _str_block(instrs: List[Instr]) -> str: - if len(instrs) == 0: - return "{ }" - lines = indent("\n".join(map(str, instrs)), " ") - return "{\n" + lines + "\n}" - - -@attr.s -class SkipInstr(InstrClass): - """The skip instruction does nothing.""" - def __str__(self) -> str: - return "skip;" - - -@attr.s -class WhileInstr(InstrClass): - """A while loop with a condition and a body.""" - cond: Expr = attr.ib() - body: List[Instr] = attr.ib() - - def __str__(self) -> str: - return f"while ({self.cond}) {_str_block(self.body)}" - - -@attr.s -class IfInstr(InstrClass): - """A conditional expression with two branches.""" - cond: Expr = attr.ib() - true: List[Instr] = attr.ib() - false: List[Instr] = attr.ib() - - def __str__(self) -> str: - if len(self.false) > 0: - else_str = f" else {_str_block(self.false)}" - else: - else_str = "" - return f"if ({self.cond}) {_str_block(self.true)}{else_str}" - - -@attr.s -class AsgnInstr(InstrClass): - """An assignment instruction with a left- and right-hand side.""" - lhs: Var = attr.ib() - rhs: Expr = attr.ib() - - def __str__(self) -> str: - return f'{self.lhs} := {self.rhs};' - - -@attr.s -class ChoiceInstr(InstrClass): - """A probabilistic choice instruction with a probability expression and two branches.""" - prob: Expr = attr.ib() - lhs: List[Instr] = attr.ib() - rhs: List[Instr] = attr.ib() - - def __str__(self) -> str: - return f"{_str_block(self.lhs)} [{self.prob}] {_str_block(self.rhs)}" - - -@attr.s -class LoopInstr(InstrClass): - """Iterating a block a constant amount of times.""" - iterations: NatLitExpr = attr.ib() - body: List[Instr] = attr.ib() - - def __str__(self) -> str: - return f"loop({self.iterations}){_str_block(self.body)}" - - -@attr.s -class TickInstr(InstrClass): - """ - An instruction that does not modify the program state, but only increases - the runtime by the value of the expression in the current state. Its only - use is its translation to :class:`TickExpr` by weakest pre-expectations. - - The type of ``expr`` must be :class:`NatType`. - """ - expr: Expr = attr.ib() - - def __str__(self) -> str: - return f"tick({self.expr});" - - -@attr.s -class ObserveInstr(InstrClass): - """ - Updates the current distribution according to the observation (forward analysis only). - May result in an error if the observed condition has probability zero. - - The type of ``cond`` must be :class:`BoolType`. - """ - cond: Expr = attr.ib() - - def __str__(self) -> str: - return f"observe({self.cond});" - - -@attr.s -class ExpectationInstr(InstrClass): - """ - Allows for expectation queries inside of a pGCL program. - """ - expr: Expr = attr.ib() - - def __str__(self) -> str: - return f"?Ex[{self.expr}];" - - -class OptimizationType(Enum): - MAXIMIZE = auto() - MINIMIZE = auto() - - -@attr.s -class OptimizationQuery(InstrClass): - expr: Expr = attr.ib() - parameter: Var = attr.ib() - type: OptimizationType = attr.ib() - - def __str__(self) -> str: - return f"?Opt[{self.expr}, {self.parameter}, {'MAX' if self.type == OptimizationType.MAXIMIZE else 'MIN'}];" - - -@attr.s -class ProbabilityQueryInstr(InstrClass): - expr: Expr = attr.ib() - - def __str__(self) -> str: - return f"?Pr[{self.expr}];" - - -@attr.s -class PrintInstr(InstrClass): - def __str__(self) -> str: - return "!Print;" - - -@attr.s -class PlotInstr(InstrClass): - var_1: VarExpr = attr.ib() - var_2: VarExpr = attr.ib(default=None) - prob: RealLitExpr = attr.ib(default=None) - term_count: NatLitExpr = attr.ib(default=None) - - def __str__(self) -> str: - output = str(self.var_1) - if self.var_2: - output += f", {str(self.var_2)}" - if self.prob: - output += f", {str(self.prob)}" - if self.term_count: - output += f", {str(self.term_count)}" - return f"!Plot[{output}]" - - -Query = Union[ProbabilityQueryInstr, ExpectationInstr, PlotInstr, PrintInstr, OptimizationQuery] -"""Union type for all query objects. See :class:`QueryInstr` for use with isinstance.""" - - -Instr = Union[SkipInstr, WhileInstr, IfInstr, AsgnInstr, ChoiceInstr, LoopInstr, - TickInstr, ObserveInstr, Query] -"""Union type for all instruction objects. See :class:`InstrClass` for use with isinstance.""" - - -@attr.s(frozen=True) -class ProgramConfig: - """ - Some compilation options for programs. Frozen after initialization (cannot - be modified). - - At the moment, we only have a flag for the type checker on which types are - allowed as program variables. - """ - - allow_real_vars: bool = attr.ib(default=True) - """ - Whether real numbers are allowed as program values (in computations, or as - variables). - """ - - -@attr.s -class Program: - """ - A pGCL program has a bunch of variables with types, constants with defining expressions, and a list of instructions. - """ - config: ProgramConfig = attr.ib(repr=False) - - declarations: List[Decl] = attr.ib(repr=False) - """The original list of declarations.""" - - variables: Dict[Var, Type] = attr.ib() - """ - A dict of variables to their type. - Only valid if the declarations are well-typed. - """ - - constants: Dict[Var, Expr] = attr.ib() - """ - A dict of constant names to their defining expression. - Only valid if the declarations are well-typed. - """ - - parameters: Dict[Var, Type] = attr.ib() - """ - A dict of parameters to their type. - Only valid if the declarations are well-typed. - """ - - instructions: List[Instr] = attr.ib() - - @staticmethod - def from_parse(config: ProgramConfig, declarations: List[Decl], parameters: Dict[Var, Type], - instructions: List[Instr]) -> Program: - """Create a program from the parser's output.""" - variables: Dict[Var, Type] = {} - constants: Dict[Var, Expr] = {} - - for decl in declarations: - if isinstance(decl, VarDecl): - variables[decl.var] = decl.typ - elif isinstance(decl, ConstDecl): - constants[decl.var] = decl.value - - return Program(config, declarations, variables, constants, parameters, instructions) - - def add_variable(self, var: Var, typ: Type): - """ - Add a new variable declaration to the program's list of declarations and - to the dict of variables. - - :raises AssertionError: if the variable is already declared - """ - for decl in self.declarations: - assert decl.var != var, f"name {var} is already declared in program" - assert var not in self.variables, f"variable {var} is already declared in program" - self.declarations.append(VarDecl(var, typ)) - self.variables[var] = typ - - def to_skeleton(self) -> Program: - """ - Return a (shallow) copy of this program with just the declarations, but - without any instructions. - - .. doctest:: - - >>> from .parser import parse_pgcl - >>> program = parse_pgcl("nat x; nat y; while (x < 2) {}") - >>> program.to_skeleton() - Program(variables={'x': NatType(bounds=None), 'y': NatType(bounds=None)}, constants={}, parameters={}, instructions=[]) - """ - return Program(config=self.config, - declarations=copy.copy(self.declarations), - parameters=copy.copy(self.parameters), - variables=copy.copy(self.variables), - constants=copy.copy(self.constants), - instructions=[]) - - def __str__(self) -> str: - """ - Convert this program to corresponding source code in pGCL. - - .. doctest:: - - >>> from .parser import parse_pgcl - >>> program = parse_pgcl("nat x; nat y; while (x < 2) {}") - >>> print(program) - nat x; - nat y; - while (x < 2) { } - """ - instrs: List[Any] = list(self.declarations) - instrs.extend(self.instructions) - return "\n".join(map(str, instrs)) diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 669e9b0..b4f728e 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -16,7 +16,7 @@ RealType, IfInstr, Instr, NatLitExpr, NatType, Node, Program, SkipInstr, Type, DUniformExpr, Unop, UnopExpr, Var, VarExpr, WhileInstr, ProgramConfig) -from .walk import Walk, walk_expr +from .ast.walk import Walk, walk_expr _T = TypeVar('_T') diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index cd47d5c..d100fde 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -19,13 +19,15 @@ """ import textwrap from decimal import Decimal -from typing import List, Optional, Callable +from typing import List, Optional, Callable, Dict, Tuple, Union +from fractions import Fraction +import attr from lark import Lark, Tree from probably.pgcl.syntax import _has_variable from probably.pgcl.ast import * -from probably.pgcl.walk import Walk, walk_expr +from probably.pgcl.ast.walk import Walk, walk_expr from probably.util.lark_expr_parser import (atom, build_expr_parser, infixl, prefix, infixr) from probably.util.ref import Mut diff --git a/probably/pgcl/simplify.py b/probably/pgcl/simplify.py index 91adce2..003b61f 100644 --- a/probably/pgcl/simplify.py +++ b/probably/pgcl/simplify.py @@ -19,7 +19,7 @@ NatLitExpr, NatType, Program, SubstExpr, TickExpr, Unop, UnopExpr, Var, expr_str_parens) from .check import CheckFail, get_type -from .walk import Walk, walk_expr +from .ast import Walk, walk_expr from .wp import ExpectationTransformer diff --git a/probably/pgcl/substitute.py b/probably/pgcl/substitute.py index b5668d4..4b047d3 100644 --- a/probably/pgcl/substitute.py +++ b/probably/pgcl/substitute.py @@ -93,7 +93,7 @@ from probably.util.ref import Mut from .ast import Expr, ExprClass, Program, SubstExpr, Var, VarExpr -from .walk import (Walk, mut_expr_children, mut_instr_exprs, walk_expr, +from .ast.walk import (Walk, mut_expr_children, mut_instr_exprs, walk_expr, walk_instrs) diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index 8883f60..8bd0f5b 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -96,7 +96,7 @@ from .ast import (AsgnInstr, Binop, BinopExpr, Expr, Instr, Program, Unop, UnopExpr, VarExpr, WhileInstr) from .check import CheckFail -from .walk import Walk, instr_exprs, mut_expr_children, walk_expr, walk_instrs +from .ast.walk import Walk, instr_exprs, mut_expr_children, walk_expr, walk_instrs def check_is_linear_program(program: Program) -> Optional[CheckFail]: diff --git a/probably/pgcl/walk.py b/probably/pgcl/walk.py deleted file mode 100644 index f99bda3..0000000 --- a/probably/pgcl/walk.py +++ /dev/null @@ -1,143 +0,0 @@ -""" ------------- -Walking ASTs ------------- - -Utilities to traverse ("walk") an AST, i.e. visiting each node in the AST. -There are two directions (bottom-up and top-down) which you can select using :class:`Walk`. - -We also have :data:`probably.util.ref.Ref` and :class:`probably.util.ref.Mut` to represent mutable references to values. -These allow a walk of an AST while modifying it. -E.g. constant folding can be implemented as a bottom-up walk where each callback simplifies the current node. - -A simple example with :func:`walk_expr` is below. -The returned iterable contains ``Mut[Expr]`` objects. -Use :attr:`probably.util.ref.Mut.val` to access the current node. - - .. doctest:: - - >>> from probably.util.ref import Mut - >>> expr = Mut.alloc(UnopExpr(Unop.NEG, NatLitExpr(10))) - - >>> [ref.val for ref in walk_expr(Walk.DOWN, expr)] - [UnopExpr(operator=Unop.NEG, expr=NatLitExpr(10)), NatLitExpr(10)] - - >>> [ref.val for ref in walk_expr(Walk.UP, expr)] - [NatLitExpr(10), UnopExpr(operator=Unop.NEG, expr=NatLitExpr(10))] - - -.. rubric:: Why not manual recursion? - -This framework allows easy and flexible traversal of ASTs while also changing direction along the way: Using :class:`probably.util.ref.Mut`, we can modify the AST and then continue traversal with the new AST. -This makes it hard to forget calling a recursive traversal call, which could easily happen if every single traversal was implemented manually. -""" - -from enum import Enum, auto -from typing import Callable, Iterable, TypeVar - -from probably.util.ref import Mut - -from .ast import * - -T = TypeVar("T") - - -class Walk(Enum): - """ - In which direction to go in a traversal: DOWN is a top-down traversal and UP is a bottom-up traversal. - """ - DOWN = auto() - UP = auto() - - def walk(self, get_children: Callable[[T], Iterable[T]], - root: T) -> Iterable[T]: - """ - Walk a tree given by ``get_children`` in the given direction. - """ - if self == Walk.DOWN: - yield root - - for child in get_children(root): - yield from self.walk(get_children, child) - - if self == Walk.UP: - yield root - - -def mut_expr_children(node_ref: Mut[Expr]) -> Iterable[Mut[Expr]]: - """Get refs to all direct children of an expr.""" - node = node_ref.val - for ref in Mut.dict_values(node.__dict__): - if not isinstance(ref.val, ExprClass): - continue - - yield ref - - -def walk_expr(walk: Walk, expr_ref: Mut[Expr]) -> Iterable[Mut[Expr]]: - """Walk an expression.""" - assert isinstance(expr_ref.val, ExprClass) - return walk.walk(mut_expr_children, expr_ref) - - -def _mut_instr_children(node_ref: Mut[Instr]) -> Iterable[Mut[Instr]]: - """ - Get refs to all direct children of an instr, including those in attributes that are lists. - - .. doctest:: - - >>> list(_mut_instr_children(Mut.alloc(ChoiceInstr(VarExpr('x'), [SkipInstr()], [SkipInstr()])))) - [Mut(val=SkipInstr()), Mut(val=SkipInstr())] - """ - node = node_ref.val - for ref in Mut.dict_values(node.__dict__): - for item_ref in Mut.iterate(ref): - if not isinstance(item_ref.val, InstrClass): - continue - - yield item_ref - - -def walk_instrs(walk: Walk, instrs: List[Instr]) -> Iterable[Mut[Instr]]: - """Walk a list of instructions.""" - for instr in Mut.list(instrs): - assert isinstance(instr.val, InstrClass) - yield from walk.walk(_mut_instr_children, instr) - - -def instr_exprs(node: Instr) -> Iterable[Expr]: - """ - Get the expressions that are direct children of this instruction as values. - - .. doctest:: - - >>> from .ast import * - >>> list(instr_exprs(AsgnInstr('x', BoolLitExpr(True)))) - [BoolLitExpr(True)] - """ - for value in node.__dict__.values(): - if isinstance(value, ExprClass): - yield value.cast() - - -def mut_instr_exprs(node: Instr) -> Iterable[Mut[Expr]]: - """ - Get refs to the expressions of an instruction. - - .. doctest:: - - >>> list(mut_instr_exprs(ChoiceInstr(VarExpr('x'), [SkipInstr()], [SkipInstr()]))) - [Mut(val=VarExpr('x'))] - """ - for ref in Mut.dict_values(node.__dict__): - if not isinstance(ref.val, ExprClass): - continue - - yield ref - - -def walk_instr_exprs(walk: Walk, instr: Instr) -> Iterable[Mut[Expr]]: - """Walk all expressions in the instruction.""" - assert isinstance(instr, InstrClass) - for expr_ref in mut_instr_exprs(instr): - yield from walk_expr(walk, expr_ref) diff --git a/probably/pgcl/wp.py b/probably/pgcl/wp.py index 983e082..08bd223 100644 --- a/probably/pgcl/wp.py +++ b/probably/pgcl/wp.py @@ -93,7 +93,7 @@ UnopExpr, Var, VarExpr, WhileInstr) from .substitute import substitute_expr from .syntax import check_is_one_big_loop -from .walk import Walk, walk_expr +from .ast.walk import Walk, walk_expr def loopfree_wp(instr: Union[Instr, Sequence[Instr]], diff --git a/tests/test_operator_precedence.py b/tests/test_operator_precedence.py index 90dd253..2a28c39 100644 --- a/tests/test_operator_precedence.py +++ b/tests/test_operator_precedence.py @@ -1,6 +1,8 @@ from probably.pgcl.parser import parse_pgcl from probably.pgcl.ast import * from pytest import raises +from decimal import Decimal +from fractions import Fraction def test_all_operators(): program = parse_pgcl(""" diff --git a/tests/test_substitution.py b/tests/test_substitution.py index fe92c41..cae02ac 100644 --- a/tests/test_substitution.py +++ b/tests/test_substitution.py @@ -7,7 +7,7 @@ from probably.pgcl.ast import Expr, SubstExpr, Unop, UnopExpr, VarExpr from probably.pgcl.parser import parse_pgcl from probably.pgcl.substitute import substitute_expr -from probably.pgcl.walk import Walk, walk_expr +from probably.pgcl.ast.walk import Walk, walk_expr from probably.pgcl.wp import loopfree_wp from probably.util.ref import Mut From 1bfd89c14365026bddd0816e505e4a7773c8dad8 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 25 May 2022 15:22:00 +0200 Subject: [PATCH 30/67] I forgot to add the new files to git --- probably/pgcl/ast/__init__.py | 14 + probably/pgcl/ast/ast.py | 127 ++++++++ probably/pgcl/ast/declarations.py | 86 +++++ probably/pgcl/ast/expressions.py | 503 ++++++++++++++++++++++++++++++ probably/pgcl/ast/instructions.py | 203 ++++++++++++ probably/pgcl/ast/program.py | 122 ++++++++ probably/pgcl/ast/types.py | 46 +++ probably/pgcl/ast/walk.py | 146 +++++++++ 8 files changed, 1247 insertions(+) create mode 100644 probably/pgcl/ast/__init__.py create mode 100644 probably/pgcl/ast/ast.py create mode 100644 probably/pgcl/ast/declarations.py create mode 100644 probably/pgcl/ast/expressions.py create mode 100644 probably/pgcl/ast/instructions.py create mode 100644 probably/pgcl/ast/program.py create mode 100644 probably/pgcl/ast/types.py create mode 100644 probably/pgcl/ast/walk.py diff --git a/probably/pgcl/ast/__init__.py b/probably/pgcl/ast/__init__.py new file mode 100644 index 0000000..f893f7e --- /dev/null +++ b/probably/pgcl/ast/__init__.py @@ -0,0 +1,14 @@ +Var = str + +# pylint: disable=wrong-import-position +from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl, Bounds +from .expressions import VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, BinopExpr, UnopExpr, \ + SubstExpr, CategoricalExpr, TickExpr, DUniformExpr, CUniformExpr, GeometricExpr, PoissonExpr, LogDistExpr, \ + BinomialExpr, BernoulliExpr, Binop, Unop, Expr, ExprClass, DistrExpr, IidSampleExpr, expr_str_parens +from .instructions import ProbabilityQueryInstr, ExpectationInstr, PlotInstr, SkipInstr, WhileInstr, IfInstr,\ + AsgnInstr, LoopInstr, ChoiceInstr, TickInstr, ObserveInstr, Instr, Query, InstrClass, PrintInstr,\ + OptimizationType, OptimizationQuery +from .types import BoolType, NatType, RealType, Type +from .ast import Node +from .program import Program, ProgramConfig +from .walk import * diff --git a/probably/pgcl/ast/ast.py b/probably/pgcl/ast/ast.py new file mode 100644 index 0000000..07162cb --- /dev/null +++ b/probably/pgcl/ast/ast.py @@ -0,0 +1,127 @@ +r""" +--- +AST +--- + +All data types to represent a pGCL program. + +.. note:: + + For our AST types, most "sum types" have a normal Python superclass (e.g. :class:`TypeClass` for types), but also a Union type (e.g. :data:`Type`). + **Prefer using the Union type, as it allows for exhaustiveness checking by mypy.** + + In some rare cases, it's necessary to tell mypy that an object of a superclass type is actually in the respective union. + Use ``cast`` methods, e.g. :meth:`InstrClass.cast` to go from :class:`InstrClass` to :data:`Instr`. + + Also note that ``isinstance`` checks must be done against the superclasses, because Python's Union does not yet work with ``isinstance``. + +Program +####### +.. autoclass:: Program + + .. automethod:: __str__ + +Types +##### +.. autodata:: Type +.. autoclass:: BoolType +.. autoclass:: NatType +.. autoclass:: Bounds +.. autoclass:: RealType + +Declarations +############ +.. autodata:: Decl +.. autoclass:: VarDecl +.. autoclass:: ConstDecl +.. autoclass:: ParameterDecl + + +.. _expressions: + +Expressions +########### + +In the AST, a bunch of different things that look like program expressions are +lumped together. Formally, let a state :math:`\sigma \in \Sigma` consists of a +bunch of values for each variable, and be represented by a function of type +:math:`\sigma : \text{Var} \to \text{Value}`. + +First, there are *state expressions* that, given a state :math:`\sigma`, compute +some value to be used later in the program itself: :math:`\Sigma \to +\text{Value}`. There are two types of expressions we call *monadic expressions*: +:class:`UniformExpr` and :class:`CategoricalExpr`. They map a state to a +distribution of values: :math:`\Sigma \to \text{Dist}[\Sigma]`. And +*expectations* are also expressed using :data:`Expr`, but they are actually a +mapping of states to *expected values*: :math:`\Sigma \to \mathbb{R}`. + +.. autodata:: Expr +.. autodata:: DistrExpr +.. autoclass:: VarExpr +.. autoclass:: BoolLitExpr +.. autoclass:: NatLitExpr +.. autoclass:: RealLitExpr +.. autoclass:: Unop +.. autoclass:: UnopExpr +.. autoclass:: Binop +.. autoclass:: BinopExpr +.. autoclass:: DUniformExpr +.. autoclass:: CUniformExpr +.. autoclass:: BernoulliExpr +.. autoclass:: GeometricExpr +.. autoclass:: PoissonExpr +.. autoclass:: LogDistExpr +.. autoclass:: BinomialExpr +.. autoclass:: IidSampleExpr +.. autoclass:: CategoricalExpr +.. autoclass:: SubstExpr +.. autoclass:: TickExpr + +Instructions +############ +.. autodata:: Instr +.. autodata:: Query +.. autoclass:: SkipInstr +.. autoclass:: WhileInstr +.. autoclass:: IfInstr +.. autoclass:: AsgnInstr +.. autoclass:: ChoiceInstr +.. autoclass:: LoopInstr +.. autoclass:: TickInstr +.. autoclass:: ObserveInstr +.. autoclass:: ExpectationInstr +.. autoclass:: OptimizationType +.. autoclass:: OptimizationQuery +.. autoclass:: ProbabilityQueryInstr +.. autoclass:: PrintInstr +.. autoclass:: PlotInstr + +Superclasses +############ +These are only used for use with isinstance. +Otherwise use corresponding Union types instead. + +.. autoclass:: TypeClass +.. autoclass:: DeclClass + + .. automethod:: __str__ + +.. autoclass:: ExprClass + + .. automethod:: __str__ + +.. autoclass:: InstrClass + + .. automethod:: __str__ + +.. autoclass:: Node +""" + + +from abc import ABC +import attr + + +@attr.s +class Node(ABC): + """Superclass for all node types in the AST.""" diff --git a/probably/pgcl/ast/declarations.py b/probably/pgcl/ast/declarations.py new file mode 100644 index 0000000..130c523 --- /dev/null +++ b/probably/pgcl/ast/declarations.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +from typing import Union +from abc import abstractmethod +import attr +from .expressions import Expr +from .ast import Node +from . import Var +from .types import Type, BoolType, NatType, RealType + +@attr.s +class Bounds: + """ + Bounds for a natural number type. + + The bounds can contain constant expressions, therefore bounds have type :class:`Expr`. + """ + lower: Expr = attr.ib() + upper: Expr = attr.ib() + + def __str__(self) -> str: + return f"[{self.lower}, {self.upper}]" + +class DeclClass(Node): + """Superclass for all declarations. See :obj:`Decl`.""" + @abstractmethod + def __str__(self) -> str: + """ + Convert this declaration to corresponding source code in pGCL. + + .. doctest:: + + >>> str(VarDecl('x', NatType(Bounds(1, 10)))) + 'nat x [1, 10];' + """ + + +@attr.s +class VarDecl(DeclClass): + """A variable declaration with a name and a type.""" + var: Var = attr.ib() + typ: Type = attr.ib() + + def __str__(self) -> str: + if isinstance(self.typ, BoolType): + return f"bool {self.var};" + elif isinstance(self.typ, NatType): + res = f"nat {self.var}" + if self.typ.bounds is not None: + res += " " + str(self.typ.bounds) + return res + ";" + elif isinstance(self.typ, RealType): + return f"real {self.var};" + raise ValueError(f"invalid type: {self.typ}") + + +@attr.s +class ConstDecl(DeclClass): + """A constant declaration with a name and an expression.""" + var: Var = attr.ib() + value: Expr = attr.ib() + + def __str__(self) -> str: + return f"const {self.var} := {self.value};" + +@attr.s +class ParameterDecl(DeclClass): + """ A parameter declaration with a name and a type.""" + var: Var = attr.ib() + typ: Type = attr.ib() + + def __str__(self) -> str: + if isinstance(self.typ, BoolType): + raise SyntaxError("A parameter cannot be of BoolType.") + if isinstance(self.typ, NatType): + res = f"nparam {self.var}" + if self.typ.bounds is not None: + res += " " + str(self.typ.bounds) + return res + ";" + elif isinstance(self.typ, RealType): + return f"rparam {self.var};" + raise ValueError(f"invalid type: {self.typ}") + + +Decl = Union[VarDecl, ConstDecl, ParameterDecl] +"""Union type for all declaration objects. See :class:`DeclClass` for use with isinstance.""" diff --git a/probably/pgcl/ast/expressions.py b/probably/pgcl/ast/expressions.py new file mode 100644 index 0000000..595384a --- /dev/null +++ b/probably/pgcl/ast/expressions.py @@ -0,0 +1,503 @@ +from __future__ import annotations + +from decimal import Decimal +from typing import Any, Union, Sequence, Optional, List, Tuple, Dict +from fractions import Fraction +from enum import auto, Enum +import itertools +from functools import reduce + +from abc import abstractmethod +import attr +from .ast import Node +from . import Var + +class ExprClass(Node): + """ + Superclass for all expressions. + See :obj:`Expr`. + + All expressions can be transformed into human-readable strings using the `str` operator. + """ + def cast(self) -> Expr: + """Cast to Expr. This is sometimes necessary to satisfy the type checker.""" + return self # type: ignore + + @abstractmethod + def __str__(self) -> str: + """ + Convert this expression to corresponding source code in pGCL. + + .. doctest:: + + >>> from probably.pgcl.parser import parse_expr + >>> str(parse_expr("x < 2 & not true")) + '(x < 2) & not true' + """ + + +@attr.s(repr=False) +class VarExpr(ExprClass): + """A variable is an expression.""" + var: Var = attr.ib() + is_parameter: bool = attr.ib(default=False) + + def __str__(self) -> str: + return self.var + + def __repr__(self) -> str: + if self.is_parameter: + return f"ParamExpr({repr(self.var)})" + else: + return f'VarExpr({repr(self.var)})' + + +@attr.s(repr=False) +class BoolLitExpr(ExprClass): + """A bool literal is an expression.""" + value: bool = attr.ib() + + def __str__(self) -> str: + return str(self.value).lower() + + def __repr__(self) -> str: + return f'BoolLitExpr({self.value})' + + +@attr.s(repr=False) +class NatLitExpr(ExprClass): + """A natural number is an expression.""" + value: int = attr.ib() + + def __str__(self) -> str: + return str(self.value) + + def __repr__(self) -> str: + return f'NatLitExpr({self.value})' + + +def _validate_real_lit_value(_object: RealLitExpr, _attribute: Any, + value: Any): + if not isinstance(value, Decimal) and not isinstance(value, Fraction): + raise ValueError( + f"Expected a Decimal or Fraction value, got: {value!r}") + + +def _parse_real_lit_expr( + value: Union[str, Decimal, Fraction]) -> Union[Decimal, Fraction]: + if isinstance(value, str): + if "/" in value: + return Fraction(value) + else: + res = Decimal(value) + assert value == str(res) + return res + return value + + +@attr.s(repr=False, frozen=True) +class RealLitExpr(ExprClass): + """ + A decimal literal (used for probabilities) is an expression. + + It is represented by either a :class:`Decimal` (created from decimal + literals), or by a :class:`Fraction` (created from a fraction of natural numbers). + + Infinity is represented by ``Decimal('Infinity')``. + + .. warning:: + + Note that the :class:`Decimal` representation is not exact under arithmetic operations. + That is fine if it is used just as the representation of a decimal literal. + For calculations, please use :meth:`to_fraction()`. + """ + value: Union[Decimal, + Fraction] = attr.ib(validator=_validate_real_lit_value, + converter=_parse_real_lit_expr) + + @staticmethod + def infinity() -> RealLitExpr: + """ + Create a new infinite value. + + .. doctest:: + + >>> RealLitExpr.infinity().is_infinite() + True + """ + return RealLitExpr(Decimal('Infinity')) + + def is_infinite(self): + """ + Whether this expression represents infinity. + """ + return isinstance(self.value, Decimal) and self.value.is_infinite() + + def to_fraction(self) -> Fraction: + """ + Convert this value to a :class:`Fraction`. + Throws an exception if the value :meth:`is_infinite()`! + + .. doctest:: + + >>> expr = RealLitExpr("0.1") + >>> expr.to_fraction() + Fraction(1, 10) + """ + assert not self.is_infinite() + if isinstance(self.value, Fraction): + return self.value + return Fraction(self.value) + + def __str__(self) -> str: + return str(self.value) + + def __repr__(self) -> str: + return f'RealLitExpr("{str(self.value)}")' + + +class Unop(Enum): + """What unary operator is it?""" + NEG = auto() + IVERSON = auto() + + def __repr__(self) -> str: + # pylint: disable=no-member + return f'Unop.{self._name_}' + + +@attr.s +class UnopExpr(ExprClass): + """A unary operator is an expression.""" + operator: Unop = attr.ib() + expr: Expr = attr.ib() + + def __str__(self) -> str: + if self.operator == Unop.NEG: + return f'not {expr_str_parens(self.expr)}' + elif self.operator == Unop.IVERSON: + return f'[{self.expr}]' + raise Exception("Invalid Unop operator") + + +class Binop(Enum): + """What binary operator is it?""" + OR = auto() + AND = auto() + LEQ = auto() + LE = auto() + GE = auto() + GEQ = auto() + EQ = auto() + PLUS = auto() + MINUS = auto() + TIMES = auto() + POWER = auto() + DIVIDE = auto() + MODULO = auto() + + def is_associative(self) -> bool: + """Is this operator associative?""" + return self in [Binop.OR, Binop.AND, Binop.PLUS, Binop.TIMES] + + def __repr__(self) -> str: + # pylint: disable=no-member + return f'Binop.{self._name_}' + + def __str__(self) -> str: + return ({ + Binop.OR: "||", + Binop.AND: "&", + Binop.LEQ: "<=", + Binop.LE: "<", + Binop.GE: ">", + Binop.GEQ: ">=", + Binop.EQ: "=", + Binop.PLUS: "+", + Binop.MINUS: "-", + Binop.TIMES: "*", + Binop.POWER: "^", + Binop.DIVIDE: "/", + Binop.MODULO: "%", + })[self] + + +@attr.s +class BinopExpr(ExprClass): + """A binary operator is an expression.""" + operator: Binop = attr.ib() + lhs: Expr = attr.ib() + rhs: Expr = attr.ib() + + @staticmethod + def reduce(operator: Binop, + iterable: Sequence[Expr], + default: Optional[Expr] = None) -> Expr: + """ + Builds a :class:`BinopExpr` using :func:`functools.reduce`. + + If the list is empty, ``default`` is returned. + + :raises AssertionError: if list is empty and ``default`` is ``None``. + """ + gen = iter(iterable) + try: + peeked = next(gen) + gen = itertools.chain([peeked], gen) + return reduce(lambda x, y: BinopExpr(operator, x, y), iterable) + except StopIteration: + assert default is not None + return default + + def flatten(self) -> List[Expr]: + """ + Return a list of all recursive operands of the same operator. + This really only makes sense if the operator is associative (see + :meth:`Binop.is_associative`). Throws an error if the operator is not + associative. + + .. doctest:: + + >>> x = VarExpr('x') + >>> times = BinopExpr(Binop.TIMES, x, x) + >>> expr = BinopExpr(Binop.PLUS, BinopExpr(Binop.PLUS, x, times), x) + >>> expr.flatten() + [VarExpr('x'), BinopExpr(operator=Binop.TIMES, lhs=VarExpr('x'), rhs=VarExpr('x')), VarExpr('x')] + """ + assert self.operator.is_associative() + + def flatten_expr(expr: Expr) -> List[Expr]: + if isinstance(expr, BinopExpr) and expr.operator == self.operator: + return flatten_expr(expr.lhs) + flatten_expr(expr.rhs) + else: + return [expr] + + return flatten_expr(self) + + def __str__(self) -> str: + if self.operator == Binop.POWER: + return f'({self.lhs}) {self.operator} ({self.rhs})' + return f'{expr_str_parens(self.lhs)} {self.operator} {expr_str_parens(self.rhs)}' + + +@attr.s +class DUniformExpr(ExprClass): + """ + Chooses a random integer within the (inclusive) interval. + + As *monadic expressions* (see :ref:`expressions`), uniform choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + start: Expr = attr.ib() + end: Expr = attr.ib() + + def distribution(self) -> List[Tuple[RealLitExpr, NatLitExpr]]: + r""" + Return the distribution of possible values as a list along with + probabilities. For the uniform distribution, all probabilites are equal + to :math:`\frac{1}{\text{end} - \text{start} + 1}`. + """ + if isinstance(self.start, NatLitExpr) and isinstance(self.end, NatLitExpr): + width = self.end.value - self.start.value + 1 + prob = RealLitExpr(Fraction(1, width)) + return [(prob, NatLitExpr(i)) + for i in range(self.start.value, self.end.value + 1)] + else: + raise NotImplementedError("Parameters not implemented yet.") + + def __str__(self) -> str: + return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' + + +def _check_categorical_exprs(_self: CategoricalExpr, _attribute: Any, + value: List[Tuple[Expr, RealLitExpr]]): + probabilities = (prob.to_fraction() for _, prob in value) + if sum(probabilities) != 1: + raise ValueError("Probabilities need to sum up to 1!") + + +@attr.s +class CUniformExpr(ExprClass): + """ + Chooses a random real number within the (inclusive) interval. + + As *monadic expressions* (see :ref:`expressions`), uniform choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + start: Expr = attr.ib() + end: Expr = attr.ib() + + def __str__(self) -> str: + return f'unif({expr_str_parens(self.start)}, {expr_str_parens(self.end)})' + + +@attr.s +class BernoulliExpr(ExprClass): + """ + Chooses a random bernoulli distributed integer. + + As *monadic expressions* (see :ref:`expressions`), geometric choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + param: Expr = attr.ib() + + def __str__(self) -> str: + return f'bernoulli({expr_str_parens(self.param)})' + + +@attr.s +class GeometricExpr(ExprClass): + """ + Chooses a random geometrically distributed integer. + + As *monadic expressions* (see :ref:`expressions`), geometric choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + param: Expr = attr.ib() + + def __str__(self) -> str: + return f'geometric({expr_str_parens(self.param)})' + + +@attr.s +class PoissonExpr(ExprClass): + """ + Chooses a random poisson distributed integer. + + As *monadic expressions* (see :ref:`expressions`), geometric choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + param: Expr = attr.ib() + + def __str__(self) -> str: + return f'poisson({expr_str_parens(self.param)})' + + +@attr.s +class LogDistExpr(ExprClass): + """ + Chooses a random logarithmically distributed integer. + """ + param: Expr = attr.ib() + + def __str__(self) -> str: + return f'logdist({expr_str_parens(self.param)})' + + +@attr.s +class BinomialExpr(ExprClass): + """ + Chooses a random logarithmically distributed integer. + + As *monadic expressions* (see :ref:`expressions`), geometric choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + n: Expr = attr.ib() + p: Expr = attr.ib() + + def __str__(self) -> str: + return f'binomial({expr_str_parens(self.n)}, {expr_str_parens(self.p)})' + + +@attr.s +class IidSampleExpr(ExprClass): + """ Independently sampling from identical distributions""" + sampling_dist: Expr = attr.ib() + variable: VarExpr = attr.ib() + + def __str__(self) -> str: + return f"iid({self.sampling_dist}, {self.variable})" + + +@attr.s +class CategoricalExpr(ExprClass): + """ + Chooses one of a list of expressions to evaluate, where each expression has + some assigned probability. The sum of probabilities must always be exactly one. + + It is represented by a `(expression, probability)` pair. + + As *monadic expressions* (see :ref:`expressions`), categorical choice + expressions are only allowed as the right-hand side of an assignment + statement and not somewhere in a nested expression. + """ + exprs: List[Tuple[Expr, RealLitExpr]] = attr.ib( + validator=_check_categorical_exprs) + + def distribution(self) -> List[Tuple[RealLitExpr, Expr]]: + r""" + Return the distribution of possible values as a list along with + probabilities. + """ + return [(prob, expr) for expr, prob in self.exprs] + + def __str__(self) -> str: + return " + ".join((f"{expr_str_parens(expr)} : {expr_str_parens(prob)}" + for expr, prob in self.exprs)) + + +@attr.s +class SubstExpr(ExprClass): + """ + A substition expression that applies a mapping from variables to expressions + to the target expression. + + An important invariant is that all substitutions must be well-typed, i.e. + assign expressions to variables of the same type. Thus the expression with + the substitutions applied has the same type as the expression before. + + It is not available in the pGCL program language, but can be generated by + program transformations to represent expectations, such as the weakest + preexpectation of a program (see :mod:`probably.pgcl.wp`). + + Substitutions can be applied using the :mod:`probably.pgcl.substitute` + module. + """ + subst: Dict[Var, Expr] = attr.ib() + expr: Expr = attr.ib() + + def __str__(self) -> str: + substs = ", ".join( + (f'{key}/{value}' for key, value in self.subst.items())) + return f'({self.expr})[{substs}]' + + +@attr.s +class TickExpr(ExprClass): + """ + Generated only by the weakest pre-expectation semantics of + :class:`TickInstr`. + """ + expr: Expr = attr.ib() + + def is_zero(self) -> bool: + """Whether this expression represents exactly zero ticks.""" + return self.expr == NatLitExpr(0) + + def __str__(self) -> str: + return f"tick({self.expr})" + + +def expr_str_parens(expr: ExprClass) -> str: + """Wrap parentheses around an expression, but not for simple expressions.""" + if isinstance(expr, + (VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, UnopExpr)): + return str(expr) + else: + return f'({expr})' + + +DistrExpr = Union[DUniformExpr, CUniformExpr, BernoulliExpr, GeometricExpr, PoissonExpr, LogDistExpr, BinomialExpr, + IidSampleExpr] +""" A type combining all sampling expressions""" + + +Expr = Union[VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, UnopExpr, + BinopExpr, CategoricalExpr, SubstExpr, TickExpr, DistrExpr] +"""Union type for all expression objects. See :class:`ExprClass` for use with isinstance.""" diff --git a/probably/pgcl/ast/instructions.py b/probably/pgcl/ast/instructions.py new file mode 100644 index 0000000..da73ecb --- /dev/null +++ b/probably/pgcl/ast/instructions.py @@ -0,0 +1,203 @@ +from __future__ import annotations + +from abc import abstractmethod +from textwrap import indent +from typing import List, Union +from enum import Enum, auto + +import attr +from .expressions import NatLitExpr, VarExpr, RealLitExpr, Expr +from .ast import Node +from . import Var + +class InstrClass(Node): + """Superclass for all instructions. See :obj:`Instr`.""" + def cast(self) -> Instr: + """Cast to Instr. This is sometimes necessary to satisfy the type checker.""" + return self # type: ignore + + @abstractmethod + def __str__(self) -> str: + """ + Convert this instruction to corresponding source code in pGCL. + + .. doctest:: + + >>> print(SkipInstr()) + skip; + >>> from .expressions import BoolLitExpr + >>> print(WhileInstr(BoolLitExpr(True), [SkipInstr()])) + while (true) { + skip; + } + >>> print(IfInstr(BoolLitExpr(False), [SkipInstr()], [])) + if (false) { + skip; + } + """ + + +def _str_block(instrs: List[Instr]) -> str: + if len(instrs) == 0: + return "{ }" + lines = indent("\n".join(map(str, instrs)), " ") + return "{\n" + lines + "\n}" + + +@attr.s +class SkipInstr(InstrClass): + """The skip instruction does nothing.""" + def __str__(self) -> str: + return "skip;" + + +@attr.s +class WhileInstr(InstrClass): + """A while loop with a condition and a body.""" + cond: Expr = attr.ib() + body: List[Instr] = attr.ib() + + def __str__(self) -> str: + return f"while ({self.cond}) {_str_block(self.body)}" + + +@attr.s +class IfInstr(InstrClass): + """A conditional expression with two branches.""" + cond: Expr = attr.ib() + true: List[Instr] = attr.ib() + false: List[Instr] = attr.ib() + + def __str__(self) -> str: + if len(self.false) > 0: + else_str = f" else {_str_block(self.false)}" + else: + else_str = "" + return f"if ({self.cond}) {_str_block(self.true)}{else_str}" + + +@attr.s +class AsgnInstr(InstrClass): + """An assignment instruction with a left- and right-hand side.""" + lhs: Var = attr.ib() + rhs: Expr = attr.ib() + + def __str__(self) -> str: + return f'{self.lhs} := {self.rhs};' + + +@attr.s +class ChoiceInstr(InstrClass): + """A probabilistic choice instruction with a probability expression and two branches.""" + prob: Expr = attr.ib() + lhs: List[Instr] = attr.ib() + rhs: List[Instr] = attr.ib() + + def __str__(self) -> str: + return f"{_str_block(self.lhs)} [{self.prob}] {_str_block(self.rhs)}" + + +@attr.s +class LoopInstr(InstrClass): + """Iterating a block a constant amount of times.""" + iterations: NatLitExpr = attr.ib() + body: List[Instr] = attr.ib() + + def __str__(self) -> str: + return f"loop({self.iterations}){_str_block(self.body)}" + + +@attr.s +class TickInstr(InstrClass): + """ + An instruction that does not modify the program state, but only increases + the runtime by the value of the expression in the current state. Its only + use is its translation to :class:`TickExpr` by weakest pre-expectations. + + The type of ``expr`` must be :class:`NatType`. + """ + expr: Expr = attr.ib() + + def __str__(self) -> str: + return f"tick({self.expr});" + + +@attr.s +class ObserveInstr(InstrClass): + """ + Updates the current distribution according to the observation (forward analysis only). + May result in an error if the observed condition has probability zero. + + The type of ``cond`` must be :class:`BoolType`. + """ + cond: Expr = attr.ib() + + def __str__(self) -> str: + return f"observe({self.cond});" + + +@attr.s +class ExpectationInstr(InstrClass): + """ + Allows for expectation queries inside of a pGCL program. + """ + expr: Expr = attr.ib() + + def __str__(self) -> str: + return f"?Ex[{self.expr}];" + + +class OptimizationType(Enum): + MAXIMIZE = auto() + MINIMIZE = auto() + + +@attr.s +class OptimizationQuery(InstrClass): + expr: Expr = attr.ib() + parameter: Var = attr.ib() + type: OptimizationType = attr.ib() + + def __str__(self) -> str: + return f"?Opt[{self.expr}, {self.parameter}, {'MAX' if self.type == OptimizationType.MAXIMIZE else 'MIN'}];" + + +@attr.s +class ProbabilityQueryInstr(InstrClass): + expr: Expr = attr.ib() + + def __str__(self) -> str: + return f"?Pr[{self.expr}];" + + +@attr.s +class PrintInstr(InstrClass): + def __str__(self) -> str: + return "!Print;" + + +@attr.s +class PlotInstr(InstrClass): + var_1: VarExpr = attr.ib() + var_2: VarExpr = attr.ib(default=None) + prob: RealLitExpr = attr.ib(default=None) + term_count: NatLitExpr = attr.ib(default=None) + + def __str__(self) -> str: + output = str(self.var_1) + if self.var_2: + output += f", {str(self.var_2)}" + if self.prob: + output += f", {str(self.prob)}" + if self.term_count: + output += f", {str(self.term_count)}" + return f"!Plot[{output}]" + + +Query = Union[ProbabilityQueryInstr, ExpectationInstr, PlotInstr, PrintInstr, OptimizationQuery] +"""Union type for all query objects. See :class:`QueryInstr` for use with isinstance.""" + + +Instr = Union[SkipInstr, WhileInstr, IfInstr, AsgnInstr, ChoiceInstr, LoopInstr, + TickInstr, ObserveInstr, Query] +"""Union type for all instruction objects. See :class:`InstrClass` for use with isinstance.""" diff --git a/probably/pgcl/ast/program.py b/probably/pgcl/ast/program.py new file mode 100644 index 0000000..1a224cf --- /dev/null +++ b/probably/pgcl/ast/program.py @@ -0,0 +1,122 @@ +from __future__ import annotations + +from typing import List, Dict, Any +import copy + +import attr +from . import Var +from .types import Type +from .declarations import Decl, VarDecl, ConstDecl +from .expressions import Expr +from .instructions import Instr + +@attr.s(frozen=True) +class ProgramConfig: + """ + Some compilation options for programs. Frozen after initialization (cannot + be modified). + + At the moment, we only have a flag for the type checker on which types are + allowed as program variables. + """ + + allow_real_vars: bool = attr.ib(default=True) + """ + Whether real numbers are allowed as program values (in computations, or as + variables). + """ + + +@attr.s +class Program: + """ + A pGCL program has a bunch of variables with types, constants with defining expressions, and a list of instructions. + """ + config: ProgramConfig = attr.ib(repr=False) + + declarations: List[Decl] = attr.ib(repr=False) + """The original list of declarations.""" + + variables: Dict[Var, Type] = attr.ib() + """ + A dict of variables to their type. + Only valid if the declarations are well-typed. + """ + + constants: Dict[Var, Expr] = attr.ib() + """ + A dict of constant names to their defining expression. + Only valid if the declarations are well-typed. + """ + + parameters: Dict[Var, Type] = attr.ib() + """ + A dict of parameters to their type. + Only valid if the declarations are well-typed. + """ + + instructions: List[Instr] = attr.ib() + + @staticmethod + def from_parse(config: ProgramConfig, declarations: List[Decl], parameters: Dict[Var, Type], + instructions: List[Instr]) -> Program: + """Create a program from the parser's output.""" + variables: Dict[Var, Type] = {} + constants: Dict[Var, Expr] = {} + + for decl in declarations: + if isinstance(decl, VarDecl): + variables[decl.var] = decl.typ + elif isinstance(decl, ConstDecl): + constants[decl.var] = decl.value + + return Program(config, declarations, variables, constants, parameters, instructions) + + def add_variable(self, var: Var, typ: Type): + """ + Add a new variable declaration to the program's list of declarations and + to the dict of variables. + + :raises AssertionError: if the variable is already declared + """ + for decl in self.declarations: + assert decl.var != var, f"name {var} is already declared in program" + assert var not in self.variables, f"variable {var} is already declared in program" + self.declarations.append(VarDecl(var, typ)) + self.variables[var] = typ + + def to_skeleton(self) -> Program: + """ + Return a (shallow) copy of this program with just the declarations, but + without any instructions. + + .. doctest:: + + >>> from probably.pgcl.parser import parse_pgcl + >>> program = parse_pgcl("nat x; nat y; while (x < 2) {}") + >>> program.to_skeleton() + Program(variables={'x': NatType(bounds=None), 'y': NatType(bounds=None)}, constants={}, parameters={}, instructions=[]) + """ + return Program(config=self.config, + declarations=copy.copy(self.declarations), + parameters=copy.copy(self.parameters), + variables=copy.copy(self.variables), + constants=copy.copy(self.constants), + instructions=[]) + + def __str__(self) -> str: + """ + Convert this program to corresponding source code in pGCL. + + .. doctest:: + + >>> from probably.pgcl.parser import parse_pgcl + >>> program = parse_pgcl("nat x; nat y; while (x < 2) {}") + >>> print(program) + nat x; + nat y; + while (x < 2) { } + """ + instrs: List[Any] = list(self.declarations) + instrs.extend(self.instructions) + return "\n".join(map(str, instrs)) diff --git a/probably/pgcl/ast/types.py b/probably/pgcl/ast/types.py new file mode 100644 index 0000000..07cf987 --- /dev/null +++ b/probably/pgcl/ast/types.py @@ -0,0 +1,46 @@ +from __future__ import annotations + +from typing import Optional, Union +import attr + +from probably.pgcl.ast import declarations +from .ast import Node + +@attr.s +class TypeClass(Node): + """Superclass for all types. See :obj:`Type`.""" + + +@attr.s +class BoolType(TypeClass): + """Boolean type.""" + + +@attr.s +class NatType(TypeClass): + """ + Natural number types with optional bounds. + + Bounds are only preserved for variables. + Values of bounded types are considered as unbounded until they are assigned to a bounded variable. + That is to say, bounds are lost in expressions such as in the example below: + + .. doctest:: + + >>> from probably.pgcl.parser import parse_pgcl, parse_expr + >>> from probably.pgcl.check import get_type + >>> program = parse_pgcl("nat x [1,5]") + >>> get_type(program, parse_expr("x + 5")) + NatType(bounds=None) + """ + + bounds: Optional[declarations.Bounds] = attr.ib() + + +@attr.s +class RealType(TypeClass): + """Real numbers, used for probabilities.""" + + +Type = Union[BoolType, NatType, RealType] +"""Union type for all type objects. See :class:`TypeClass` for use with isinstance.""" diff --git a/probably/pgcl/ast/walk.py b/probably/pgcl/ast/walk.py new file mode 100644 index 0000000..72c3b05 --- /dev/null +++ b/probably/pgcl/ast/walk.py @@ -0,0 +1,146 @@ +""" +------------ +Walking ASTs +------------ + +Utilities to traverse ("walk") an AST, i.e. visiting each node in the AST. +There are two directions (bottom-up and top-down) which you can select using :class:`Walk`. + +We also have :data:`probably.util.ref.Ref` and :class:`probably.util.ref.Mut` to represent mutable references to values. +These allow a walk of an AST while modifying it. +E.g. constant folding can be implemented as a bottom-up walk where each callback simplifies the current node. + +A simple example with :func:`walk_expr` is below. +The returned iterable contains ``Mut[Expr]`` objects. +Use :attr:`probably.util.ref.Mut.val` to access the current node. + + .. doctest:: + + >>> from probably.util.ref import Mut + >>> from . import * + >>> expr = Mut.alloc(UnopExpr(Unop.NEG, NatLitExpr(10))) + + >>> [ref.val for ref in walk_expr(Walk.DOWN, expr)] + [UnopExpr(operator=Unop.NEG, expr=NatLitExpr(10)), NatLitExpr(10)] + + >>> [ref.val for ref in walk_expr(Walk.UP, expr)] + [NatLitExpr(10), UnopExpr(operator=Unop.NEG, expr=NatLitExpr(10))] + + +.. rubric:: Why not manual recursion? + +This framework allows easy and flexible traversal of ASTs while also changing direction along the way: Using :class:`probably.util.ref.Mut`, we can modify the AST and then continue traversal with the new AST. +This makes it hard to forget calling a recursive traversal call, which could easily happen if every single traversal was implemented manually. +""" + +from enum import Enum, auto +from typing import Callable, Iterable, TypeVar, List + +from probably.util.ref import Mut + +from . import Expr, ExprClass, Instr, InstrClass + +T = TypeVar("T") + + +class Walk(Enum): + """ + In which direction to go in a traversal: DOWN is a top-down traversal and UP is a bottom-up traversal. + """ + DOWN = auto() + UP = auto() + + def walk(self, get_children: Callable[[T], Iterable[T]], + root: T) -> Iterable[T]: + """ + Walk a tree given by ``get_children`` in the given direction. + """ + if self == Walk.DOWN: + yield root + + for child in get_children(root): + yield from self.walk(get_children, child) + + if self == Walk.UP: + yield root + + +def mut_expr_children(node_ref: Mut[Expr]) -> Iterable[Mut[Expr]]: + """Get refs to all direct children of an expr.""" + node = node_ref.val + for ref in Mut.dict_values(node.__dict__): + if not isinstance(ref.val, ExprClass): + continue + + yield ref + + +def walk_expr(walk: Walk, expr_ref: Mut[Expr]) -> Iterable[Mut[Expr]]: + """Walk an expression.""" + assert isinstance(expr_ref.val, ExprClass) + return walk.walk(mut_expr_children, expr_ref) + + +def _mut_instr_children(node_ref: Mut[Instr]) -> Iterable[Mut[Instr]]: + """ + Get refs to all direct children of an instr, including those in attributes that are lists. + + .. doctest:: + + >>> from . import * + >>> list(_mut_instr_children(Mut.alloc(ChoiceInstr(VarExpr('x'), [SkipInstr()], [SkipInstr()])))) + [Mut(val=SkipInstr()), Mut(val=SkipInstr())] + """ + node = node_ref.val + for ref in Mut.dict_values(node.__dict__): + for item_ref in Mut.iterate(ref): + if not isinstance(item_ref.val, InstrClass): + continue + + yield item_ref + + +def walk_instrs(walk: Walk, instrs: List[Instr]) -> Iterable[Mut[Instr]]: + """Walk a list of instructions.""" + for instr in Mut.list(instrs): + assert isinstance(instr.val, InstrClass) + yield from walk.walk(_mut_instr_children, instr) + + +def instr_exprs(node: Instr) -> Iterable[Expr]: + """ + Get the expressions that are direct children of this instruction as values. + + .. doctest:: + + >>> from . import * + >>> list(instr_exprs(AsgnInstr('x', BoolLitExpr(True)))) + [BoolLitExpr(True)] + """ + for value in node.__dict__.values(): + if isinstance(value, ExprClass): + yield value.cast() + + +def mut_instr_exprs(node: Instr) -> Iterable[Mut[Expr]]: + """ + Get refs to the expressions of an instruction. + + .. doctest:: + + >>> from . import * + >>> list(mut_instr_exprs(ChoiceInstr(VarExpr('x'), [SkipInstr()], [SkipInstr()]))) + [Mut(val=VarExpr('x'))] + """ + for ref in Mut.dict_values(node.__dict__): + if not isinstance(ref.val, ExprClass): + continue + + yield ref + + +def walk_instr_exprs(walk: Walk, instr: Instr) -> Iterable[Mut[Expr]]: + """Walk all expressions in the instruction.""" + assert isinstance(instr, InstrClass) + for expr_ref in mut_instr_exprs(instr): + yield from walk_expr(walk, expr_ref) From 9fd02578a72a21f0e4b68215162c7457307edf49 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 25 May 2022 15:26:30 +0200 Subject: [PATCH 31/67] Move documentation of ast module to __init__.py --- probably/pgcl/ast/__init__.py | 119 +++++++++++++++++++++++++++++++++ probably/pgcl/ast/ast.py | 120 ---------------------------------- 2 files changed, 119 insertions(+), 120 deletions(-) diff --git a/probably/pgcl/ast/__init__.py b/probably/pgcl/ast/__init__.py index f893f7e..29a1b1a 100644 --- a/probably/pgcl/ast/__init__.py +++ b/probably/pgcl/ast/__init__.py @@ -1,3 +1,122 @@ +r""" +--- +AST +--- + +All data types to represent a pGCL program. + +.. note:: + + For our AST types, most "sum types" have a normal Python superclass (e.g. :class:`TypeClass` for types), but also a Union type (e.g. :data:`Type`). + **Prefer using the Union type, as it allows for exhaustiveness checking by mypy.** + + In some rare cases, it's necessary to tell mypy that an object of a superclass type is actually in the respective union. + Use ``cast`` methods, e.g. :meth:`InstrClass.cast` to go from :class:`InstrClass` to :data:`Instr`. + + Also note that ``isinstance`` checks must be done against the superclasses, because Python's Union does not yet work with ``isinstance``. + +Program +####### +.. autoclass:: Program + + .. automethod:: __str__ + +Types +##### +.. autodata:: Type +.. autoclass:: BoolType +.. autoclass:: NatType +.. autoclass:: Bounds +.. autoclass:: RealType + +Declarations +############ +.. autodata:: Decl +.. autoclass:: VarDecl +.. autoclass:: ConstDecl +.. autoclass:: ParameterDecl + + +.. _expressions: + +Expressions +########### + +In the AST, a bunch of different things that look like program expressions are +lumped together. Formally, let a state :math:`\sigma \in \Sigma` consists of a +bunch of values for each variable, and be represented by a function of type +:math:`\sigma : \text{Var} \to \text{Value}`. + +First, there are *state expressions* that, given a state :math:`\sigma`, compute +some value to be used later in the program itself: :math:`\Sigma \to +\text{Value}`. There are two types of expressions we call *monadic expressions*: +:class:`UniformExpr` and :class:`CategoricalExpr`. They map a state to a +distribution of values: :math:`\Sigma \to \text{Dist}[\Sigma]`. And +*expectations* are also expressed using :data:`Expr`, but they are actually a +mapping of states to *expected values*: :math:`\Sigma \to \mathbb{R}`. + +.. autodata:: Expr +.. autodata:: DistrExpr +.. autoclass:: VarExpr +.. autoclass:: BoolLitExpr +.. autoclass:: NatLitExpr +.. autoclass:: RealLitExpr +.. autoclass:: Unop +.. autoclass:: UnopExpr +.. autoclass:: Binop +.. autoclass:: BinopExpr +.. autoclass:: DUniformExpr +.. autoclass:: CUniformExpr +.. autoclass:: BernoulliExpr +.. autoclass:: GeometricExpr +.. autoclass:: PoissonExpr +.. autoclass:: LogDistExpr +.. autoclass:: BinomialExpr +.. autoclass:: IidSampleExpr +.. autoclass:: CategoricalExpr +.. autoclass:: SubstExpr +.. autoclass:: TickExpr + +Instructions +############ +.. autodata:: Instr +.. autodata:: Query +.. autoclass:: SkipInstr +.. autoclass:: WhileInstr +.. autoclass:: IfInstr +.. autoclass:: AsgnInstr +.. autoclass:: ChoiceInstr +.. autoclass:: LoopInstr +.. autoclass:: TickInstr +.. autoclass:: ObserveInstr +.. autoclass:: ExpectationInstr +.. autoclass:: OptimizationType +.. autoclass:: OptimizationQuery +.. autoclass:: ProbabilityQueryInstr +.. autoclass:: PrintInstr +.. autoclass:: PlotInstr + +Superclasses +############ +These are only used for use with isinstance. +Otherwise use corresponding Union types instead. + +.. autoclass:: TypeClass +.. autoclass:: DeclClass + + .. automethod:: __str__ + +.. autoclass:: ExprClass + + .. automethod:: __str__ + +.. autoclass:: InstrClass + + .. automethod:: __str__ + +.. autoclass:: Node +""" + Var = str # pylint: disable=wrong-import-position diff --git a/probably/pgcl/ast/ast.py b/probably/pgcl/ast/ast.py index 07162cb..efb8ac5 100644 --- a/probably/pgcl/ast/ast.py +++ b/probably/pgcl/ast/ast.py @@ -1,123 +1,3 @@ -r""" ---- -AST ---- - -All data types to represent a pGCL program. - -.. note:: - - For our AST types, most "sum types" have a normal Python superclass (e.g. :class:`TypeClass` for types), but also a Union type (e.g. :data:`Type`). - **Prefer using the Union type, as it allows for exhaustiveness checking by mypy.** - - In some rare cases, it's necessary to tell mypy that an object of a superclass type is actually in the respective union. - Use ``cast`` methods, e.g. :meth:`InstrClass.cast` to go from :class:`InstrClass` to :data:`Instr`. - - Also note that ``isinstance`` checks must be done against the superclasses, because Python's Union does not yet work with ``isinstance``. - -Program -####### -.. autoclass:: Program - - .. automethod:: __str__ - -Types -##### -.. autodata:: Type -.. autoclass:: BoolType -.. autoclass:: NatType -.. autoclass:: Bounds -.. autoclass:: RealType - -Declarations -############ -.. autodata:: Decl -.. autoclass:: VarDecl -.. autoclass:: ConstDecl -.. autoclass:: ParameterDecl - - -.. _expressions: - -Expressions -########### - -In the AST, a bunch of different things that look like program expressions are -lumped together. Formally, let a state :math:`\sigma \in \Sigma` consists of a -bunch of values for each variable, and be represented by a function of type -:math:`\sigma : \text{Var} \to \text{Value}`. - -First, there are *state expressions* that, given a state :math:`\sigma`, compute -some value to be used later in the program itself: :math:`\Sigma \to -\text{Value}`. There are two types of expressions we call *monadic expressions*: -:class:`UniformExpr` and :class:`CategoricalExpr`. They map a state to a -distribution of values: :math:`\Sigma \to \text{Dist}[\Sigma]`. And -*expectations* are also expressed using :data:`Expr`, but they are actually a -mapping of states to *expected values*: :math:`\Sigma \to \mathbb{R}`. - -.. autodata:: Expr -.. autodata:: DistrExpr -.. autoclass:: VarExpr -.. autoclass:: BoolLitExpr -.. autoclass:: NatLitExpr -.. autoclass:: RealLitExpr -.. autoclass:: Unop -.. autoclass:: UnopExpr -.. autoclass:: Binop -.. autoclass:: BinopExpr -.. autoclass:: DUniformExpr -.. autoclass:: CUniformExpr -.. autoclass:: BernoulliExpr -.. autoclass:: GeometricExpr -.. autoclass:: PoissonExpr -.. autoclass:: LogDistExpr -.. autoclass:: BinomialExpr -.. autoclass:: IidSampleExpr -.. autoclass:: CategoricalExpr -.. autoclass:: SubstExpr -.. autoclass:: TickExpr - -Instructions -############ -.. autodata:: Instr -.. autodata:: Query -.. autoclass:: SkipInstr -.. autoclass:: WhileInstr -.. autoclass:: IfInstr -.. autoclass:: AsgnInstr -.. autoclass:: ChoiceInstr -.. autoclass:: LoopInstr -.. autoclass:: TickInstr -.. autoclass:: ObserveInstr -.. autoclass:: ExpectationInstr -.. autoclass:: OptimizationType -.. autoclass:: OptimizationQuery -.. autoclass:: ProbabilityQueryInstr -.. autoclass:: PrintInstr -.. autoclass:: PlotInstr - -Superclasses -############ -These are only used for use with isinstance. -Otherwise use corresponding Union types instead. - -.. autoclass:: TypeClass -.. autoclass:: DeclClass - - .. automethod:: __str__ - -.. autoclass:: ExprClass - - .. automethod:: __str__ - -.. autoclass:: InstrClass - - .. automethod:: __str__ - -.. autoclass:: Node -""" - - from abc import ABC import attr From 8557c91fd83dba884a48eda9c254714e1d44e479 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 25 May 2022 16:44:24 +0200 Subject: [PATCH 32/67] Fix pylint cyclic import warnings --- probably/pgcl/ast/__init__.py | 2 +- probably/pgcl/ast/declarations.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/probably/pgcl/ast/__init__.py b/probably/pgcl/ast/__init__.py index 29a1b1a..bd7e2e4 100644 --- a/probably/pgcl/ast/__init__.py +++ b/probably/pgcl/ast/__init__.py @@ -119,7 +119,7 @@ Var = str -# pylint: disable=wrong-import-position +# pylint: disable=wrong-import-position, cyclic-import from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl, Bounds from .expressions import VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, BinopExpr, UnopExpr, \ SubstExpr, CategoricalExpr, TickExpr, DUniformExpr, CUniformExpr, GeometricExpr, PoissonExpr, LogDistExpr, \ diff --git a/probably/pgcl/ast/declarations.py b/probably/pgcl/ast/declarations.py index 130c523..6fecb7e 100644 --- a/probably/pgcl/ast/declarations.py +++ b/probably/pgcl/ast/declarations.py @@ -6,6 +6,8 @@ from .expressions import Expr from .ast import Node from . import Var +# pylint: disable = cyclic-import +# this is not actually a problem, as the types module only accesses Bounds, which doesn't access types from .types import Type, BoolType, NatType, RealType @attr.s From e300fd39f9e74f5f5e2a6d963524e45af2ccc74a Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 25 May 2022 17:18:46 +0200 Subject: [PATCH 33/67] Fix mypy errors --- mypy.ini | 3 +++ probably/pgcl/parser.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/mypy.ini b/mypy.ini index beab497..b104ea2 100644 --- a/mypy.ini +++ b/mypy.ini @@ -14,3 +14,6 @@ ignore_missing_imports = True [mypy-networkx.*] ignore_missing_imports = True + +[mypy-click.*] +ignore_missing_imports = True diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index d100fde..d14103c 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -383,6 +383,7 @@ def _parse_instr(t: Tree) -> Instr: elif t.data == 'observe': return ObserveInstr(_parse_expr(_child_tree(t, 0))) elif t.data == 'loop': + assert isinstance(t.children[0], str) return LoopInstr(NatLitExpr(value=int(t.children[0])), _parse_instrs(_child_tree(t, 1))) else: raise Exception(f'invalid AST: {t.data}') @@ -423,25 +424,32 @@ def _parse_query(t: Tree): lit = _parse_literal(_child_tree(t, 2)) if isinstance(lit, BoolLitExpr): raise SyntaxError("Plot instructions cannot handle boolean literals as arguments") + assert isinstance(t.children[2], Tree) if t.children[2].data in ('real', 'infinity'): + assert isinstance(lit, RealLitExpr) return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), VarExpr(_parse_var(_child_tree(t, 1))), prob=lit) else: + assert isinstance(lit, NatLitExpr) return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), VarExpr(_parse_var(_child_tree(t, 1))), term_count=lit) elif len(t.children) == 2: + assert isinstance(t.children[1], Tree) if t.children[1].data == 'real': lit = _parse_literal(_child_tree(t, 1)) + assert isinstance(lit, RealLitExpr) return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), prob=lit) elif t.children[1].data == 'nat': lit = _parse_literal(_child_tree(t, 1)) + assert isinstance(lit, NatLitExpr) return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), term_count=lit) elif t.children[1].data == 'infinity': lit = _parse_literal(_child_tree(t, 1)) + assert isinstance(lit, RealLitExpr) return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), prob=lit) elif t.children[1].data in ('true', 'false'): From b22519b1e56f15402f8cef42f4b59ede89c3f20f Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 25 May 2022 17:22:41 +0200 Subject: [PATCH 34/67] Update mypy to newer version The old version didn't seem to work correctly --- poetry.lock | 187 +++++++++++++++++++++---------------------------- pyproject.toml | 2 +- 2 files changed, 80 insertions(+), 109 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1bcb029..d90db25 100644 --- a/poetry.lock +++ b/poetry.lock @@ -97,7 +97,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.3.3" +version = "6.4" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -116,7 +116,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*" [[package]] name = "dill" -version = "0.3.5" +version = "0.3.5.1" description = "serialize all of python" category = "dev" optional = false @@ -214,7 +214,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.11.3" +version = "4.11.4" description = "Read metadata from Python packages" category = "main" optional = false @@ -298,19 +298,21 @@ python-versions = ">=3.5" [[package]] name = "mypy" -version = "0.770" +version = "0.960" description = "Optional static typing for Python" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] -mypy-extensions = ">=0.4.3,<0.5.0" -typed-ast = ">=1.4.0,<1.5.0" -typing-extensions = ">=3.7.4" +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" [package.extras] dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] [[package]] name = "mypy-extensions" @@ -723,14 +725,6 @@ category = "dev" optional = false python-versions = ">=3.7" -[[package]] -name = "typed-ast" -version = "1.4.3" -description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "typing-extensions" version = "4.2.0" @@ -791,7 +785,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "9337904f77d899f6a04bb64f056eacfaa0c88aa89073275e4ec32a2baef50bf1" +content-hash = "494760bc8dc286c4874c5f7cb58354d7dfc9fdc89b1da56e2862bba6c4c7c92f" [metadata.files] alabaster = [ @@ -835,55 +829,55 @@ colorama = [ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ - {file = "coverage-6.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df32ee0f4935a101e4b9a5f07b617d884a531ed5666671ff6ac66d2e8e8246d8"}, - {file = "coverage-6.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75b5dbffc334e0beb4f6c503fb95e6d422770fd2d1b40a64898ea26d6c02742d"}, - {file = "coverage-6.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:114944e6061b68a801c5da5427b9173a0dd9d32cd5fcc18a13de90352843737d"}, - {file = "coverage-6.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab88a01cd180b5640ccc9c47232e31924d5f9967ab7edd7e5c91c68eee47a69"}, - {file = "coverage-6.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad8f9068f5972a46d50fe5f32c09d6ee11da69c560fcb1b4c3baea246ca4109b"}, - {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4cd696aa712e6cd16898d63cf66139dc70d998f8121ab558f0e1936396dbc579"}, - {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c1a9942e282cc9d3ed522cd3e3cab081149b27ea3bda72d6f61f84eaf88c1a63"}, - {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c06455121a089252b5943ea682187a4e0a5cf0a3fb980eb8e7ce394b144430a9"}, - {file = "coverage-6.3.3-cp310-cp310-win32.whl", hash = "sha256:cb5311d6ccbd22578c80028c5e292a7ab9adb91bd62c1982087fad75abe2e63d"}, - {file = "coverage-6.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:6d4a6f30f611e657495cc81a07ff7aa8cd949144e7667c5d3e680d73ba7a70e4"}, - {file = "coverage-6.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:79bf405432428e989cad7b8bc60581963238f7645ae8a404f5dce90236cc0293"}, - {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:338c417613f15596af9eb7a39353b60abec9d8ce1080aedba5ecee6a5d85f8d3"}, - {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db094a6a4ae6329ed322a8973f83630b12715654c197dd392410400a5bfa1a73"}, - {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1414e8b124611bf4df8d77215bd32cba6e3425da8ce9c1f1046149615e3a9a31"}, - {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:93b16b08f94c92cab88073ffd185070cdcb29f1b98df8b28e6649145b7f2c90d"}, - {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fbc86ae8cc129c801e7baaafe3addf3c8d49c9c1597c44bdf2d78139707c3c62"}, - {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b5ba058610e8289a07db2a57bce45a1793ec0d3d11db28c047aae2aa1a832572"}, - {file = "coverage-6.3.3-cp37-cp37m-win32.whl", hash = "sha256:8329635c0781927a2c6ae068461e19674c564e05b86736ab8eb29c420ee7dc20"}, - {file = "coverage-6.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:e5af1feee71099ae2e3b086ec04f57f9950e1be9ecf6c420696fea7977b84738"}, - {file = "coverage-6.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e814a4a5a1d95223b08cdb0f4f57029e8eab22ffdbae2f97107aeef28554517e"}, - {file = "coverage-6.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:61f4fbf3633cb0713437291b8848634ea97f89c7e849c2be17a665611e433f53"}, - {file = "coverage-6.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3401b0d2ed9f726fadbfa35102e00d1b3547b73772a1de5508ef3bdbcb36afe7"}, - {file = "coverage-6.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8586b177b4407f988731eb7f41967415b2197f35e2a6ee1a9b9b561f6323c8e9"}, - {file = "coverage-6.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:892e7fe32191960da559a14536768a62e83e87bbb867e1b9c643e7e0fbce2579"}, - {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:afb03f981fadb5aed1ac6e3dd34f0488e1a0875623d557b6fad09b97a942b38a"}, - {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cbe91bc84be4e5ef0b1480d15c7b18e29c73bdfa33e07d3725da7d18e1b0aff2"}, - {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:91502bf27cbd5c83c95cfea291ef387469f2387508645602e1ca0fd8a4ba7548"}, - {file = "coverage-6.3.3-cp38-cp38-win32.whl", hash = "sha256:c488db059848702aff30aa1d90ef87928d4e72e4f00717343800546fdbff0a94"}, - {file = "coverage-6.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6534fcdfb5c503affb6b1130db7b5bfc8a0f77fa34880146f7a5c117987d0"}, - {file = "coverage-6.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc692c9ee18f0dd3214843779ba6b275ee4bb9b9a5745ba64265bce911aefd1a"}, - {file = "coverage-6.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:462105283de203df8de58a68c1bb4ba2a8a164097c2379f664fa81d6baf94b81"}, - {file = "coverage-6.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc972d829ad5ef4d4c5fcabd2bbe2add84ce8236f64ba1c0c72185da3a273130"}, - {file = "coverage-6.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:06f54765cdbce99901871d50fe9f41d58213f18e98b170a30ca34f47de7dd5e8"}, - {file = "coverage-6.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7835f76a081787f0ca62a53504361b3869840a1620049b56d803a8cb3a9eeea3"}, - {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6f5fee77ec3384b934797f1873758f796dfb4f167e1296dc00f8b2e023ce6ee9"}, - {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:baa8be8aba3dd1e976e68677be68a960a633a6d44c325757aefaa4d66175050f"}, - {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4d06380e777dd6b35ee936f333d55b53dc4a8271036ff884c909cf6e94be8b6c"}, - {file = "coverage-6.3.3-cp39-cp39-win32.whl", hash = "sha256:f8cabc5fd0091976ab7b020f5708335033e422de25e20ddf9416bdce2b7e07d8"}, - {file = "coverage-6.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c9441d57b0963cf8340268ad62fc83de61f1613034b79c2b1053046af0c5284"}, - {file = "coverage-6.3.3-pp36.pp37.pp38-none-any.whl", hash = "sha256:d522f1dc49127eab0bfbba4e90fa068ecff0899bbf61bf4065c790ddd6c177fe"}, - {file = "coverage-6.3.3.tar.gz", hash = "sha256:2781c43bffbbec2b8867376d4d61916f5e9c4cc168232528562a61d1b4b01879"}, + {file = "coverage-6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50ed480b798febce113709846b11f5d5ed1e529c88d8ae92f707806c50297abf"}, + {file = "coverage-6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:26f8f92699756cb7af2b30720de0c5bb8d028e923a95b6d0c891088025a1ac8f"}, + {file = "coverage-6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60c2147921da7f4d2d04f570e1838db32b95c5509d248f3fe6417e91437eaf41"}, + {file = "coverage-6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:750e13834b597eeb8ae6e72aa58d1d831b96beec5ad1d04479ae3772373a8088"}, + {file = "coverage-6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af5b9ee0fc146e907aa0f5fb858c3b3da9199d78b7bb2c9973d95550bd40f701"}, + {file = "coverage-6.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a022394996419142b33a0cf7274cb444c01d2bb123727c4bb0b9acabcb515dea"}, + {file = "coverage-6.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5a78cf2c43b13aa6b56003707c5203f28585944c277c1f3f109c7b041b16bd39"}, + {file = "coverage-6.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9229d074e097f21dfe0643d9d0140ee7433814b3f0fc3706b4abffd1e3038632"}, + {file = "coverage-6.4-cp310-cp310-win32.whl", hash = "sha256:fb45fe08e1abc64eb836d187b20a59172053999823f7f6ef4f18a819c44ba16f"}, + {file = "coverage-6.4-cp310-cp310-win_amd64.whl", hash = "sha256:3cfd07c5889ddb96a401449109a8b97a165be9d67077df6802f59708bfb07720"}, + {file = "coverage-6.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:03014a74023abaf5a591eeeaf1ac66a73d54eba178ff4cb1fa0c0a44aae70383"}, + {file = "coverage-6.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c82f2cd69c71698152e943f4a5a6b83a3ab1db73b88f6e769fabc86074c3b08"}, + {file = "coverage-6.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b546cf2b1974ddc2cb222a109b37c6ed1778b9be7e6b0c0bc0cf0438d9e45a6"}, + {file = "coverage-6.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc173f1ce9ffb16b299f51c9ce53f66a62f4d975abe5640e976904066f3c835d"}, + {file = "coverage-6.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c53ad261dfc8695062fc8811ac7c162bd6096a05a19f26097f411bdf5747aee7"}, + {file = "coverage-6.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:eef5292b60b6de753d6e7f2d128d5841c7915fb1e3321c3a1fe6acfe76c38052"}, + {file = "coverage-6.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:543e172ce4c0de533fa892034cce260467b213c0ea8e39da2f65f9a477425211"}, + {file = "coverage-6.4-cp37-cp37m-win32.whl", hash = "sha256:00c8544510f3c98476bbd58201ac2b150ffbcce46a8c3e4fb89ebf01998f806a"}, + {file = "coverage-6.4-cp37-cp37m-win_amd64.whl", hash = "sha256:b84ab65444dcc68d761e95d4d70f3cfd347ceca5a029f2ffec37d4f124f61311"}, + {file = "coverage-6.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d548edacbf16a8276af13063a2b0669d58bbcfca7c55a255f84aac2870786a61"}, + {file = "coverage-6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:033ebec282793bd9eb988d0271c211e58442c31077976c19c442e24d827d356f"}, + {file = "coverage-6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:742fb8b43835078dd7496c3c25a1ec8d15351df49fb0037bffb4754291ef30ce"}, + {file = "coverage-6.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55fae115ef9f67934e9f1103c9ba826b4c690e4c5bcf94482b8b2398311bf9c"}, + {file = "coverage-6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd698341626f3c77784858427bad0cdd54a713115b423d22ac83a28303d1d95"}, + {file = "coverage-6.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:62d382f7d77eeeaff14b30516b17bcbe80f645f5cf02bb755baac376591c653c"}, + {file = "coverage-6.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:016d7f5cf1c8c84f533a3c1f8f36126fbe00b2ec0ccca47cc5731c3723d327c6"}, + {file = "coverage-6.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:69432946f154c6add0e9ede03cc43b96e2ef2733110a77444823c053b1ff5166"}, + {file = "coverage-6.4-cp38-cp38-win32.whl", hash = "sha256:83bd142cdec5e4a5c4ca1d4ff6fa807d28460f9db919f9f6a31babaaa8b88426"}, + {file = "coverage-6.4-cp38-cp38-win_amd64.whl", hash = "sha256:4002f9e8c1f286e986fe96ec58742b93484195defc01d5cc7809b8f7acb5ece3"}, + {file = "coverage-6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e4f52c272fdc82e7c65ff3f17a7179bc5f710ebc8ce8a5cadac81215e8326740"}, + {file = "coverage-6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b5578efe4038be02d76c344007b13119b2b20acd009a88dde8adec2de4f630b5"}, + {file = "coverage-6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8099ea680201c2221f8468c372198ceba9338a5fec0e940111962b03b3f716a"}, + {file = "coverage-6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a00441f5ea4504f5abbc047589d09e0dc33eb447dc45a1a527c8b74bfdd32c65"}, + {file = "coverage-6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e76bd16f0e31bc2b07e0fb1379551fcd40daf8cdf7e24f31a29e442878a827c"}, + {file = "coverage-6.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8d2e80dd3438e93b19e1223a9850fa65425e77f2607a364b6fd134fcd52dc9df"}, + {file = "coverage-6.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:341e9c2008c481c5c72d0e0dbf64980a4b2238631a7f9780b0fe2e95755fb018"}, + {file = "coverage-6.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:21e6686a95025927775ac501e74f5940cdf6fe052292f3a3f7349b0abae6d00f"}, + {file = "coverage-6.4-cp39-cp39-win32.whl", hash = "sha256:968ed5407f9460bd5a591cefd1388cc00a8f5099de9e76234655ae48cfdbe2c3"}, + {file = "coverage-6.4-cp39-cp39-win_amd64.whl", hash = "sha256:e35217031e4b534b09f9b9a5841b9344a30a6357627761d4218818b865d45055"}, + {file = "coverage-6.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:e637ae0b7b481905358624ef2e81d7fb0b1af55f5ff99f9ba05442a444b11e45"}, + {file = "coverage-6.4.tar.gz", hash = "sha256:727dafd7f67a6e1cad808dc884bd9c5a2f6ef1f8f6d2f22b37b96cb0080d4f49"}, ] decorator = [ {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, ] dill = [ - {file = "dill-0.3.5-py2.py3-none-any.whl", hash = "sha256:6eb4bb70a98509e69204e621942c4306580d5bf2229f450f04fcf2efca3908e5"}, - {file = "dill-0.3.5.tar.gz", hash = "sha256:3a11d19c15d409296a2ee714b1dbd5efb733a329f0d89c0e58aad6154ab6f2f5"}, + {file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"}, + {file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"}, ] docutils = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, @@ -914,8 +908,8 @@ imagesize = [ {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, - {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, + {file = "importlib_metadata-4.11.4-py3-none-any.whl", hash = "sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"}, + {file = "importlib_metadata-4.11.4.tar.gz", hash = "sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700"}, ] isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, @@ -1018,20 +1012,29 @@ more-itertools = [ {file = "more_itertools-8.13.0-py3-none-any.whl", hash = "sha256:c5122bffc5f104d37c1626b8615b511f3427aa5389b94d61e5ef8236bfbc3ddb"}, ] mypy = [ - {file = "mypy-0.770-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:a34b577cdf6313bf24755f7a0e3f3c326d5c1f4fe7422d1d06498eb25ad0c600"}, - {file = "mypy-0.770-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:86c857510a9b7c3104cf4cde1568f4921762c8f9842e987bc03ed4f160925754"}, - {file = "mypy-0.770-cp35-cp35m-win_amd64.whl", hash = "sha256:a8ffcd53cb5dfc131850851cc09f1c44689c2812d0beb954d8138d4f5fc17f65"}, - {file = "mypy-0.770-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:7687f6455ec3ed7649d1ae574136835a4272b65b3ddcf01ab8704ac65616c5ce"}, - {file = "mypy-0.770-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3beff56b453b6ef94ecb2996bea101a08f1f8a9771d3cbf4988a61e4d9973761"}, - {file = "mypy-0.770-cp36-cp36m-win_amd64.whl", hash = "sha256:15b948e1302682e3682f11f50208b726a246ab4e6c1b39f9264a8796bb416aa2"}, - {file = "mypy-0.770-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:b90928f2d9eb2f33162405f32dde9f6dcead63a0971ca8a1b50eb4ca3e35ceb8"}, - {file = "mypy-0.770-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c56ffe22faa2e51054c5f7a3bc70a370939c2ed4de308c690e7949230c995913"}, - {file = "mypy-0.770-cp37-cp37m-win_amd64.whl", hash = "sha256:8dfb69fbf9f3aeed18afffb15e319ca7f8da9642336348ddd6cab2713ddcf8f9"}, - {file = "mypy-0.770-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:219a3116ecd015f8dca7b5d2c366c973509dfb9a8fc97ef044a36e3da66144a1"}, - {file = "mypy-0.770-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7ec45a70d40ede1ec7ad7f95b3c94c9cf4c186a32f6bacb1795b60abd2f9ef27"}, - {file = "mypy-0.770-cp38-cp38-win_amd64.whl", hash = "sha256:f91c7ae919bbc3f96cd5e5b2e786b2b108343d1d7972ea130f7de27fdd547cf3"}, - {file = "mypy-0.770-py3-none-any.whl", hash = "sha256:3b1fc683fb204c6b4403a1ef23f0b1fac8e4477091585e0c8c54cbdf7d7bb164"}, - {file = "mypy-0.770.tar.gz", hash = "sha256:8a627507ef9b307b46a1fea9513d5c98680ba09591253082b4c48697ba05a4ae"}, + {file = "mypy-0.960-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3a3e525cd76c2c4f90f1449fd034ba21fcca68050ff7c8397bb7dd25dd8b8248"}, + {file = "mypy-0.960-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7a76dc4f91e92db119b1be293892df8379b08fd31795bb44e0ff84256d34c251"}, + {file = "mypy-0.960-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffdad80a92c100d1b0fe3d3cf1a4724136029a29afe8566404c0146747114382"}, + {file = "mypy-0.960-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7d390248ec07fa344b9f365e6ed9d205bd0205e485c555bed37c4235c868e9d5"}, + {file = "mypy-0.960-cp310-cp310-win_amd64.whl", hash = "sha256:925aa84369a07846b7f3b8556ccade1f371aa554f2bd4fb31cb97a24b73b036e"}, + {file = "mypy-0.960-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:239d6b2242d6c7f5822163ee082ef7a28ee02e7ac86c35593ef923796826a385"}, + {file = "mypy-0.960-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f1ba54d440d4feee49d8768ea952137316d454b15301c44403db3f2cb51af024"}, + {file = "mypy-0.960-cp36-cp36m-win_amd64.whl", hash = "sha256:cb7752b24528c118a7403ee955b6a578bfcf5879d5ee91790667c8ea511d2085"}, + {file = "mypy-0.960-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:826a2917c275e2ee05b7c7b736c1e6549a35b7ea5a198ca457f8c2ebea2cbecf"}, + {file = "mypy-0.960-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3eabcbd2525f295da322dff8175258f3fc4c3eb53f6d1929644ef4d99b92e72d"}, + {file = "mypy-0.960-cp37-cp37m-win_amd64.whl", hash = "sha256:f47322796c412271f5aea48381a528a613f33e0a115452d03ae35d673e6064f8"}, + {file = "mypy-0.960-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2c7f8bb9619290836a4e167e2ef1f2cf14d70e0bc36c04441e41487456561409"}, + {file = "mypy-0.960-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbfb873cf2b8d8c3c513367febde932e061a5f73f762896826ba06391d932b2a"}, + {file = "mypy-0.960-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc537885891382e08129d9862553b3d00d4be3eb15b8cae9e2466452f52b0117"}, + {file = "mypy-0.960-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:481f98c6b24383188c928f33dd2f0776690807e12e9989dd0419edd5c74aa53b"}, + {file = "mypy-0.960-cp38-cp38-win_amd64.whl", hash = "sha256:29dc94d9215c3eb80ac3c2ad29d0c22628accfb060348fd23d73abe3ace6c10d"}, + {file = "mypy-0.960-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:33d53a232bb79057f33332dbbb6393e68acbcb776d2f571ba4b1d50a2c8ba873"}, + {file = "mypy-0.960-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d645e9e7f7a5da3ec3bbcc314ebb9bb22c7ce39e70367830eb3c08d0140b9ce"}, + {file = "mypy-0.960-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:85cf2b14d32b61db24ade8ac9ae7691bdfc572a403e3cb8537da936e74713275"}, + {file = "mypy-0.960-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a85a20b43fa69efc0b955eba1db435e2ffecb1ca695fe359768e0503b91ea89f"}, + {file = "mypy-0.960-cp39-cp39-win_amd64.whl", hash = "sha256:0ebfb3f414204b98c06791af37a3a96772203da60636e2897408517fcfeee7a8"}, + {file = "mypy-0.960-py3-none-any.whl", hash = "sha256:bfd4f6536bd384c27c392a8b8f790fd0ed5c0cf2f63fc2fed7bce56751d53026"}, + {file = "mypy-0.960.tar.gz", hash = "sha256:d4fccf04c1acf750babd74252e0f2db6bd2ac3aa8fe960797d9f3ef41cf2bfd4"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -1162,38 +1165,6 @@ tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -typed-ast = [ - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, - {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, - {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, - {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, - {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, - {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, - {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, - {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, - {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, - {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, - {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, - {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, - {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, - {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, - {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, - {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, -] typing-extensions = [ {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, diff --git a/pyproject.toml b/pyproject.toml index 9965aad..dff2f2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ networkx = "~2.5" [tool.poetry.dev-dependencies] pytest = "^4.6" pylint = "^2.5.2" -mypy = "^0.770" +mypy = "^0.960" yapf = "^0.30.0" sphinx = "^4.0" sphinx-autodoc-typehints = "^1.18" From 9189730abbfce172aea6006db9e3f89bf6d74f40 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 25 May 2022 17:33:01 +0200 Subject: [PATCH 35/67] Move Bounds class to types file --- probably/pgcl/ast/__init__.py | 4 ++-- probably/pgcl/ast/declarations.py | 15 +-------------- probably/pgcl/ast/types.py | 19 +++++++++++++++++-- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/probably/pgcl/ast/__init__.py b/probably/pgcl/ast/__init__.py index bd7e2e4..432a38c 100644 --- a/probably/pgcl/ast/__init__.py +++ b/probably/pgcl/ast/__init__.py @@ -120,14 +120,14 @@ Var = str # pylint: disable=wrong-import-position, cyclic-import -from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl, Bounds +from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl from .expressions import VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, BinopExpr, UnopExpr, \ SubstExpr, CategoricalExpr, TickExpr, DUniformExpr, CUniformExpr, GeometricExpr, PoissonExpr, LogDistExpr, \ BinomialExpr, BernoulliExpr, Binop, Unop, Expr, ExprClass, DistrExpr, IidSampleExpr, expr_str_parens from .instructions import ProbabilityQueryInstr, ExpectationInstr, PlotInstr, SkipInstr, WhileInstr, IfInstr,\ AsgnInstr, LoopInstr, ChoiceInstr, TickInstr, ObserveInstr, Instr, Query, InstrClass, PrintInstr,\ OptimizationType, OptimizationQuery -from .types import BoolType, NatType, RealType, Type +from .types import BoolType, NatType, RealType, Type, Bounds from .ast import Node from .program import Program, ProgramConfig from .walk import * diff --git a/probably/pgcl/ast/declarations.py b/probably/pgcl/ast/declarations.py index 6fecb7e..b6a2d5b 100644 --- a/probably/pgcl/ast/declarations.py +++ b/probably/pgcl/ast/declarations.py @@ -6,22 +6,8 @@ from .expressions import Expr from .ast import Node from . import Var -# pylint: disable = cyclic-import -# this is not actually a problem, as the types module only accesses Bounds, which doesn't access types from .types import Type, BoolType, NatType, RealType -@attr.s -class Bounds: - """ - Bounds for a natural number type. - - The bounds can contain constant expressions, therefore bounds have type :class:`Expr`. - """ - lower: Expr = attr.ib() - upper: Expr = attr.ib() - - def __str__(self) -> str: - return f"[{self.lower}, {self.upper}]" class DeclClass(Node): """Superclass for all declarations. See :obj:`Decl`.""" @@ -32,6 +18,7 @@ def __str__(self) -> str: .. doctest:: + >>> from .types import Bounds >>> str(VarDecl('x', NatType(Bounds(1, 10)))) 'nat x [1, 10];' """ diff --git a/probably/pgcl/ast/types.py b/probably/pgcl/ast/types.py index 07cf987..4550a83 100644 --- a/probably/pgcl/ast/types.py +++ b/probably/pgcl/ast/types.py @@ -3,8 +3,23 @@ from typing import Optional, Union import attr -from probably.pgcl.ast import declarations from .ast import Node +from .expressions import Expr + + +@attr.s +class Bounds: + """ + Bounds for a natural number type. + + The bounds can contain constant expressions, therefore bounds have type :class:`Expr`. + """ + lower: Expr = attr.ib() + upper: Expr = attr.ib() + + def __str__(self) -> str: + return f"[{self.lower}, {self.upper}]" + @attr.s class TypeClass(Node): @@ -34,7 +49,7 @@ class NatType(TypeClass): NatType(bounds=None) """ - bounds: Optional[declarations.Bounds] = attr.ib() + bounds: Optional[Bounds] = attr.ib() @attr.s From 6ec6e8a9dafa045d513dbf0eb2b9242dda5ed87e Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 27 May 2022 11:24:55 +0200 Subject: [PATCH 36/67] Move unused import to doctest --- probably/pgcl/check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index b4f728e..4136a9d 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -10,12 +10,11 @@ from probably.util.ref import Mut -#pylint: disable=unused-import from .ast import (AsgnInstr, Binop, BinopExpr, BoolLitExpr, BoolType, CategoricalExpr, ChoiceInstr, Decl, Expr, RealLitExpr, RealType, IfInstr, Instr, NatLitExpr, NatType, Node, Program, SkipInstr, Type, DUniformExpr, Unop, UnopExpr, Var, - VarExpr, WhileInstr, ProgramConfig) + VarExpr, WhileInstr) from .ast.walk import Walk, walk_expr _T = TypeVar('_T') @@ -375,6 +374,7 @@ def check_expression(program, expr: Expr) -> Optional[CheckFail]: .. doctest:: + >>> from .ast import ProgramConfig >>> program = Program(ProgramConfig(), list(), dict(), dict(), dict(), list()) >>> check_expression(program, RealLitExpr("1.0")) CheckFail(location=..., message='A program expression may not return a probability.') From 5bdf1113bc510a53150e835c1cb029d6664dd6a8 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 27 May 2022 14:27:10 +0200 Subject: [PATCH 37/67] Merge typechecker from forward --- probably/pgcl/check.py | 146 ++++++++++++++++++++++++++++++++++++++--- probably/util/color.py | 19 ++++++ 2 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 probably/util/color.py diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 4136a9d..6a48dfe 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -4,17 +4,21 @@ ------------- """ -from typing import Dict, Iterable, List, Optional, TypeVar, Union +from typing import Dict, Iterable, List, Optional, TypeVar, Union, get_args, Tuple import attr +from probably.util.color import Style from probably.util.ref import Mut from .ast import (AsgnInstr, Binop, BinopExpr, BoolLitExpr, BoolType, CategoricalExpr, ChoiceInstr, Decl, Expr, RealLitExpr, RealType, IfInstr, Instr, NatLitExpr, NatType, Node, Program, SkipInstr, Type, DUniformExpr, Unop, UnopExpr, Var, - VarExpr, WhileInstr) + VarExpr, WhileInstr, VarDecl, ObserveInstr, ProbabilityQueryInstr, + ExpectationInstr, PrintInstr, OptimizationQuery, PlotInstr, + LoopInstr, CUniformExpr, GeometricExpr, BernoulliExpr,PoissonExpr, + LogDistExpr, BinomialExpr, IidSampleExpr, DistrExpr) from .ast.walk import Walk, walk_expr _T = TypeVar('_T') @@ -91,6 +95,11 @@ def get_type(program: Program, if variable_type is not None: return variable_type + # maybe a parameter? + parameter_type = program.parameters.get(expr.var) + if parameter_type is not None: + return parameter_type + # it must be a constant constant_type = program.constants.get(expr.var) if constant_type is None: @@ -146,8 +155,8 @@ def get_type(program: Program, return CheckFail.expected_numeric_got(expr.lhs, lhs_typ) if check and expr.operator in [ - Binop.LEQ, Binop.LE, Binop.EQ, Binop.PLUS, Binop.MINUS, - Binop.TIMES + Binop.LEQ, Binop.LE, Binop.GEQ, Binop.GE, Binop.EQ, Binop.PLUS, Binop.MINUS, + Binop.TIMES, Binop.MODULO, Binop.POWER ]: rhs_typ = get_type(program, expr.rhs, check=check) if isinstance(rhs_typ, CheckFail): @@ -159,18 +168,18 @@ def get_type(program: Program, return CheckFail.expected_type_got(expr, lhs_typ, rhs_typ) # binops that take numeric operands and return a boolean - if expr.operator in [Binop.LEQ, Binop.LE, Binop.EQ]: + if expr.operator in [Binop.LEQ, Binop.LE, Binop.EQ, Binop.GEQ, Binop.GE]: return BoolType() # binops that take numeric operands and return a numeric value - if expr.operator in [Binop.PLUS, Binop.MINUS, Binop.TIMES]: + if expr.operator in [Binop.PLUS, Binop.MINUS, Binop.TIMES, Binop.MODULO, Binop.POWER]: # intentionally lose the bounds on NatType (see NatType documentation) if isinstance(lhs_typ, NatType) and lhs_typ.bounds is not None: return NatType(bounds=None) return lhs_typ - if isinstance(expr, DUniformExpr): - return NatType(bounds=None) + if isinstance(expr, get_args(DistrExpr)): + return _get_distribution_type(program, expr, check) if isinstance(expr, CategoricalExpr): first_expr = expr.exprs[0][0] @@ -189,6 +198,52 @@ def get_type(program: Program, raise Exception("unreachable") +def _check_distribution_arguments(prog: Program, expected_type: Type, *parameters: Tuple[Type, Expr]): + for expected_param_type, param_expr in parameters: + param_type = get_type(prog, param_expr) + if isinstance(param_type, CheckFail): + return CheckFail + elif not is_compatible(expected_param_type, param_type): + return CheckFail.expected_type_got(param_expr, expected_param_type, param_type) + return expected_type + + +def _get_distribution_type(prog: Program, expr: Expr, check: bool = True) -> Union[Type, CheckFail]: + assert isinstance(expr, get_args(DistrExpr)), f"Expression must be a distribution expression, was {type(expr)}." + + if isinstance(expr, DUniformExpr): + return _check_distribution_arguments(prog, NatType(bounds=None), (NatType(bounds=None), expr.start), + (NatType(bounds=None), expr.end) + ) + elif isinstance(expr, CUniformExpr): + raise NotImplementedError("Currently continuous distributions are not supported.") + + elif isinstance(expr, GeometricExpr): + return _check_distribution_arguments(prog, NatType(bounds=None), (RealType(), expr.param)) + + elif isinstance(expr, BernoulliExpr): + return _check_distribution_arguments(prog, NatType(bounds=None), (RealType(), expr.param)) + + elif isinstance(expr, PoissonExpr): + return _check_distribution_arguments(prog, NatType(bounds=None), (NatType(bounds=None), expr.param)) + + elif isinstance(expr, LogDistExpr): + return _check_distribution_arguments(prog, NatType(bounds=None), (RealType(), expr.param)) + + elif isinstance(expr, BinomialExpr): + return _check_distribution_arguments(prog, NatType(bounds=None), (NatType(bounds=None), expr.n), + (RealType(), expr.p) + ) + if isinstance(expr, IidSampleExpr): + if isinstance(expr.sampling_dist, get_args(DistrExpr)): + return _get_distribution_type(prog, expr.sampling_dist, check) + else: + print(Style.OKRED + "Type Checking is not accurate anymore." + Style.RESET) + return check_expression(prog, expr.sampling_dist) + + raise Exception("unreachable") + + def is_compatible(lhs: Type, rhs: Type) -> bool: """ Check if the right-hand side type is compatible with the left-hand side type. @@ -260,7 +315,8 @@ def _check_constant_declarations(program: Program) -> Optional[CheckFail]: def _check_declaration_list(program: Program) -> Optional[CheckFail]: """ - Check that all variables/constants are defined at most once. + Check that all variables/constants are defined at most once and that real + variables are only declared if they are allowed in the config. .. doctest:: @@ -274,6 +330,12 @@ def _check_declaration_list(program: Program) -> Optional[CheckFail]: if declared.get(decl.var) is not None: return CheckFail(decl, "Already declared variable/constant before.") + if not program.config.allow_real_vars: + if isinstance(decl, VarDecl) and isinstance(decl.typ, RealType): + return CheckFail( + decl, + "Real number variables are not allowed by the program config." + ) declared[decl.var] = decl return None @@ -288,6 +350,7 @@ def _check_instrs(program: Program, return None +# pylint: disable = too-many-statements def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: """ Check a single instruction for type-safety. @@ -353,8 +416,73 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: return CheckFail.expected_type_got(instr.prob, RealType(), prob_type) return _check_instrs(program, instr.lhs, instr.rhs) + if isinstance(instr, ObserveInstr): + cond_type = get_type(program, instr.cond) + if isinstance(cond_type, CheckFail): + return cond_type + if not is_compatible(BoolType(), cond_type): + return CheckFail.expected_type_got(instr.cond, BoolType(), + cond_type) + return None + + if isinstance(instr, ProbabilityQueryInstr): + cond_type = get_type(program, instr.expr) + if isinstance(cond_type, CheckFail): + return cond_type + if not (is_compatible(BoolType(), cond_type) or is_compatible(NatType(None), cond_type)): + return CheckFail.expected_type_got(instr.expr, BoolType(), + cond_type) + return None + + if isinstance(instr, ExpectationInstr): + expr_type = get_type(program, instr.expr, check=True) + if isinstance(expr_type, CheckFail): + return expr_type + return None + + if isinstance(instr, PrintInstr): + return None + + if isinstance(instr, OptimizationQuery): + expr_type = get_type(program, instr.expr, check=True) + if isinstance(expr_type, CheckFail): + return expr_type + return None + + if isinstance(instr, PlotInstr): + var_1_type = get_type(program, instr.var_1, check=True) + if isinstance(var_1_type, CheckFail): + return var_1_type + if instr.var_2: + var_2_type = get_type(program, instr.var_2, check=True) + if isinstance(var_2_type, CheckFail): + return var_2_type + if instr.prob: + prob_type = get_type(program, instr.prob, check=True) + if isinstance(prob_type, CheckFail): + return prob_type + if not is_compatible(RealType(), prob_type): + return CheckFail.expected_type_got(instr.prob, RealType(), + prob_type) + if instr.term_count: + int_type = get_type(program, instr.term_count, check=True) + if isinstance(int_type, CheckFail): + return int_type + if not is_compatible(NatType(bounds=None), int_type): + return CheckFail.expected_type_got(instr.term_count, NatType(None), + int_type) + return None + if isinstance(instr, LoopInstr): + int_type = get_type(program, instr.iterations, check=True) + if isinstance(int_type, CheckFail): + return int_type + if not is_compatible(NatType(bounds=None), int_type): + return CheckFail.expected_type_got(instr.iterations, NatType(None), + int_type) + return _check_instrs(program, instr.body) raise Exception("unreachable") +# pylint: enable = too-many-statements def check_program(program: Program) -> Optional[CheckFail]: diff --git a/probably/util/color.py b/probably/util/color.py new file mode 100644 index 0000000..01b9a84 --- /dev/null +++ b/probably/util/color.py @@ -0,0 +1,19 @@ + +class Style: + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + UNDERLINE = '\033[4m' + OKWHITE = '\033[97m' + OKCYAN = '\033[96m' + OKMAGENTA = '\033[95m' + OKBLUE = '\033[94m' + OKYELLOW = '\033[93m' + OKGREEN = '\033[92m' + OKRED = '\033[91m' + RESET = '\033[0m' From 3e25603d4cf6fe2db508aaa8a1037cb14a3a2b18 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 27 May 2022 15:42:13 +0200 Subject: [PATCH 38/67] Add tests for some of the typechecking --- probably/pgcl/check.py | 1 + tests/test_typechecking.py | 119 +++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 tests/test_typechecking.py diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 6a48dfe..fd82cb7 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -416,6 +416,7 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: return CheckFail.expected_type_got(instr.prob, RealType(), prob_type) return _check_instrs(program, instr.lhs, instr.rhs) + if isinstance(instr, ObserveInstr): cond_type = get_type(program, instr.cond) if isinstance(cond_type, CheckFail): diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py new file mode 100644 index 0000000..a812ae3 --- /dev/null +++ b/tests/test_typechecking.py @@ -0,0 +1,119 @@ +from probably.pgcl.ast.program import ProgramConfig +from probably.pgcl.ast.declarations import ConstDecl, VarDecl +from probably.pgcl.ast.expressions import NatLitExpr, VarExpr +from probably.pgcl.ast.types import NatType, RealType +from probably.pgcl.check import CheckFail, check_program +from probably.pgcl.parser import parse_pgcl + +def test_correct_program(): + program = parse_pgcl(""" + const pi := 3.14 + nat x + real y + const twopi := 2 * pi + while(x < 10 & false) { + skip + } + if(pi = 5.0 || false) { + x := 3 + } { + { + loop(300) { + // tick(77) + skip + } + } [y] { + observe(true) + } + } + ?Pr [true] + ?Pr [5] + ?Ex [7 = 8] + !Plot [x, y, 5] + """) + assert check_program(program) is None + + +def test_for_declaration_errors(): + program = parse_pgcl(""" + const twopi := 2 * pi + const pi := 3.14 + """) + check = check_program(program) + assert isinstance(check, CheckFail) + assert check.location == VarExpr("pi") + assert "Constant is not yet defined" in check.message + + program = parse_pgcl(""" + const pi := 3.14 + nat x + const xpi := x * pi + """) + check = check_program(program) + assert isinstance(check, CheckFail) + assert check.location == VarExpr("x") + assert "Variable used in constant definition is not a constant" in check.message + + program = parse_pgcl(""" + nat x + nat x + """) + check = check_program(program) + assert isinstance(check, CheckFail) + assert check.location == VarDecl("x", NatType(None)) + assert "Already declared variable/constant before." in check.message + + program = parse_pgcl(""" + const x := 4 + const x := 5 + """) + check = check_program(program) + assert isinstance(check, CheckFail) + assert check.location == ConstDecl("x", NatLitExpr(5)) + assert "Already declared variable/constant before." in check.message + + program = parse_pgcl("real x", ProgramConfig(allow_real_vars = False)) + check = check_program(program) + assert isinstance(check, CheckFail) + assert check.location == VarDecl("x", RealType()) + assert "Real number variables are not allowed by the program config." in check.message + + +def test_for_instr_errors(): + program = parse_pgcl(""" + real x + while(x) { + skip + } + """, ProgramConfig(allow_real_vars = False)) + assert isinstance(check_program(program), CheckFail) + + program = parse_pgcl(""" + real x + if(x) { + skip + } else { + // ??? + } + """, ProgramConfig(allow_real_vars = False)) + assert isinstance(check_program(program), CheckFail) + + program = parse_pgcl(""" + real x + x := 5 + """, ProgramConfig(allow_real_vars = False)) + assert isinstance(check_program(program), CheckFail) + + program = parse_pgcl(""" + x := 5 + """, ProgramConfig(allow_real_vars = False)) + assert isinstance(check_program(program), CheckFail) + + program = parse_pgcl(""" + { + skip + } [true] { + skip + } + """, ProgramConfig(allow_real_vars = False)) + assert isinstance(check_program(program), CheckFail) From 965da72a13f6a1f4f6adfae4ca350e7d9e340b40 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 27 May 2022 15:52:55 +0200 Subject: [PATCH 39/67] Revert "Remove test for parser check that is no longer done" This reverts commit 5de84e68cc73249e2b5323f4a2df58cda71b9b5c. --- tests/test_compile_checks.py | 3 +++ tests/test_distributions.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_compile_checks.py b/tests/test_compile_checks.py index a4568f7..a32a99e 100644 --- a/tests/test_compile_checks.py +++ b/tests/test_compile_checks.py @@ -6,6 +6,9 @@ def test_uniform_checks(): + program = compile_pgcl("nat x; x := unif(13, 6.0);") + assert isinstance(program, CheckFail) + with pytest.raises(UnexpectedCharacters) as excinfo: compile_pgcl("nat x; x := x + unif(13, 6);") diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 2e2e8ce..b71c7ca 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -22,4 +22,4 @@ def test_all_distributions(): PoissonExpr(NatLitExpr(1)), LogDistExpr(NatLitExpr(1)), BernoulliExpr(NatLitExpr(1)), - BinomialExpr(NatLitExpr(1), NatLitExpr(2))] + BinomialExpr(NatLitExpr(1), NatLitExpr(2))] \ No newline at end of file From 8404efae9715331343024d6319d08532ad26c3ee Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 27 May 2022 16:23:40 +0200 Subject: [PATCH 40/67] Fix bug in typechecking test --- tests/test_distributions.py | 2 +- tests/test_typechecking.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_distributions.py b/tests/test_distributions.py index b71c7ca..2e2e8ce 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -22,4 +22,4 @@ def test_all_distributions(): PoissonExpr(NatLitExpr(1)), LogDistExpr(NatLitExpr(1)), BernoulliExpr(NatLitExpr(1)), - BinomialExpr(NatLitExpr(1), NatLitExpr(2))] \ No newline at end of file + BinomialExpr(NatLitExpr(1), NatLitExpr(2))] diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py index a812ae3..868d753 100644 --- a/tests/test_typechecking.py +++ b/tests/test_typechecking.py @@ -85,7 +85,7 @@ def test_for_instr_errors(): while(x) { skip } - """, ProgramConfig(allow_real_vars = False)) + """) assert isinstance(check_program(program), CheckFail) program = parse_pgcl(""" @@ -95,18 +95,18 @@ def test_for_instr_errors(): } else { // ??? } - """, ProgramConfig(allow_real_vars = False)) + """) assert isinstance(check_program(program), CheckFail) program = parse_pgcl(""" real x x := 5 - """, ProgramConfig(allow_real_vars = False)) + """) assert isinstance(check_program(program), CheckFail) program = parse_pgcl(""" x := 5 - """, ProgramConfig(allow_real_vars = False)) + """) assert isinstance(check_program(program), CheckFail) program = parse_pgcl(""" @@ -115,5 +115,5 @@ def test_for_instr_errors(): } [true] { skip } - """, ProgramConfig(allow_real_vars = False)) + """) assert isinstance(check_program(program), CheckFail) From 02dc6dde402932c8cddb632dfad6978b413444bc Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 27 May 2022 17:03:23 +0200 Subject: [PATCH 41/67] Remove 'parameters' parameter from Program.from_parse --- probably/pgcl/ast/program.py | 8 +++++--- probably/pgcl/parser.py | 2 +- tests/test_pgcl.py | 8 ++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/probably/pgcl/ast/program.py b/probably/pgcl/ast/program.py index 1a224cf..805b74f 100644 --- a/probably/pgcl/ast/program.py +++ b/probably/pgcl/ast/program.py @@ -6,7 +6,7 @@ import attr from . import Var from .types import Type -from .declarations import Decl, VarDecl, ConstDecl +from .declarations import Decl, ParameterDecl, VarDecl, ConstDecl from .expressions import Expr from .instructions import Instr @@ -58,17 +58,19 @@ class Program: instructions: List[Instr] = attr.ib() @staticmethod - def from_parse(config: ProgramConfig, declarations: List[Decl], parameters: Dict[Var, Type], - instructions: List[Instr]) -> Program: + def from_parse(config: ProgramConfig, declarations: List[Decl], instructions: List[Instr]) -> Program: """Create a program from the parser's output.""" variables: Dict[Var, Type] = {} constants: Dict[Var, Expr] = {} + parameters: Dict[Var, Type] = {} for decl in declarations: if isinstance(decl, VarDecl): variables[decl.var] = decl.typ elif isinstance(decl, ConstDecl): constants[decl.var] = decl.value + elif isinstance(decl, ParameterDecl): + parameters[decl.var] = decl.typ return Program(config, declarations, variables, constants, parameters, instructions) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index d14103c..75dbef2 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -470,7 +470,7 @@ def _parse_program(config: ProgramConfig, t: Tree) -> Program: declarations = _parse_declarations(_child_tree(t, 0)) instructions = _parse_instrs(_child_tree(t, 1)) instructions.extend(_parse_queries(_child_tree(t, 2))) - return Program.from_parse(config, declarations, _parameters, instructions) + return Program.from_parse(config, declarations, instructions) def parse_pgcl(code: str, config: ProgramConfig = ProgramConfig()) -> Program: diff --git a/tests/test_pgcl.py b/tests/test_pgcl.py index 9354c9f..3929801 100644 --- a/tests/test_pgcl.py +++ b/tests/test_pgcl.py @@ -44,3 +44,11 @@ def test_comments(): """) assert len(program.instructions) == 0 + +def test_params(): + program = parse_pgcl(""" + nparam x + rparam y + """) + assert program.parameters["x"] == NatType(None) + assert program.parameters["y"] == RealType() From 9943cb9eaf7519affb2c8de683604ad1923d4a01 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 27 May 2022 17:41:02 +0200 Subject: [PATCH 42/67] Remove VarExpr.is_parameter --- probably/pgcl/ast/expressions.py | 6 +----- probably/pgcl/parser.py | 18 +----------------- probably/pgcl/syntax.py | 19 ++++++++++++------- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/probably/pgcl/ast/expressions.py b/probably/pgcl/ast/expressions.py index 595384a..0fd4cbf 100644 --- a/probably/pgcl/ast/expressions.py +++ b/probably/pgcl/ast/expressions.py @@ -40,16 +40,12 @@ def __str__(self) -> str: class VarExpr(ExprClass): """A variable is an expression.""" var: Var = attr.ib() - is_parameter: bool = attr.ib(default=False) def __str__(self) -> str: return self.var def __repr__(self) -> str: - if self.is_parameter: - return f"ParamExpr({repr(self.var)})" - else: - return f'VarExpr({repr(self.var)})' + return f'VarExpr({repr(self.var)})' @attr.s(repr=False) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 75dbef2..9e34f6e 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -25,7 +25,6 @@ import attr from lark import Lark, Tree -from probably.pgcl.syntax import _has_variable from probably.pgcl.ast import * from probably.pgcl.ast.walk import Walk, walk_expr from probably.util.lark_expr_parser import (atom, build_expr_parser, infixl, @@ -135,9 +134,6 @@ def _doc_parser_grammar(): _doc_parser_grammar.__doc__ = "The Lark grammar for pGCL::\n" + _PGCL_GRAMMAR + "\n\nThis function only exists for documentation purposes and should never be called in code." -# Collect parameter information here. -_parameters: Dict[Var, Type] = {} - # All known distribution types. Dictionary entry contains the token name as key. # Also the value of a given gey is a tuple consisting of the number of parameters and the Class name (constructor call) distributions: Dict[str, Tuple[int, Callable]] = { @@ -216,10 +212,8 @@ def opt_child1(): elif t.data == "const": return ConstDecl(var0(), _parse_expr(_child_tree(t, 1))) elif t.data == "rparam": - _parameters[var0()] = RealType() return ParameterDecl(var0(), RealType()) elif t.data == "nparam": - _parameters[var0()] = NatType(bounds=None) return ParameterDecl(var0(), NatType(bounds=None)) else: raise Exception(f'invalid AST: {t.data}') @@ -241,7 +235,7 @@ def expr1() -> Expr: return _parse_literal(_child_tree(t, 0)) elif t.data == 'var': name = _parse_var(_child_tree(t, 0)) - return VarExpr(name, name in _parameters) + return VarExpr(name) elif t.data == 'or': return BinopExpr(Binop.OR, expr0(), expr1()) elif t.data == 'and': @@ -314,9 +308,6 @@ def _parse_distribution(t: Tree) -> Expr: params = [] for i in range(param_count): param = _parse_expr(_child_tree(t, i)) - if _has_variable(param): - raise SyntaxError( - "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?") params.append(param) return constructor(*params) @@ -369,9 +360,6 @@ def _parse_instr(t: Tree) -> Instr: _parse_instrs(_child_tree(t, 1)), _parse_instrs(_child_tree(t, 2))) elif t.data == 'assign': - variable = _parse_var(_child_tree(t, 0)) - if variable in _parameters: - raise SyntaxError("Parameters must not be assigned a new value.") return AsgnInstr(_parse_var(_child_tree(t, 0)), _parse_rvalue(_child_tree(t, 1))) elif t.data == 'choice': @@ -415,9 +403,6 @@ def _parse_query(t: Tree): else: raise SyntaxError(f"The optimization can either be 'MAX' or 'MIN', but not {mode}") parameter = _parse_var(_child_tree(t, 1)) - if parameter not in _parameters: - raise SyntaxError( - f"In optimization queries, the variable can only be a program parameter, was {parameter}.") return OptimizationQuery(_parse_expr(_child_tree(t, 0)), parameter, opt_type) elif t.data == "plot": if len(t.children) == 3: @@ -466,7 +451,6 @@ def _parse_query(t: Tree): def _parse_program(config: ProgramConfig, t: Tree) -> Program: assert t.data == 'start' - globals()['_parameters'] = {} declarations = _parse_declarations(_child_tree(t, 0)) instructions = _parse_instrs(_child_tree(t, 1)) instructions.extend(_parse_queries(_child_tree(t, 2))) diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index 8bd0f5b..5890e4b 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -89,7 +89,7 @@ """ -from typing import Optional, Sequence +from typing import List, Optional, Sequence from probably.util.ref import Mut @@ -119,29 +119,33 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: """ for instr_ref in walk_instrs(Walk.DOWN, program.instructions): for expr in instr_exprs(instr_ref.val): - res = check_is_linear_expr(expr) + res = check_is_linear_expr(expr, [*program.constants.keys(), *program.parameters.keys()]) if isinstance(res, CheckFail): return res return None -def _has_variable(expr: Expr) -> bool: +def _has_variable(expr: Expr, not_a_variable: List[str]) -> bool: if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: return False - if isinstance(expr, VarExpr) and not expr.is_parameter: + if isinstance(expr, VarExpr) and not expr in not_a_variable: return True for child_ref in mut_expr_children(Mut.alloc(expr)): - if _has_variable(child_ref.val): + if _has_variable(child_ref.val, not_a_variable): return True return False -def check_is_linear_expr(expr: Expr) -> Optional[CheckFail]: +def check_is_linear_expr(expr: Expr, not_a_variable: List[str]) -> Optional[CheckFail]: """ Linear expressions do not multiply variables with each other. However, they may contain multiplication with constants or Iverson brackets. Division is also not allowed in linear expressions. + :param expr: + :param not_a_variable: A list of literals that are not to be considered variables. Usually, this + consists of all parameters and constants of a program. + .. doctest:: >>> from .ast import * @@ -162,7 +166,8 @@ def check_is_linear_expr(expr: Expr) -> Optional[CheckFail]: node = node_ref.val if isinstance(node, BinopExpr): if node.operator == Binop.MODULO or \ - (node.operator == Binop.TIMES and _has_variable(node.lhs) and _has_variable(node.rhs)): + (node.operator == Binop.TIMES and _has_variable(node.lhs, not_a_variable) \ + and _has_variable(node.rhs, not_a_variable)): return CheckFail(node, "Is not a linear expression") if node.operator == Binop.DIVIDE: return CheckFail( From a1f93d95c73b21e40fa9642788e1fff6b2a0df75 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 1 Jun 2022 14:55:56 +0200 Subject: [PATCH 43/67] Fix unsafe return type of get_type for iid expressions --- probably/pgcl/check.py | 8 +++----- probably/util/color.py | 19 ------------------- 2 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 probably/util/color.py diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index fd82cb7..458e8d0 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -8,7 +8,6 @@ import attr -from probably.util.color import Style from probably.util.ref import Mut from .ast import (AsgnInstr, Binop, BinopExpr, BoolLitExpr, BoolType, @@ -198,11 +197,11 @@ def get_type(program: Program, raise Exception("unreachable") -def _check_distribution_arguments(prog: Program, expected_type: Type, *parameters: Tuple[Type, Expr]): +def _check_distribution_arguments(prog: Program, expected_type: Type, *parameters: Tuple[Type, Expr]) -> Union[Type, CheckFail]: for expected_param_type, param_expr in parameters: param_type = get_type(prog, param_expr) if isinstance(param_type, CheckFail): - return CheckFail + return param_type elif not is_compatible(expected_param_type, param_type): return CheckFail.expected_type_got(param_expr, expected_param_type, param_type) return expected_type @@ -238,8 +237,7 @@ def _get_distribution_type(prog: Program, expr: Expr, check: bool = True) -> Uni if isinstance(expr.sampling_dist, get_args(DistrExpr)): return _get_distribution_type(prog, expr.sampling_dist, check) else: - print(Style.OKRED + "Type Checking is not accurate anymore." + Style.RESET) - return check_expression(prog, expr.sampling_dist) + return get_type(prog, expr.sampling_dist, check) raise Exception("unreachable") diff --git a/probably/util/color.py b/probably/util/color.py deleted file mode 100644 index 01b9a84..0000000 --- a/probably/util/color.py +++ /dev/null @@ -1,19 +0,0 @@ - -class Style: - BLACK = '\033[30m' - RED = '\033[31m' - GREEN = '\033[32m' - YELLOW = '\033[33m' - BLUE = '\033[34m' - MAGENTA = '\033[35m' - CYAN = '\033[36m' - WHITE = '\033[37m' - UNDERLINE = '\033[4m' - OKWHITE = '\033[97m' - OKCYAN = '\033[96m' - OKMAGENTA = '\033[95m' - OKBLUE = '\033[94m' - OKYELLOW = '\033[93m' - OKGREEN = '\033[92m' - OKRED = '\033[91m' - RESET = '\033[0m' From 8cc2a56714aad3229c1072426be8c32add5dc6c8 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 1 Jun 2022 15:13:17 +0200 Subject: [PATCH 44/67] Prettify linear checks --- probably/pgcl/syntax.py | 37 +++++++++++++++---------------- tests/test_operator_precedence.py | 4 ++-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index 5890e4b..f0516f0 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -89,12 +89,12 @@ """ -from typing import List, Optional, Sequence +from typing import Set, Optional, Sequence from probably.util.ref import Mut from .ast import (AsgnInstr, Binop, BinopExpr, Expr, Instr, Program, Unop, - UnopExpr, VarExpr, WhileInstr) + UnopExpr, Var, VarExpr, WhileInstr) from .check import CheckFail from .ast.walk import Walk, instr_exprs, mut_expr_children, walk_expr, walk_instrs @@ -119,32 +119,22 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: """ for instr_ref in walk_instrs(Walk.DOWN, program.instructions): for expr in instr_exprs(instr_ref.val): - res = check_is_linear_expr(expr, [*program.constants.keys(), *program.parameters.keys()]) + res = check_is_linear_expr(expr, {*program.parameters.keys()}) if isinstance(res, CheckFail): return res return None -def _has_variable(expr: Expr, not_a_variable: List[str]) -> bool: - if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: - return False - if isinstance(expr, VarExpr) and not expr in not_a_variable: - return True - for child_ref in mut_expr_children(Mut.alloc(expr)): - if _has_variable(child_ref.val, not_a_variable): - return True - return False - - -def check_is_linear_expr(expr: Expr, not_a_variable: List[str]) -> Optional[CheckFail]: +#pylint: disable = dangerous-default-value +def check_is_linear_expr(expr: Expr, not_a_variable: Set[Var] = set()) -> Optional[CheckFail]: """ Linear expressions do not multiply variables with each other. However, they may contain multiplication with constants or Iverson brackets. Division is also not allowed in linear expressions. :param expr: - :param not_a_variable: A list of literals that are not to be considered variables. Usually, this - consists of all parameters and constants of a program. + :param not_a_variable: A collection of literals that are not to be considered variables, for example the + parameters of a program .. doctest:: @@ -162,12 +152,21 @@ def check_is_linear_expr(expr: Expr, not_a_variable: List[str]) -> Optional[Chec CheckFail(location=..., message='General division is not linear (division of constants is)') """ + def _has_variable(expr: Expr) -> bool: + if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: + return False + if isinstance(expr, VarExpr) and not expr.var in not_a_variable: + return True + for child_ref in mut_expr_children(Mut.alloc(expr)): + if _has_variable(child_ref.val): + return True + return False + for node_ref in walk_expr(Walk.DOWN, Mut.alloc(expr)): node = node_ref.val if isinstance(node, BinopExpr): if node.operator == Binop.MODULO or \ - (node.operator == Binop.TIMES and _has_variable(node.lhs, not_a_variable) \ - and _has_variable(node.rhs, not_a_variable)): + (node.operator == Binop.TIMES and _has_variable(node.lhs) and _has_variable(node.rhs)): return CheckFail(node, "Is not a linear expression") if node.operator == Binop.DIVIDE: return CheckFail( diff --git a/tests/test_operator_precedence.py b/tests/test_operator_precedence.py index 2a28c39..d3f6dd8 100644 --- a/tests/test_operator_precedence.py +++ b/tests/test_operator_precedence.py @@ -21,8 +21,8 @@ def test_all_operators(): assert instr[0].rhs == BinopExpr(Binop.OR, BoolLitExpr(True), BinopExpr(Binop.AND, BoolLitExpr(False), BoolLitExpr(True))) - assert instr[1].rhs == BinopExpr(Binop.AND, BinopExpr(Binop.GE, RealLitExpr(Decimal(6.0)), VarExpr("pi", False)),\ - UnopExpr(Unop.NEG, BinopExpr(Binop.EQ, VarExpr("pi", False), BinopExpr(Binop.TIMES, VarExpr("pi", False), NatLitExpr(3))))) + assert instr[1].rhs == BinopExpr(Binop.AND, BinopExpr(Binop.GE, RealLitExpr(Decimal(6.0)), VarExpr("pi")),\ + UnopExpr(Unop.NEG, BinopExpr(Binop.EQ, VarExpr("pi"), BinopExpr(Binop.TIMES, VarExpr("pi"), NatLitExpr(3))))) exprs = instr[2].rhs.exprs assert exprs[0] == (NatLitExpr(1), RealLitExpr(Decimal(0.5))) From 2aa93a305f915afb45bce67b3423e661112246de Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 1 Jun 2022 16:27:48 +0200 Subject: [PATCH 45/67] Fix unsafe default value warning --- probably/pgcl/syntax.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index f0516f0..a7eebc1 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -89,7 +89,8 @@ """ -from typing import Set, Optional, Sequence +from typing import Optional, Sequence +from collections.abc import Container from probably.util.ref import Mut @@ -125,8 +126,7 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: return None -#pylint: disable = dangerous-default-value -def check_is_linear_expr(expr: Expr, not_a_variable: Set[Var] = set()) -> Optional[CheckFail]: +def check_is_linear_expr(expr: Expr, not_a_variable: Container[Var] = frozenset()) -> Optional[CheckFail]: """ Linear expressions do not multiply variables with each other. However, they may contain multiplication with constants or Iverson brackets. From f96efa4aad491140d9cd190e1aed85dd317fe93d Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 1 Jun 2022 17:21:03 +0200 Subject: [PATCH 46/67] Add some old checks from the parser to the typechecker --- probably/pgcl/check.py | 3 +++ tests/test_typechecking.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 458e8d0..998ccbe 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -199,6 +199,7 @@ def get_type(program: Program, def _check_distribution_arguments(prog: Program, expected_type: Type, *parameters: Tuple[Type, Expr]) -> Union[Type, CheckFail]: for expected_param_type, param_expr in parameters: + # Check for variables in parameters here param_type = get_type(prog, param_expr) if isinstance(param_type, CheckFail): return param_type @@ -446,6 +447,8 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: expr_type = get_type(program, instr.expr, check=True) if isinstance(expr_type, CheckFail): return expr_type + if instr.parameter not in program.parameters: + return CheckFail(instr, f"In optimization queries, the variable can only be a program parameter, was {instr.parameter}.") return None if isinstance(instr, PlotInstr): diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py index 868d753..489778a 100644 --- a/tests/test_typechecking.py +++ b/tests/test_typechecking.py @@ -117,3 +117,9 @@ def test_for_instr_errors(): } """) assert isinstance(check_program(program), CheckFail) + + program = parse_pgcl(""" + nparam x + x := 5 + """) + assert isinstance(check_program(program), CheckFail) From ecd08e9f86755a79ed29e5b73561dfb95ce75eb6 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 2 Jun 2022 14:51:01 +0200 Subject: [PATCH 47/67] Fix precedence of modulo operator --- probably/pgcl/parser.py | 2 +- tests/test_operator_precedence.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 9e34f6e..52f7658 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -106,7 +106,7 @@ infixl("geq", ">="), infixl("eq", "=")], [infixl("plus", "+"), infixl("minus", "-")], [infixl("likely", ":")], - [infixl("times", "*"), infixl("divide", "/")], [infixr("power", "^")], [infixl("mod", "%")], + [infixl("times", "*"), infixl("divide", "/"), infixl("mod", "%")], [infixr("power", "^")], [ prefix("neg", "not "), atom("parens", '"(" expression ")"'), diff --git a/tests/test_operator_precedence.py b/tests/test_operator_precedence.py index d3f6dd8..2b99211 100644 --- a/tests/test_operator_precedence.py +++ b/tests/test_operator_precedence.py @@ -32,7 +32,7 @@ def test_all_operators(): assert instr[4].rhs == BinopExpr(Binop.POWER, NatLitExpr(1), BinopExpr(Binop.POWER, NatLitExpr(2), NatLitExpr(3))) - assert instr[5].rhs == BinopExpr(Binop.POWER, BinopExpr(Binop.MODULO, NatLitExpr(1), NatLitExpr(2)), NatLitExpr(3)) + assert instr[5].rhs == BinopExpr(Binop.MODULO, NatLitExpr(1), BinopExpr(Binop.POWER, NatLitExpr(2), NatLitExpr(3))) def test_likely_minus_error(): with raises(Exception) as e: From 476940ac6d605d9ee1ca423479dbdfe102fa5104 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 2 Jun 2022 15:00:17 +0200 Subject: [PATCH 48/67] Fix (suppressed) cyclic dependency warnings --- probably/pgcl/ast/__init__.py | 5 +---- probably/pgcl/ast/ast.py | 3 +++ probably/pgcl/ast/declarations.py | 4 ++-- probably/pgcl/ast/expressions.py | 5 ++--- probably/pgcl/ast/instructions.py | 3 +-- probably/pgcl/ast/program.py | 2 +- probably/pgcl/ast/walk.py | 3 ++- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/probably/pgcl/ast/__init__.py b/probably/pgcl/ast/__init__.py index 432a38c..e2a8017 100644 --- a/probably/pgcl/ast/__init__.py +++ b/probably/pgcl/ast/__init__.py @@ -117,10 +117,7 @@ .. autoclass:: Node """ -Var = str - -# pylint: disable=wrong-import-position, cyclic-import -from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl +from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl, Var from .expressions import VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, BinopExpr, UnopExpr, \ SubstExpr, CategoricalExpr, TickExpr, DUniformExpr, CUniformExpr, GeometricExpr, PoissonExpr, LogDistExpr, \ BinomialExpr, BernoulliExpr, Binop, Unop, Expr, ExprClass, DistrExpr, IidSampleExpr, expr_str_parens diff --git a/probably/pgcl/ast/ast.py b/probably/pgcl/ast/ast.py index efb8ac5..9b50cff 100644 --- a/probably/pgcl/ast/ast.py +++ b/probably/pgcl/ast/ast.py @@ -2,6 +2,9 @@ import attr +Var = str + + @attr.s class Node(ABC): """Superclass for all node types in the AST.""" diff --git a/probably/pgcl/ast/declarations.py b/probably/pgcl/ast/declarations.py index b6a2d5b..a7d5e43 100644 --- a/probably/pgcl/ast/declarations.py +++ b/probably/pgcl/ast/declarations.py @@ -4,13 +4,13 @@ from abc import abstractmethod import attr from .expressions import Expr -from .ast import Node -from . import Var +from .ast import Node, Var from .types import Type, BoolType, NatType, RealType class DeclClass(Node): """Superclass for all declarations. See :obj:`Decl`.""" + @abstractmethod def __str__(self) -> str: """ diff --git a/probably/pgcl/ast/expressions.py b/probably/pgcl/ast/expressions.py index 0fd4cbf..537487c 100644 --- a/probably/pgcl/ast/expressions.py +++ b/probably/pgcl/ast/expressions.py @@ -9,8 +9,7 @@ from abc import abstractmethod import attr -from .ast import Node -from . import Var +from .ast import Node, Var class ExprClass(Node): """ @@ -427,7 +426,7 @@ class CategoricalExpr(ExprClass): validator=_check_categorical_exprs) def distribution(self) -> List[Tuple[RealLitExpr, Expr]]: - r""" + """ Return the distribution of possible values as a list along with probabilities. """ diff --git a/probably/pgcl/ast/instructions.py b/probably/pgcl/ast/instructions.py index da73ecb..76ef34a 100644 --- a/probably/pgcl/ast/instructions.py +++ b/probably/pgcl/ast/instructions.py @@ -7,8 +7,7 @@ import attr from .expressions import NatLitExpr, VarExpr, RealLitExpr, Expr -from .ast import Node -from . import Var +from .ast import Node, Var class InstrClass(Node): """Superclass for all instructions. See :obj:`Instr`.""" diff --git a/probably/pgcl/ast/program.py b/probably/pgcl/ast/program.py index 805b74f..57e054c 100644 --- a/probably/pgcl/ast/program.py +++ b/probably/pgcl/ast/program.py @@ -4,11 +4,11 @@ import copy import attr -from . import Var from .types import Type from .declarations import Decl, ParameterDecl, VarDecl, ConstDecl from .expressions import Expr from .instructions import Instr +from .ast import Var @attr.s(frozen=True) class ProgramConfig: diff --git a/probably/pgcl/ast/walk.py b/probably/pgcl/ast/walk.py index 72c3b05..23791f2 100644 --- a/probably/pgcl/ast/walk.py +++ b/probably/pgcl/ast/walk.py @@ -38,7 +38,8 @@ from probably.util.ref import Mut -from . import Expr, ExprClass, Instr, InstrClass +from .expressions import Expr, ExprClass +from .instructions import Instr, InstrClass T = TypeVar("T") From 16e31c4c7194b7b42abefbd87bd1d28aacc12ea0 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 2 Jun 2022 15:04:59 +0200 Subject: [PATCH 49/67] Fix typechecking for IidSampleExpr --- probably/pgcl/ast/__init__.py | 4 ++-- probably/pgcl/check.py | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/probably/pgcl/ast/__init__.py b/probably/pgcl/ast/__init__.py index e2a8017..eb5ffd6 100644 --- a/probably/pgcl/ast/__init__.py +++ b/probably/pgcl/ast/__init__.py @@ -117,7 +117,7 @@ .. autoclass:: Node """ -from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl, Var +from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl from .expressions import VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, BinopExpr, UnopExpr, \ SubstExpr, CategoricalExpr, TickExpr, DUniformExpr, CUniformExpr, GeometricExpr, PoissonExpr, LogDistExpr, \ BinomialExpr, BernoulliExpr, Binop, Unop, Expr, ExprClass, DistrExpr, IidSampleExpr, expr_str_parens @@ -125,6 +125,6 @@ AsgnInstr, LoopInstr, ChoiceInstr, TickInstr, ObserveInstr, Instr, Query, InstrClass, PrintInstr,\ OptimizationType, OptimizationQuery from .types import BoolType, NatType, RealType, Type, Bounds -from .ast import Node +from .ast import Node, Var from .program import Program, ProgramConfig from .walk import * diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 998ccbe..ed79189 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -238,7 +238,11 @@ def _get_distribution_type(prog: Program, expr: Expr, check: bool = True) -> Uni if isinstance(expr.sampling_dist, get_args(DistrExpr)): return _get_distribution_type(prog, expr.sampling_dist, check) else: - return get_type(prog, expr.sampling_dist, check) + if check: + safe = check_expression(prog, expr.sampling_dist) + if isinstance(safe, CheckFail): + return safe + return NatType(bounds=None) raise Exception("unreachable") From 5ab560ce36e2fe33c4fc57a8f844fc40d357277e Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 2 Jun 2022 15:09:33 +0200 Subject: [PATCH 50/67] Give some binary operators clearer names --- probably/pgcl/ast/expressions.py | 8 ++++---- probably/pgcl/check.py | 4 ++-- probably/pgcl/parser.py | 4 ++-- probably/pysmt/expr.py | 2 +- tests/test_operator_precedence.py | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/probably/pgcl/ast/expressions.py b/probably/pgcl/ast/expressions.py index 537487c..e17e840 100644 --- a/probably/pgcl/ast/expressions.py +++ b/probably/pgcl/ast/expressions.py @@ -180,8 +180,8 @@ class Binop(Enum): OR = auto() AND = auto() LEQ = auto() - LE = auto() - GE = auto() + LT = auto() + GT = auto() GEQ = auto() EQ = auto() PLUS = auto() @@ -204,8 +204,8 @@ def __str__(self) -> str: Binop.OR: "||", Binop.AND: "&", Binop.LEQ: "<=", - Binop.LE: "<", - Binop.GE: ">", + Binop.LT: "<", + Binop.GT: ">", Binop.GEQ: ">=", Binop.EQ: "=", Binop.PLUS: "+", diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index ed79189..e6ca5e5 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -154,7 +154,7 @@ def get_type(program: Program, return CheckFail.expected_numeric_got(expr.lhs, lhs_typ) if check and expr.operator in [ - Binop.LEQ, Binop.LE, Binop.GEQ, Binop.GE, Binop.EQ, Binop.PLUS, Binop.MINUS, + Binop.LEQ, Binop.LT, Binop.GEQ, Binop.GT, Binop.EQ, Binop.PLUS, Binop.MINUS, Binop.TIMES, Binop.MODULO, Binop.POWER ]: rhs_typ = get_type(program, expr.rhs, check=check) @@ -167,7 +167,7 @@ def get_type(program: Program, return CheckFail.expected_type_got(expr, lhs_typ, rhs_typ) # binops that take numeric operands and return a boolean - if expr.operator in [Binop.LEQ, Binop.LE, Binop.EQ, Binop.GEQ, Binop.GE]: + if expr.operator in [Binop.LEQ, Binop.LT, Binop.EQ, Binop.GEQ, Binop.GT]: return BoolType() # binops that take numeric operands and return a numeric value diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 52f7658..cc9cb20 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -243,11 +243,11 @@ def expr1() -> Expr: elif t.data == 'leq': return BinopExpr(Binop.LEQ, expr0(), expr1()) elif t.data == 'le': - return BinopExpr(Binop.LE, expr0(), expr1()) + return BinopExpr(Binop.LT, expr0(), expr1()) elif t.data == 'geq': return BinopExpr(Binop.GEQ, expr0(), expr1()) elif t.data == 'ge': - return BinopExpr(Binop.GE, expr0(), expr1()) + return BinopExpr(Binop.GT, expr0(), expr1()) elif t.data == 'eq': return BinopExpr(Binop.EQ, expr0(), expr1()) elif t.data == 'plus': diff --git a/probably/pysmt/expr.py b/probably/pysmt/expr.py index ae27f51..8595fee 100644 --- a/probably/pysmt/expr.py +++ b/probably/pysmt/expr.py @@ -105,7 +105,7 @@ def expr_to_pysmt(context: TranslationContext, return And(lhs, rhs) elif expr.operator == Binop.LEQ: return LE(lhs, rhs) - elif expr.operator == Binop.LE: + elif expr.operator == Binop.LT: return LT(lhs, rhs) elif expr.operator == Binop.EQ: return EqualsOrIff(lhs, rhs) diff --git a/tests/test_operator_precedence.py b/tests/test_operator_precedence.py index 2b99211..2fb7036 100644 --- a/tests/test_operator_precedence.py +++ b/tests/test_operator_precedence.py @@ -21,7 +21,7 @@ def test_all_operators(): assert instr[0].rhs == BinopExpr(Binop.OR, BoolLitExpr(True), BinopExpr(Binop.AND, BoolLitExpr(False), BoolLitExpr(True))) - assert instr[1].rhs == BinopExpr(Binop.AND, BinopExpr(Binop.GE, RealLitExpr(Decimal(6.0)), VarExpr("pi")),\ + assert instr[1].rhs == BinopExpr(Binop.AND, BinopExpr(Binop.GT, RealLitExpr(Decimal(6.0)), VarExpr("pi")),\ UnopExpr(Unop.NEG, BinopExpr(Binop.EQ, VarExpr("pi"), BinopExpr(Binop.TIMES, VarExpr("pi"), NatLitExpr(3))))) exprs = instr[2].rhs.exprs From 0da4e946fa82118f5eacdaf382a36d643df61c12 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 2 Jun 2022 16:04:52 +0200 Subject: [PATCH 51/67] Replace not_a_variable and add a warning to the typechecker --- probably/pgcl/__init__.py | 2 +- probably/pgcl/check.py | 19 +++++++++++++++++-- probably/pgcl/compiler.py | 4 ++-- probably/pgcl/parser.py | 2 +- probably/pgcl/syntax.py | 25 ++++++++++++------------- tests/test_typechecking.py | 10 ++++++++++ 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/probably/pgcl/__init__.py b/probably/pgcl/__init__.py index 48f3d35..b265b71 100644 --- a/probably/pgcl/__init__.py +++ b/probably/pgcl/__init__.py @@ -31,7 +31,7 @@ ... {c := unif(1,10)} [0.8] {f:=true} ... }''' >>> compile_pgcl(code) - Program(variables={'f': BoolType(), 'c': NatType(bounds=None)}, constants={}, parameters={}, instructions=[SkipInstr(), WhileInstr(cond=BinopExpr(operator=Binop.AND, lhs=BinopExpr(operator=Binop.LE, lhs=VarExpr('c'), rhs=NatLitExpr(10)), rhs=VarExpr('f')), body=[ChoiceInstr(prob=RealLitExpr("0.8"), lhs=[AsgnInstr(lhs='c', rhs=DUniformExpr(start=NatLitExpr(1), end=NatLitExpr(10)))], rhs=[AsgnInstr(lhs='f', rhs=BoolLitExpr(True))])])]) + Program(variables={'f': BoolType(), 'c': NatType(bounds=None)}, constants={}, parameters={}, instructions=[SkipInstr(), WhileInstr(cond=BinopExpr(operator=Binop.AND, lhs=BinopExpr(operator=Binop.LT, lhs=VarExpr('c'), rhs=NatLitExpr(10)), rhs=VarExpr('f')), body=[ChoiceInstr(prob=RealLitExpr("0.8"), lhs=[AsgnInstr(lhs='c', rhs=DUniformExpr(start=NatLitExpr(1), end=NatLitExpr(10)))], rhs=[AsgnInstr(lhs='f', rhs=BoolLitExpr(True))])])]) For more details on what syntax is accepted for pGCL programs, you can view the :ref:`formal grammar used for the pGCL parser `. diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index e6ca5e5..4768c9b 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -18,7 +18,7 @@ ExpectationInstr, PrintInstr, OptimizationQuery, PlotInstr, LoopInstr, CUniformExpr, GeometricExpr, BernoulliExpr,PoissonExpr, LogDistExpr, BinomialExpr, IidSampleExpr, DistrExpr) -from .ast.walk import Walk, walk_expr +from .ast.walk import Walk, mut_expr_children, walk_expr _T = TypeVar('_T') @@ -198,8 +198,23 @@ def get_type(program: Program, def _check_distribution_arguments(prog: Program, expected_type: Type, *parameters: Tuple[Type, Expr]) -> Union[Type, CheckFail]: + # this function is copied from the syntax module, which is not pretty, but prevents cyclic imports + # also, it works only if constant substitution has been performed + # pylint: disable=duplicate-code + def _has_variable(expr: Expr) -> bool: + if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: + return False + if isinstance(expr, VarExpr) and expr.var not in prog.parameters: + return True + for child_ref in mut_expr_children(Mut.alloc(expr)): + if _has_variable(child_ref.val): + return True + return False + for expected_param_type, param_expr in parameters: - # Check for variables in parameters here + if _has_variable(param_expr): + return CheckFail(param_expr, "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?") + param_type = get_type(prog, param_expr) if isinstance(param_type, CheckFail): return param_type diff --git a/probably/pgcl/compiler.py b/probably/pgcl/compiler.py index 19f5889..6c3e788 100644 --- a/probably/pgcl/compiler.py +++ b/probably/pgcl/compiler.py @@ -41,11 +41,11 @@ def compile_pgcl(code: str, substitute_constants: Whether constant substitution is done on the program, defaults to `True`. """ program = parse_pgcl(code) + if substitute_constants: + substitute.substitute_constants(program) check_result = check_program(program) if check_result is not None: return check_result - if substitute_constants: - substitute.substitute_constants(program) return program diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index cc9cb20..7f05a0e 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -485,7 +485,7 @@ def parse_expr(code: str) -> Expr: .. doctest:: >>> parse_expr("x < y & z") - BinopExpr(operator=Binop.AND, lhs=BinopExpr(operator=Binop.LE, lhs=VarExpr('x'), rhs=VarExpr('y')), rhs=VarExpr('z')) + BinopExpr(operator=Binop.AND, lhs=BinopExpr(operator=Binop.LT, lhs=VarExpr('x'), rhs=VarExpr('y')), rhs=VarExpr('z')) >>> parse_expr("[x]") Traceback (most recent call last): diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index a7eebc1..367c20b 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -90,12 +90,11 @@ """ from typing import Optional, Sequence -from collections.abc import Container from probably.util.ref import Mut from .ast import (AsgnInstr, Binop, BinopExpr, Expr, Instr, Program, Unop, - UnopExpr, Var, VarExpr, WhileInstr) + UnopExpr, VarExpr, WhileInstr) from .check import CheckFail from .ast.walk import Walk, instr_exprs, mut_expr_children, walk_expr, walk_instrs @@ -120,42 +119,42 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: """ for instr_ref in walk_instrs(Walk.DOWN, program.instructions): for expr in instr_exprs(instr_ref.val): - res = check_is_linear_expr(expr, {*program.parameters.keys()}) + res = check_is_linear_expr(expr, program) if isinstance(res, CheckFail): return res return None -def check_is_linear_expr(expr: Expr, not_a_variable: Container[Var] = frozenset()) -> Optional[CheckFail]: +def check_is_linear_expr(expr: Expr, context: Program) -> Optional[CheckFail]: """ Linear expressions do not multiply variables with each other. However, they may contain multiplication with constants or Iverson brackets. Division is also not allowed in linear expressions. :param expr: - :param not_a_variable: A collection of literals that are not to be considered variables, for example the - parameters of a program + :param not_a_variable: The context in which the expression is to be evaluated. Literals that are + parameters according to this context not considered variables. .. doctest:: >>> from .ast import * >>> from .parser import parse_expectation >>> nat = NatLitExpr(10) - >>> check_is_linear_expr(BinopExpr(Binop.TIMES, nat, nat)) - >>> check_is_linear_expr(BinopExpr(Binop.TIMES, nat, VarExpr('x'))) - >>> check_is_linear_expr(BinopExpr(Binop.TIMES, VarExpr('x'), VarExpr('x'))) + >>> check_is_linear_expr(BinopExpr(Binop.TIMES, nat, nat), None) + >>> check_is_linear_expr(BinopExpr(Binop.TIMES, nat, VarExpr('x')), None) + >>> check_is_linear_expr(BinopExpr(Binop.TIMES, VarExpr('x'), VarExpr('x')), None) CheckFail(location=..., message='Is not a linear expression') - >>> check_is_linear_expr(parse_expectation("[x < 6] * x")) - >>> check_is_linear_expr(parse_expectation("[x * x]")) + >>> check_is_linear_expr(parse_expectation("[x < 6] * x"), None) + >>> check_is_linear_expr(parse_expectation("[x * x]"), None) CheckFail(location=..., message='Is not a linear expression') - >>> check_is_linear_expr(parse_expectation("x/x")) + >>> check_is_linear_expr(parse_expectation("x/x"), None) CheckFail(location=..., message='General division is not linear (division of constants is)') """ def _has_variable(expr: Expr) -> bool: if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: return False - if isinstance(expr, VarExpr) and not expr.var in not_a_variable: + if isinstance(expr, VarExpr) and (context is None or expr.var not in context.parameters): return True for child_ref in mut_expr_children(Mut.alloc(expr)): if _has_variable(child_ref.val): diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py index 489778a..2e366d6 100644 --- a/tests/test_typechecking.py +++ b/tests/test_typechecking.py @@ -123,3 +123,13 @@ def test_for_instr_errors(): x := 5 """) assert isinstance(check_program(program), CheckFail) + + program = parse_pgcl(""" + nat x + nat y + x := 5 + y := unif(10, x * 5 + 3) + """) + res = check_program(program) + assert isinstance(res, CheckFail) + assert "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?" in res.message From 6158b3758fe62c43005e807f7e9f47cf9cf6c625 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 2 Jun 2022 16:18:02 +0200 Subject: [PATCH 52/67] Make it more explicit that iid type checking is unsafe --- probably/pgcl/check.py | 2 ++ probably/pgcl/syntax.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 4768c9b..03b518d 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -253,10 +253,12 @@ def _get_distribution_type(prog: Program, expr: Expr, check: bool = True) -> Uni if isinstance(expr.sampling_dist, get_args(DistrExpr)): return _get_distribution_type(prog, expr.sampling_dist, check) else: + # we cannot check whether the sampling distribution as given by the program is actually a distribution if check: safe = check_expression(prog, expr.sampling_dist) if isinstance(safe, CheckFail): return safe + print(f"Type Checking is not accurate anymore (because of '{expr}').") return NatType(bounds=None) raise Exception("unreachable") diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index 367c20b..444c4d0 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -133,7 +133,7 @@ def check_is_linear_expr(expr: Expr, context: Program) -> Optional[CheckFail]: :param expr: :param not_a_variable: The context in which the expression is to be evaluated. Literals that are - parameters according to this context not considered variables. + parameters according to this context are not considered variables. .. doctest:: From 7e8c1806f022db60318caf6bf16f253d3155ade6 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 3 Jun 2022 14:25:23 +0200 Subject: [PATCH 53/67] Logger warning for typechecking of iid exprs --- probably/pgcl/ast/expressions.py | 4 +++- probably/pgcl/check.py | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/probably/pgcl/ast/expressions.py b/probably/pgcl/ast/expressions.py index e17e840..50265d1 100644 --- a/probably/pgcl/ast/expressions.py +++ b/probably/pgcl/ast/expressions.py @@ -402,7 +402,9 @@ def __str__(self) -> str: @attr.s class IidSampleExpr(ExprClass): - """ Independently sampling from identical distributions""" + """ Independently sampling from identical distributions + + We assume the sampling distribution to be encoded as a PGF (this is not checked by probably).""" sampling_dist: Expr = attr.ib() variable: VarExpr = attr.ib() diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 03b518d..7a00317 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -7,6 +7,7 @@ from typing import Dict, Iterable, List, Optional, TypeVar, Union, get_args, Tuple import attr +import logging from probably.util.ref import Mut @@ -253,12 +254,12 @@ def _get_distribution_type(prog: Program, expr: Expr, check: bool = True) -> Uni if isinstance(expr.sampling_dist, get_args(DistrExpr)): return _get_distribution_type(prog, expr.sampling_dist, check) else: - # we cannot check whether the sampling distribution as given by the program is actually a distribution + # we cannot check whether the sampling distribution as given by the program is actually a PGF if check: safe = check_expression(prog, expr.sampling_dist) if isinstance(safe, CheckFail): return safe - print(f"Type Checking is not accurate anymore (because of '{expr}').") + logging.getLogger("probably").warn("Probably does not check whether expressions used in DistrExprs are actually valid PGFs.", expr=expr) return NatType(bounds=None) raise Exception("unreachable") From 6247646dfebc3909806e43aa4d06d273684257fa Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 3 Jun 2022 14:28:02 +0200 Subject: [PATCH 54/67] Update parameter in syntax module --- probably/pgcl/syntax.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index 444c4d0..a85c6b6 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -125,15 +125,16 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: return None -def check_is_linear_expr(expr: Expr, context: Program) -> Optional[CheckFail]: +def check_is_linear_expr(context: Optional[Program], expr: Expr) -> Optional[CheckFail]: """ Linear expressions do not multiply variables with each other. However, they may contain multiplication with constants or Iverson brackets. Division is also not allowed in linear expressions. + :param context: The context in which the expression is to be evaluated. Literals that are + parameters according to this context are not considered variables. Pass None if + no context is required. :param expr: - :param not_a_variable: The context in which the expression is to be evaluated. Literals that are - parameters according to this context are not considered variables. .. doctest:: From bb071e1a8c6facf6c5c3df8c71dff136ae71b6ee Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 3 Jun 2022 14:39:45 +0200 Subject: [PATCH 55/67] Fix warnings --- probably/pgcl/ast/expressions.py | 2 +- probably/pgcl/check.py | 4 ++-- probably/pgcl/syntax.py | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/probably/pgcl/ast/expressions.py b/probably/pgcl/ast/expressions.py index 50265d1..1c0d800 100644 --- a/probably/pgcl/ast/expressions.py +++ b/probably/pgcl/ast/expressions.py @@ -403,7 +403,7 @@ def __str__(self) -> str: @attr.s class IidSampleExpr(ExprClass): """ Independently sampling from identical distributions - + We assume the sampling distribution to be encoded as a PGF (this is not checked by probably).""" sampling_dist: Expr = attr.ib() variable: VarExpr = attr.ib() diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 7a00317..546077a 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -6,8 +6,8 @@ from typing import Dict, Iterable, List, Optional, TypeVar, Union, get_args, Tuple -import attr import logging +import attr from probably.util.ref import Mut @@ -259,7 +259,7 @@ def _get_distribution_type(prog: Program, expr: Expr, check: bool = True) -> Uni safe = check_expression(prog, expr.sampling_dist) if isinstance(safe, CheckFail): return safe - logging.getLogger("probably").warn("Probably does not check whether expressions used in DistrExprs are actually valid PGFs.", expr=expr) + logging.getLogger("probably").warning("Probably does not check whether expressions used in DistrExprs are actually valid PGFs (%s).", expr) return NatType(bounds=None) raise Exception("unreachable") diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index a85c6b6..a29e6c6 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -119,7 +119,7 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: """ for instr_ref in walk_instrs(Walk.DOWN, program.instructions): for expr in instr_exprs(instr_ref.val): - res = check_is_linear_expr(expr, program) + res = check_is_linear_expr(program, expr) if isinstance(res, CheckFail): return res return None @@ -141,14 +141,14 @@ def check_is_linear_expr(context: Optional[Program], expr: Expr) -> Optional[Che >>> from .ast import * >>> from .parser import parse_expectation >>> nat = NatLitExpr(10) - >>> check_is_linear_expr(BinopExpr(Binop.TIMES, nat, nat), None) - >>> check_is_linear_expr(BinopExpr(Binop.TIMES, nat, VarExpr('x')), None) - >>> check_is_linear_expr(BinopExpr(Binop.TIMES, VarExpr('x'), VarExpr('x')), None) + >>> check_is_linear_expr(None, BinopExpr(Binop.TIMES, nat, nat)) + >>> check_is_linear_expr(None, BinopExpr(Binop.TIMES, nat, VarExpr('x'))) + >>> check_is_linear_expr(None, BinopExpr(Binop.TIMES, VarExpr('x'), VarExpr('x'))) CheckFail(location=..., message='Is not a linear expression') - >>> check_is_linear_expr(parse_expectation("[x < 6] * x"), None) - >>> check_is_linear_expr(parse_expectation("[x * x]"), None) + >>> check_is_linear_expr(None, parse_expectation("[x < 6] * x")) + >>> check_is_linear_expr(None, parse_expectation("[x * x]")) CheckFail(location=..., message='Is not a linear expression') - >>> check_is_linear_expr(parse_expectation("x/x"), None) + >>> check_is_linear_expr(None, parse_expectation("x/x")) CheckFail(location=..., message='General division is not linear (division of constants is)') """ From 579fdf6ef6ab473e9757e36935f763cc6b0bb8e1 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 3 Jun 2022 15:15:39 +0200 Subject: [PATCH 56/67] Disallow constants in programs in the syntax module --- probably/pgcl/syntax.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index a29e6c6..980d288 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -103,6 +103,9 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: """ Check if the given (well-typed) program is linear. + :param program: The program to check. It must not contain any constants + (see :py:mod:`probably.pgcl.substitute`). + .. doctest:: >>> from .parser import parse_pgcl @@ -133,7 +136,8 @@ def check_is_linear_expr(context: Optional[Program], expr: Expr) -> Optional[Che :param context: The context in which the expression is to be evaluated. Literals that are parameters according to this context are not considered variables. Pass None if - no context is required. + no context is required. If the context is not None, it must not contain any constants + (see :py:mod:`probably.pgcl.substitute`). :param expr: .. doctest:: @@ -153,6 +157,8 @@ def check_is_linear_expr(context: Optional[Program], expr: Expr) -> Optional[Che """ def _has_variable(expr: Expr) -> bool: + if isinstance(expr, VarExpr) and context is not None and expr.var in context.constants: + raise Exception("The context program must not contain constants") if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: return False if isinstance(expr, VarExpr) and (context is None or expr.var not in context.parameters): From 0a598c2ee3c93ab8e234dcc990ce7ffa2ebff9c1 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 3 Jun 2022 15:30:55 +0200 Subject: [PATCH 57/67] Make some variable names (true, false) illegal --- probably/pgcl/parser.py | 4 ++++ tests/{test_distributions.py => test_parser.py} | 10 ++++++++++ 2 files changed, 14 insertions(+) rename tests/{test_distributions.py => test_parser.py} (72%) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 7f05a0e..59fdd86 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -99,6 +99,8 @@ %import common.WS """ +_illegal_variable_names = {"true", "false"} + _OPERATOR_TABLE = [[infixl("or", "||")], [infixl("and", "&")], [infixl("leq", "<="), infixl("le", "<"), @@ -183,6 +185,8 @@ def _child_str(t: Tree, index: int) -> str: def _parse_var(t: Tree) -> Var: assert t.data == 'var' assert t.children[0].type == 'CNAME' # type: ignore + if t.children[0] in _illegal_variable_names: + raise SyntaxError(f"Illegal variable name: {t.children[0]}") return str(_child_str(t, 0)) diff --git a/tests/test_distributions.py b/tests/test_parser.py similarity index 72% rename from tests/test_distributions.py rename to tests/test_parser.py index 2e2e8ce..b954ec0 100644 --- a/tests/test_distributions.py +++ b/tests/test_parser.py @@ -1,5 +1,6 @@ from probably.pgcl.parser import parse_pgcl from probably.pgcl.ast import * +from pytest import raises def test_all_distributions(): program = parse_pgcl(""" @@ -23,3 +24,12 @@ def test_all_distributions(): LogDistExpr(NatLitExpr(1)), BernoulliExpr(NatLitExpr(1)), BinomialExpr(NatLitExpr(1), NatLitExpr(2))] + +def test_illegal_variable_names(): + illegal_names = {"true", "false"} + for name in illegal_names: + with raises(SyntaxError) as e: + parse_pgcl(f""" + nat {name} + """) + assert "Illegal variable name: " in e.value.msg From 12167a50e56ab6c1d88b5f9a57e930df6a848ac4 Mon Sep 17 00:00:00 2001 From: Legotier Date: Fri, 3 Jun 2022 16:23:43 +0200 Subject: [PATCH 58/67] Eliminate true and false from pgcl grammar --- probably/pgcl/parser.py | 5 ++--- tests/test_typechecking.py | 7 +++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 59fdd86..8f71ca8 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -85,7 +85,7 @@ | "∞" -> infinity | "\\infty" -> infinity - var: CNAME + var: /(?!true|false)([_a-zA-Z]\\w*)/ %ignore /#.*$/m @@ -93,7 +93,6 @@ %ignore WS %ignore ";" - %import common.CNAME %import common.INT %import common.FLOAT %import common.WS @@ -184,7 +183,7 @@ def _child_str(t: Tree, index: int) -> str: def _parse_var(t: Tree) -> Var: assert t.data == 'var' - assert t.children[0].type == 'CNAME' # type: ignore + #assert t.children[0].type == 'CNAME' # type: ignore (doesn't work anymore) if t.children[0] in _illegal_variable_names: raise SyntaxError(f"Illegal variable name: {t.children[0]}") return str(_child_str(t, 0)) diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py index 2e366d6..2a706b5 100644 --- a/tests/test_typechecking.py +++ b/tests/test_typechecking.py @@ -133,3 +133,10 @@ def test_for_instr_errors(): res = check_program(program) assert isinstance(res, CheckFail) assert "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?" in res.message + + program = parse_pgcl(""" + nat x + !Plot[x, true] + """) + res = check_program(program) + assert isinstance(res, CheckFail) From e606806dc1a1da24224ddc3d980061a0f2689941 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 8 Jun 2022 13:53:57 +0200 Subject: [PATCH 59/67] Revert "Eliminate true and false from pgcl grammar" This reverts commit 12167a50e56ab6c1d88b5f9a57e930df6a848ac4. --- probably/pgcl/parser.py | 5 +++-- tests/test_typechecking.py | 7 ------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 8f71ca8..59fdd86 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -85,7 +85,7 @@ | "∞" -> infinity | "\\infty" -> infinity - var: /(?!true|false)([_a-zA-Z]\\w*)/ + var: CNAME %ignore /#.*$/m @@ -93,6 +93,7 @@ %ignore WS %ignore ";" + %import common.CNAME %import common.INT %import common.FLOAT %import common.WS @@ -183,7 +184,7 @@ def _child_str(t: Tree, index: int) -> str: def _parse_var(t: Tree) -> Var: assert t.data == 'var' - #assert t.children[0].type == 'CNAME' # type: ignore (doesn't work anymore) + assert t.children[0].type == 'CNAME' # type: ignore if t.children[0] in _illegal_variable_names: raise SyntaxError(f"Illegal variable name: {t.children[0]}") return str(_child_str(t, 0)) diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py index 2a706b5..2e366d6 100644 --- a/tests/test_typechecking.py +++ b/tests/test_typechecking.py @@ -133,10 +133,3 @@ def test_for_instr_errors(): res = check_program(program) assert isinstance(res, CheckFail) assert "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?" in res.message - - program = parse_pgcl(""" - nat x - !Plot[x, true] - """) - res = check_program(program) - assert isinstance(res, CheckFail) From 4d4c322180f44e74da71ec248e4c87cec411a786 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 8 Jun 2022 13:56:24 +0200 Subject: [PATCH 60/67] Fix error message in check_is_linear_expr --- probably/pgcl/syntax.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index 980d288..e5fb4f2 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -158,7 +158,7 @@ def check_is_linear_expr(context: Optional[Program], expr: Expr) -> Optional[Che def _has_variable(expr: Expr) -> bool: if isinstance(expr, VarExpr) and context is not None and expr.var in context.constants: - raise Exception("The context program must not contain constants") + raise Exception(f"The expression must not contain constants. Found the constant '{expr.var}'") if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: return False if isinstance(expr, VarExpr) and (context is None or expr.var not in context.parameters): From 21ae3315cac8596e5e25564633cc562669991283 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 8 Jun 2022 14:24:36 +0200 Subject: [PATCH 61/67] Add assertion for illegal keyword to constructor of VarExpr --- probably/pgcl/ast/expressions.py | 3 +++ tests/test_parser.py | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/probably/pgcl/ast/expressions.py b/probably/pgcl/ast/expressions.py index 1c0d800..c76c88b 100644 --- a/probably/pgcl/ast/expressions.py +++ b/probably/pgcl/ast/expressions.py @@ -40,6 +40,9 @@ class VarExpr(ExprClass): """A variable is an expression.""" var: Var = attr.ib() + def __attrs_post_init__(self): + assert self.var not in {'true', 'false'} + def __str__(self) -> str: return self.var diff --git a/tests/test_parser.py b/tests/test_parser.py index b954ec0..5c0800f 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -25,7 +25,7 @@ def test_all_distributions(): BernoulliExpr(NatLitExpr(1)), BinomialExpr(NatLitExpr(1), NatLitExpr(2))] -def test_illegal_variable_names(): +def test_syntax_errors(): illegal_names = {"true", "false"} for name in illegal_names: with raises(SyntaxError) as e: @@ -33,3 +33,11 @@ def test_illegal_variable_names(): nat {name} """) assert "Illegal variable name: " in e.value.msg + + with raises(SyntaxError) as e: + parse_pgcl(f""" + nat x + nat y + !Plot[x,y,true] + """) + assert "Illegal variable name: " in e.value.msg From f1d923a17ae6e479ee14665c8610c88c5e4eb1b7 Mon Sep 17 00:00:00 2001 From: Legotier Date: Wed, 8 Jun 2022 14:32:09 +0200 Subject: [PATCH 62/67] Better error message for usage of true or false in plot instructions --- probably/pgcl/parser.py | 3 ++- tests/test_parser.py | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 59fdd86..0e054b2 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -441,7 +441,8 @@ def _parse_query(t: Tree): assert isinstance(lit, RealLitExpr) return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), prob=lit) - elif t.children[1].data in ('true', 'false'): + elif t.children[1].data in ('true', 'false') or \ + (t.children[1].data == 'var' and t.children[1].children[0] in ('true', 'false')): raise SyntaxError("Plot instruction does not support boolean operators") else: return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), diff --git a/tests/test_parser.py b/tests/test_parser.py index 5c0800f..407b249 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -40,4 +40,11 @@ def test_syntax_errors(): nat y !Plot[x,y,true] """) - assert "Illegal variable name: " in e.value.msg + assert "Plot instructions cannot handle boolean literals as arguments" in e.value.msg + + with raises(SyntaxError) as e: + parse_pgcl(f""" + nat x + !Plot[x,true] + """) + assert "Plot instruction does not support boolean operators" in e.value.msg From 79991b93ddeed87254bd69510d14a1b17c128b6e Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 9 Jun 2022 13:38:06 +0200 Subject: [PATCH 63/67] Allow variables in distribution parameters --- probably/pgcl/check.py | 18 +----------------- tests/test_typechecking.py | 10 ---------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 546077a..f33d322 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -19,7 +19,7 @@ ExpectationInstr, PrintInstr, OptimizationQuery, PlotInstr, LoopInstr, CUniformExpr, GeometricExpr, BernoulliExpr,PoissonExpr, LogDistExpr, BinomialExpr, IidSampleExpr, DistrExpr) -from .ast.walk import Walk, mut_expr_children, walk_expr +from .ast.walk import Walk, walk_expr _T = TypeVar('_T') @@ -199,23 +199,7 @@ def get_type(program: Program, def _check_distribution_arguments(prog: Program, expected_type: Type, *parameters: Tuple[Type, Expr]) -> Union[Type, CheckFail]: - # this function is copied from the syntax module, which is not pretty, but prevents cyclic imports - # also, it works only if constant substitution has been performed - # pylint: disable=duplicate-code - def _has_variable(expr: Expr) -> bool: - if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: - return False - if isinstance(expr, VarExpr) and expr.var not in prog.parameters: - return True - for child_ref in mut_expr_children(Mut.alloc(expr)): - if _has_variable(child_ref.val): - return True - return False - for expected_param_type, param_expr in parameters: - if _has_variable(param_expr): - return CheckFail(param_expr, "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?") - param_type = get_type(prog, param_expr) if isinstance(param_type, CheckFail): return param_type diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py index 2e366d6..489778a 100644 --- a/tests/test_typechecking.py +++ b/tests/test_typechecking.py @@ -123,13 +123,3 @@ def test_for_instr_errors(): x := 5 """) assert isinstance(check_program(program), CheckFail) - - program = parse_pgcl(""" - nat x - nat y - x := 5 - y := unif(10, x * 5 + 3) - """) - res = check_program(program) - assert isinstance(res, CheckFail) - assert "In distribution parameter expressions, no variables are allowed. - Forgot parameter declaration?" in res.message From 1777e884d5c4ae2f8e55923e251ed20ada85cac3 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 9 Jun 2022 13:46:42 +0200 Subject: [PATCH 64/67] Remove program config --- probably/pgcl/ast/__init__.py | 2 +- probably/pgcl/ast/program.py | 24 +++--------------------- probably/pgcl/check.py | 19 +++++-------------- probably/pgcl/parser.py | 8 ++++---- tests/test_typechecking.py | 7 ------- 5 files changed, 13 insertions(+), 47 deletions(-) diff --git a/probably/pgcl/ast/__init__.py b/probably/pgcl/ast/__init__.py index eb5ffd6..0384a61 100644 --- a/probably/pgcl/ast/__init__.py +++ b/probably/pgcl/ast/__init__.py @@ -126,5 +126,5 @@ OptimizationType, OptimizationQuery from .types import BoolType, NatType, RealType, Type, Bounds from .ast import Node, Var -from .program import Program, ProgramConfig +from .program import Program from .walk import * diff --git a/probably/pgcl/ast/program.py b/probably/pgcl/ast/program.py index 57e054c..72661a0 100644 --- a/probably/pgcl/ast/program.py +++ b/probably/pgcl/ast/program.py @@ -10,29 +10,12 @@ from .instructions import Instr from .ast import Var -@attr.s(frozen=True) -class ProgramConfig: - """ - Some compilation options for programs. Frozen after initialization (cannot - be modified). - - At the moment, we only have a flag for the type checker on which types are - allowed as program variables. - """ - - allow_real_vars: bool = attr.ib(default=True) - """ - Whether real numbers are allowed as program values (in computations, or as - variables). - """ - @attr.s class Program: """ A pGCL program has a bunch of variables with types, constants with defining expressions, and a list of instructions. """ - config: ProgramConfig = attr.ib(repr=False) declarations: List[Decl] = attr.ib(repr=False) """The original list of declarations.""" @@ -58,7 +41,7 @@ class Program: instructions: List[Instr] = attr.ib() @staticmethod - def from_parse(config: ProgramConfig, declarations: List[Decl], instructions: List[Instr]) -> Program: + def from_parse(declarations: List[Decl], instructions: List[Instr]) -> Program: """Create a program from the parser's output.""" variables: Dict[Var, Type] = {} constants: Dict[Var, Expr] = {} @@ -72,7 +55,7 @@ def from_parse(config: ProgramConfig, declarations: List[Decl], instructions: Li elif isinstance(decl, ParameterDecl): parameters[decl.var] = decl.typ - return Program(config, declarations, variables, constants, parameters, instructions) + return Program(declarations, variables, constants, parameters, instructions) def add_variable(self, var: Var, typ: Type): """ @@ -99,8 +82,7 @@ def to_skeleton(self) -> Program: >>> program.to_skeleton() Program(variables={'x': NatType(bounds=None), 'y': NatType(bounds=None)}, constants={}, parameters={}, instructions=[]) """ - return Program(config=self.config, - declarations=copy.copy(self.declarations), + return Program(declarations=copy.copy(self.declarations), parameters=copy.copy(self.parameters), variables=copy.copy(self.variables), constants=copy.copy(self.constants), diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index f33d322..671f59c 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -15,7 +15,7 @@ CategoricalExpr, ChoiceInstr, Decl, Expr, RealLitExpr, RealType, IfInstr, Instr, NatLitExpr, NatType, Node, Program, SkipInstr, Type, DUniformExpr, Unop, UnopExpr, Var, - VarExpr, WhileInstr, VarDecl, ObserveInstr, ProbabilityQueryInstr, + VarExpr, WhileInstr, ObserveInstr, ProbabilityQueryInstr, ExpectationInstr, PrintInstr, OptimizationQuery, PlotInstr, LoopInstr, CUniformExpr, GeometricExpr, BernoulliExpr,PoissonExpr, LogDistExpr, BinomialExpr, IidSampleExpr, DistrExpr) @@ -77,7 +77,7 @@ def get_type(program: Program, >>> from .ast import * >>> nat = NatLitExpr(10) - >>> program = Program(ProgramConfig(), list(), dict(), dict(), dict(), list()) + >>> program = Program(list(), dict(), dict(), dict(), list()) >>> get_type(program, BinopExpr(Binop.TIMES, nat, nat)) NatType(bounds=None) @@ -320,8 +320,7 @@ def _check_constant_declarations(program: Program) -> Optional[CheckFail]: def _check_declaration_list(program: Program) -> Optional[CheckFail]: """ - Check that all variables/constants are defined at most once and that real - variables are only declared if they are allowed in the config. + Check that all variables/constants are defined at most once. .. doctest:: @@ -333,14 +332,7 @@ def _check_declaration_list(program: Program) -> Optional[CheckFail]: declared: Dict[Var, Decl] = {} for decl in program.declarations: if declared.get(decl.var) is not None: - return CheckFail(decl, - "Already declared variable/constant before.") - if not program.config.allow_real_vars: - if isinstance(decl, VarDecl) and isinstance(decl.typ, RealType): - return CheckFail( - decl, - "Real number variables are not allowed by the program config." - ) + return CheckFail(decl, "Already declared variable/constant before.") declared[decl.var] = decl return None @@ -510,8 +502,7 @@ def check_expression(program, expr: Expr) -> Optional[CheckFail]: .. doctest:: - >>> from .ast import ProgramConfig - >>> program = Program(ProgramConfig(), list(), dict(), dict(), dict(), list()) + >>> program = Program(list(), dict(), dict(), dict(), list()) >>> check_expression(program, RealLitExpr("1.0")) CheckFail(location=..., message='A program expression may not return a probability.') """ diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 0e054b2..79565f6 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -454,15 +454,15 @@ def _parse_query(t: Tree): raise Exception(f'invalid AST: {t.data}') -def _parse_program(config: ProgramConfig, t: Tree) -> Program: +def _parse_program(t: Tree) -> Program: assert t.data == 'start' declarations = _parse_declarations(_child_tree(t, 0)) instructions = _parse_instrs(_child_tree(t, 1)) instructions.extend(_parse_queries(_child_tree(t, 2))) - return Program.from_parse(config, declarations, instructions) + return Program.from_parse(declarations, instructions) -def parse_pgcl(code: str, config: ProgramConfig = ProgramConfig()) -> Program: +def parse_pgcl(code: str) -> Program: """ Parse a pGCL program with an optional :py:class:`probably.pgcl.ast.ProgramConfig`. @@ -478,7 +478,7 @@ def parse_pgcl(code: str, config: ProgramConfig = ProgramConfig()) -> Program: AsgnInstr(lhs='x', rhs=CategoricalExpr(exprs=[(VarExpr('x'), RealLitExpr("1/3")), (VarExpr('y'), RealLitExpr("2/3"))])) """ tree = _PARSER.parse(code) - return _parse_program(config, tree) + return _parse_program(tree) def parse_expr(code: str) -> Expr: diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py index 489778a..f4c52c8 100644 --- a/tests/test_typechecking.py +++ b/tests/test_typechecking.py @@ -1,4 +1,3 @@ -from probably.pgcl.ast.program import ProgramConfig from probably.pgcl.ast.declarations import ConstDecl, VarDecl from probably.pgcl.ast.expressions import NatLitExpr, VarExpr from probably.pgcl.ast.types import NatType, RealType @@ -72,12 +71,6 @@ def test_for_declaration_errors(): assert check.location == ConstDecl("x", NatLitExpr(5)) assert "Already declared variable/constant before." in check.message - program = parse_pgcl("real x", ProgramConfig(allow_real_vars = False)) - check = check_program(program) - assert isinstance(check, CheckFail) - assert check.location == VarDecl("x", RealType()) - assert "Real number variables are not allowed by the program config." in check.message - def test_for_instr_errors(): program = parse_pgcl(""" From 3af0bf5abf47965f4adcd3d084341b1a7d1d1487 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 9 Jun 2022 14:24:53 +0200 Subject: [PATCH 65/67] Add typecheck for TickInstr and TickExpr --- probably/pgcl/check.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index 671f59c..c4ac8ef 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -18,7 +18,7 @@ VarExpr, WhileInstr, ObserveInstr, ProbabilityQueryInstr, ExpectationInstr, PrintInstr, OptimizationQuery, PlotInstr, LoopInstr, CUniformExpr, GeometricExpr, BernoulliExpr,PoissonExpr, - LogDistExpr, BinomialExpr, IidSampleExpr, DistrExpr) + LogDistExpr, BinomialExpr, IidSampleExpr, DistrExpr, TickInstr, TickExpr) from .ast.walk import Walk, walk_expr _T = TypeVar('_T') @@ -195,6 +195,14 @@ def get_type(program: Program, return CheckFail.expected_type_got(expr, typ, other_typ) return typ + if isinstance(expr, TickExpr): + typ = get_type(program, expr.expr, check=check) + if isinstance(typ, CheckFail): + return typ + if check and not is_compatible(NatType(bounds=None), typ): + return CheckFail.expected_type_got(expr.expr, NatType(None), typ) + return typ + raise Exception("unreachable") @@ -472,6 +480,7 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: return CheckFail.expected_type_got(instr.term_count, NatType(None), int_type) return None + if isinstance(instr, LoopInstr): int_type = get_type(program, instr.iterations, check=True) if isinstance(int_type, CheckFail): @@ -481,6 +490,14 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: int_type) return _check_instrs(program, instr.body) + if isinstance(instr, TickInstr): + typ = get_type(program, instr.expr, check=True) + if isinstance(typ, CheckFail): + return typ + if not is_compatible(NatType(bounds=None), typ): + return CheckFail.expected_type_got(instr.expr, NatType(None), typ) + return None + raise Exception("unreachable") # pylint: enable = too-many-statements From 2dd1aa3ff51b493ca241df78a7d20a374a6a0329 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 9 Jun 2022 14:40:06 +0200 Subject: [PATCH 66/67] Auto format --- probably/cmd.py | 3 +- probably/pgcl/__init__.py | 2 +- probably/pgcl/ast/__init__.py | 21 ++++--- probably/pgcl/ast/ast.py | 2 +- probably/pgcl/ast/declarations.py | 10 ++-- probably/pgcl/ast/expressions.py | 20 ++++--- probably/pgcl/ast/instructions.py | 14 +++-- probably/pgcl/ast/program.py | 15 +++-- probably/pgcl/ast/types.py | 1 + probably/pgcl/ast/walk.py | 2 +- probably/pgcl/check.py | 97 ++++++++++++++++++++----------- probably/pgcl/parser.py | 52 +++++++++++------ probably/pgcl/simplify.py | 12 ++-- probably/pgcl/substitute.py | 2 +- probably/pgcl/syntax.py | 18 ++++-- probably/pgcl/wp.py | 42 ++++++++----- probably/pysmt/context.py | 2 +- probably/pysmt/expr.py | 5 +- tests/test_loopfree_wp.py | 4 +- tests/test_one_loop_ert.py | 2 +- tests/test_one_loop_wp.py | 2 +- tests/test_operator_precedence.py | 28 ++++++--- tests/test_parser.py | 13 +++-- tests/test_pgcl.py | 1 + tests/test_substitution.py | 2 +- tests/test_typechecking.py | 1 + 26 files changed, 233 insertions(+), 140 deletions(-) diff --git a/probably/cmd.py b/probably/cmd.py index c287aa3..8f6eaa6 100644 --- a/probably/cmd.py +++ b/probably/cmd.py @@ -48,4 +48,5 @@ def main(input: IO): print(f"\t{res}") else: print("Program is linear.") - print("\Weakest pre-expectation transformer:", str(general_wp_transformer(program))) + print("\Weakest pre-expectation transformer:", + str(general_wp_transformer(program))) diff --git a/probably/pgcl/__init__.py b/probably/pgcl/__init__.py index b265b71..0640c28 100644 --- a/probably/pgcl/__init__.py +++ b/probably/pgcl/__init__.py @@ -51,6 +51,6 @@ """ from .ast import * +from .ast.walk import * from .check import * from .parser import parse_pgcl -from .ast.walk import * diff --git a/probably/pgcl/ast/__init__.py b/probably/pgcl/ast/__init__.py index 0384a61..5012a28 100644 --- a/probably/pgcl/ast/__init__.py +++ b/probably/pgcl/ast/__init__.py @@ -117,14 +117,19 @@ .. autoclass:: Node """ -from .declarations import VarDecl, ConstDecl, ParameterDecl, Decl -from .expressions import VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, BinopExpr, UnopExpr, \ - SubstExpr, CategoricalExpr, TickExpr, DUniformExpr, CUniformExpr, GeometricExpr, PoissonExpr, LogDistExpr, \ - BinomialExpr, BernoulliExpr, Binop, Unop, Expr, ExprClass, DistrExpr, IidSampleExpr, expr_str_parens -from .instructions import ProbabilityQueryInstr, ExpectationInstr, PlotInstr, SkipInstr, WhileInstr, IfInstr,\ - AsgnInstr, LoopInstr, ChoiceInstr, TickInstr, ObserveInstr, Instr, Query, InstrClass, PrintInstr,\ - OptimizationType, OptimizationQuery -from .types import BoolType, NatType, RealType, Type, Bounds from .ast import Node, Var +from .declarations import ConstDecl, Decl, ParameterDecl, VarDecl +from .expressions import (BernoulliExpr, BinomialExpr, Binop, BinopExpr, + BoolLitExpr, CategoricalExpr, CUniformExpr, + DistrExpr, DUniformExpr, Expr, ExprClass, + GeometricExpr, IidSampleExpr, LogDistExpr, + NatLitExpr, PoissonExpr, RealLitExpr, SubstExpr, + TickExpr, Unop, UnopExpr, VarExpr, expr_str_parens) +from .instructions import (AsgnInstr, ChoiceInstr, ExpectationInstr, IfInstr, + Instr, InstrClass, LoopInstr, ObserveInstr, + OptimizationQuery, OptimizationType, PlotInstr, + PrintInstr, ProbabilityQueryInstr, Query, SkipInstr, + TickInstr, WhileInstr) from .program import Program +from .types import BoolType, Bounds, NatType, RealType, Type from .walk import * diff --git a/probably/pgcl/ast/ast.py b/probably/pgcl/ast/ast.py index 9b50cff..64ce066 100644 --- a/probably/pgcl/ast/ast.py +++ b/probably/pgcl/ast/ast.py @@ -1,6 +1,6 @@ from abc import ABC -import attr +import attr Var = str diff --git a/probably/pgcl/ast/declarations.py b/probably/pgcl/ast/declarations.py index a7d5e43..14c382f 100644 --- a/probably/pgcl/ast/declarations.py +++ b/probably/pgcl/ast/declarations.py @@ -1,16 +1,17 @@ from __future__ import annotations -from typing import Union from abc import abstractmethod +from typing import Union + import attr -from .expressions import Expr + from .ast import Node, Var -from .types import Type, BoolType, NatType, RealType +from .expressions import Expr +from .types import BoolType, NatType, RealType, Type class DeclClass(Node): """Superclass for all declarations. See :obj:`Decl`.""" - @abstractmethod def __str__(self) -> str: """ @@ -52,6 +53,7 @@ class ConstDecl(DeclClass): def __str__(self) -> str: return f"const {self.var} := {self.value};" + @attr.s class ParameterDecl(DeclClass): """ A parameter declaration with a name and a type.""" diff --git a/probably/pgcl/ast/expressions.py b/probably/pgcl/ast/expressions.py index c76c88b..f9d01e6 100644 --- a/probably/pgcl/ast/expressions.py +++ b/probably/pgcl/ast/expressions.py @@ -1,16 +1,18 @@ from __future__ import annotations +import itertools +from abc import abstractmethod from decimal import Decimal -from typing import Any, Union, Sequence, Optional, List, Tuple, Dict +from enum import Enum, auto from fractions import Fraction -from enum import auto, Enum -import itertools from functools import reduce +from typing import Any, Dict, List, Optional, Sequence, Tuple, Union -from abc import abstractmethod import attr + from .ast import Node, Var + class ExprClass(Node): """ Superclass for all expressions. @@ -75,7 +77,7 @@ def __repr__(self) -> str: def _validate_real_lit_value(_object: RealLitExpr, _attribute: Any, - value: Any): + value: Any): if not isinstance(value, Decimal) and not isinstance(value, Fraction): raise ValueError( f"Expected a Decimal or Fraction value, got: {value!r}") @@ -296,7 +298,8 @@ def distribution(self) -> List[Tuple[RealLitExpr, NatLitExpr]]: probabilities. For the uniform distribution, all probabilites are equal to :math:`\frac{1}{\text{end} - \text{start} + 1}`. """ - if isinstance(self.start, NatLitExpr) and isinstance(self.end, NatLitExpr): + if isinstance(self.start, NatLitExpr) and isinstance( + self.end, NatLitExpr): width = self.end.value - self.start.value + 1 prob = RealLitExpr(Fraction(1, width)) return [(prob, NatLitExpr(i)) @@ -493,11 +496,10 @@ def expr_str_parens(expr: ExprClass) -> str: return f'({expr})' -DistrExpr = Union[DUniformExpr, CUniformExpr, BernoulliExpr, GeometricExpr, PoissonExpr, LogDistExpr, BinomialExpr, - IidSampleExpr] +DistrExpr = Union[DUniformExpr, CUniformExpr, BernoulliExpr, GeometricExpr, + PoissonExpr, LogDistExpr, BinomialExpr, IidSampleExpr] """ A type combining all sampling expressions""" - Expr = Union[VarExpr, BoolLitExpr, NatLitExpr, RealLitExpr, UnopExpr, BinopExpr, CategoricalExpr, SubstExpr, TickExpr, DistrExpr] """Union type for all expression objects. See :class:`ExprClass` for use with isinstance.""" diff --git a/probably/pgcl/ast/instructions.py b/probably/pgcl/ast/instructions.py index 76ef34a..331a3a4 100644 --- a/probably/pgcl/ast/instructions.py +++ b/probably/pgcl/ast/instructions.py @@ -1,13 +1,15 @@ from __future__ import annotations from abc import abstractmethod +from enum import Enum, auto from textwrap import indent from typing import List, Union -from enum import Enum, auto import attr -from .expressions import NatLitExpr, VarExpr, RealLitExpr, Expr + from .ast import Node, Var +from .expressions import Expr, NatLitExpr, RealLitExpr, VarExpr + class InstrClass(Node): """Superclass for all instructions. See :obj:`Instr`.""" @@ -193,10 +195,10 @@ def __str__(self) -> str: return f"!Plot[{output}]" -Query = Union[ProbabilityQueryInstr, ExpectationInstr, PlotInstr, PrintInstr, OptimizationQuery] +Query = Union[ProbabilityQueryInstr, ExpectationInstr, PlotInstr, PrintInstr, + OptimizationQuery] """Union type for all query objects. See :class:`QueryInstr` for use with isinstance.""" - -Instr = Union[SkipInstr, WhileInstr, IfInstr, AsgnInstr, ChoiceInstr, LoopInstr, - TickInstr, ObserveInstr, Query] +Instr = Union[SkipInstr, WhileInstr, IfInstr, AsgnInstr, ChoiceInstr, + LoopInstr, TickInstr, ObserveInstr, Query] """Union type for all instruction objects. See :class:`InstrClass` for use with isinstance.""" diff --git a/probably/pgcl/ast/program.py b/probably/pgcl/ast/program.py index 72661a0..145c1da 100644 --- a/probably/pgcl/ast/program.py +++ b/probably/pgcl/ast/program.py @@ -1,14 +1,15 @@ from __future__ import annotations -from typing import List, Dict, Any import copy +from typing import Any, Dict, List import attr -from .types import Type -from .declarations import Decl, ParameterDecl, VarDecl, ConstDecl + +from .ast import Var +from .declarations import ConstDecl, Decl, ParameterDecl, VarDecl from .expressions import Expr from .instructions import Instr -from .ast import Var +from .types import Type @attr.s @@ -41,7 +42,8 @@ class Program: instructions: List[Instr] = attr.ib() @staticmethod - def from_parse(declarations: List[Decl], instructions: List[Instr]) -> Program: + def from_parse(declarations: List[Decl], + instructions: List[Instr]) -> Program: """Create a program from the parser's output.""" variables: Dict[Var, Type] = {} constants: Dict[Var, Expr] = {} @@ -55,7 +57,8 @@ def from_parse(declarations: List[Decl], instructions: List[Instr]) -> Program: elif isinstance(decl, ParameterDecl): parameters[decl.var] = decl.typ - return Program(declarations, variables, constants, parameters, instructions) + return Program(declarations, variables, constants, parameters, + instructions) def add_variable(self, var: Var, typ: Type): """ diff --git a/probably/pgcl/ast/types.py b/probably/pgcl/ast/types.py index 4550a83..6ad597d 100644 --- a/probably/pgcl/ast/types.py +++ b/probably/pgcl/ast/types.py @@ -1,6 +1,7 @@ from __future__ import annotations from typing import Optional, Union + import attr from .ast import Node diff --git a/probably/pgcl/ast/walk.py b/probably/pgcl/ast/walk.py index 23791f2..a4c673f 100644 --- a/probably/pgcl/ast/walk.py +++ b/probably/pgcl/ast/walk.py @@ -34,7 +34,7 @@ """ from enum import Enum, auto -from typing import Callable, Iterable, TypeVar, List +from typing import Callable, Iterable, List, TypeVar from probably.util.ref import Mut diff --git a/probably/pgcl/check.py b/probably/pgcl/check.py index c4ac8ef..43169cf 100644 --- a/probably/pgcl/check.py +++ b/probably/pgcl/check.py @@ -4,21 +4,23 @@ ------------- """ -from typing import Dict, Iterable, List, Optional, TypeVar, Union, get_args, Tuple - import logging +from typing import (Dict, Iterable, List, Optional, Tuple, TypeVar, Union, + get_args) + import attr from probably.util.ref import Mut -from .ast import (AsgnInstr, Binop, BinopExpr, BoolLitExpr, BoolType, - CategoricalExpr, ChoiceInstr, Decl, Expr, RealLitExpr, - RealType, IfInstr, Instr, NatLitExpr, NatType, Node, - Program, SkipInstr, Type, DUniformExpr, Unop, UnopExpr, Var, - VarExpr, WhileInstr, ObserveInstr, ProbabilityQueryInstr, - ExpectationInstr, PrintInstr, OptimizationQuery, PlotInstr, - LoopInstr, CUniformExpr, GeometricExpr, BernoulliExpr,PoissonExpr, - LogDistExpr, BinomialExpr, IidSampleExpr, DistrExpr, TickInstr, TickExpr) +from .ast import (AsgnInstr, BernoulliExpr, BinomialExpr, Binop, BinopExpr, + BoolLitExpr, BoolType, CategoricalExpr, ChoiceInstr, + CUniformExpr, Decl, DistrExpr, DUniformExpr, + ExpectationInstr, Expr, GeometricExpr, IfInstr, + IidSampleExpr, Instr, LogDistExpr, LoopInstr, NatLitExpr, + NatType, Node, ObserveInstr, OptimizationQuery, PlotInstr, + PoissonExpr, PrintInstr, ProbabilityQueryInstr, Program, + RealLitExpr, RealType, SkipInstr, TickExpr, TickInstr, Type, + Unop, UnopExpr, Var, VarExpr, WhileInstr) from .ast.walk import Walk, walk_expr _T = TypeVar('_T') @@ -155,8 +157,8 @@ def get_type(program: Program, return CheckFail.expected_numeric_got(expr.lhs, lhs_typ) if check and expr.operator in [ - Binop.LEQ, Binop.LT, Binop.GEQ, Binop.GT, Binop.EQ, Binop.PLUS, Binop.MINUS, - Binop.TIMES, Binop.MODULO, Binop.POWER + Binop.LEQ, Binop.LT, Binop.GEQ, Binop.GT, Binop.EQ, Binop.PLUS, + Binop.MINUS, Binop.TIMES, Binop.MODULO, Binop.POWER ]: rhs_typ = get_type(program, expr.rhs, check=check) if isinstance(rhs_typ, CheckFail): @@ -168,11 +170,15 @@ def get_type(program: Program, return CheckFail.expected_type_got(expr, lhs_typ, rhs_typ) # binops that take numeric operands and return a boolean - if expr.operator in [Binop.LEQ, Binop.LT, Binop.EQ, Binop.GEQ, Binop.GT]: + if expr.operator in [ + Binop.LEQ, Binop.LT, Binop.EQ, Binop.GEQ, Binop.GT + ]: return BoolType() # binops that take numeric operands and return a numeric value - if expr.operator in [Binop.PLUS, Binop.MINUS, Binop.TIMES, Binop.MODULO, Binop.POWER]: + if expr.operator in [ + Binop.PLUS, Binop.MINUS, Binop.TIMES, Binop.MODULO, Binop.POWER + ]: # intentionally lose the bounds on NatType (see NatType documentation) if isinstance(lhs_typ, NatType) and lhs_typ.bounds is not None: return NatType(bounds=None) @@ -206,42 +212,54 @@ def get_type(program: Program, raise Exception("unreachable") -def _check_distribution_arguments(prog: Program, expected_type: Type, *parameters: Tuple[Type, Expr]) -> Union[Type, CheckFail]: +def _check_distribution_arguments( + prog: Program, expected_type: Type, + *parameters: Tuple[Type, Expr]) -> Union[Type, CheckFail]: for expected_param_type, param_expr in parameters: param_type = get_type(prog, param_expr) if isinstance(param_type, CheckFail): return param_type elif not is_compatible(expected_param_type, param_type): - return CheckFail.expected_type_got(param_expr, expected_param_type, param_type) + return CheckFail.expected_type_got(param_expr, expected_param_type, + param_type) return expected_type -def _get_distribution_type(prog: Program, expr: Expr, check: bool = True) -> Union[Type, CheckFail]: - assert isinstance(expr, get_args(DistrExpr)), f"Expression must be a distribution expression, was {type(expr)}." +def _get_distribution_type(prog: Program, + expr: Expr, + check: bool = True) -> Union[Type, CheckFail]: + assert isinstance( + expr, get_args(DistrExpr) + ), f"Expression must be a distribution expression, was {type(expr)}." if isinstance(expr, DUniformExpr): - return _check_distribution_arguments(prog, NatType(bounds=None), (NatType(bounds=None), expr.start), - (NatType(bounds=None), expr.end) - ) + return _check_distribution_arguments( + prog, NatType(bounds=None), (NatType(bounds=None), expr.start), + (NatType(bounds=None), expr.end)) elif isinstance(expr, CUniformExpr): - raise NotImplementedError("Currently continuous distributions are not supported.") + raise NotImplementedError( + "Currently continuous distributions are not supported.") elif isinstance(expr, GeometricExpr): - return _check_distribution_arguments(prog, NatType(bounds=None), (RealType(), expr.param)) + return _check_distribution_arguments(prog, NatType(bounds=None), + (RealType(), expr.param)) elif isinstance(expr, BernoulliExpr): - return _check_distribution_arguments(prog, NatType(bounds=None), (RealType(), expr.param)) + return _check_distribution_arguments(prog, NatType(bounds=None), + (RealType(), expr.param)) elif isinstance(expr, PoissonExpr): - return _check_distribution_arguments(prog, NatType(bounds=None), (NatType(bounds=None), expr.param)) + return _check_distribution_arguments( + prog, NatType(bounds=None), (NatType(bounds=None), expr.param)) elif isinstance(expr, LogDistExpr): - return _check_distribution_arguments(prog, NatType(bounds=None), (RealType(), expr.param)) + return _check_distribution_arguments(prog, NatType(bounds=None), + (RealType(), expr.param)) elif isinstance(expr, BinomialExpr): - return _check_distribution_arguments(prog, NatType(bounds=None), (NatType(bounds=None), expr.n), - (RealType(), expr.p) - ) + return _check_distribution_arguments(prog, NatType(bounds=None), + (NatType(bounds=None), expr.n), + (RealType(), expr.p)) if isinstance(expr, IidSampleExpr): if isinstance(expr.sampling_dist, get_args(DistrExpr)): return _get_distribution_type(prog, expr.sampling_dist, check) @@ -251,7 +269,9 @@ def _get_distribution_type(prog: Program, expr: Expr, check: bool = True) -> Uni safe = check_expression(prog, expr.sampling_dist) if isinstance(safe, CheckFail): return safe - logging.getLogger("probably").warning("Probably does not check whether expressions used in DistrExprs are actually valid PGFs (%s).", expr) + logging.getLogger("probably").warning( + "Probably does not check whether expressions used in DistrExprs are actually valid PGFs (%s).", + expr) return NatType(bounds=None) raise Exception("unreachable") @@ -340,7 +360,8 @@ def _check_declaration_list(program: Program) -> Optional[CheckFail]: declared: Dict[Var, Decl] = {} for decl in program.declarations: if declared.get(decl.var) is not None: - return CheckFail(decl, "Already declared variable/constant before.") + return CheckFail(decl, + "Already declared variable/constant before.") declared[decl.var] = decl return None @@ -435,7 +456,8 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: cond_type = get_type(program, instr.expr) if isinstance(cond_type, CheckFail): return cond_type - if not (is_compatible(BoolType(), cond_type) or is_compatible(NatType(None), cond_type)): + if not (is_compatible(BoolType(), cond_type) + or is_compatible(NatType(None), cond_type)): return CheckFail.expected_type_got(instr.expr, BoolType(), cond_type) return None @@ -454,7 +476,10 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: if isinstance(expr_type, CheckFail): return expr_type if instr.parameter not in program.parameters: - return CheckFail(instr, f"In optimization queries, the variable can only be a program parameter, was {instr.parameter}.") + return CheckFail( + instr, + f"In optimization queries, the variable can only be a program parameter, was {instr.parameter}." + ) return None if isinstance(instr, PlotInstr): @@ -477,8 +502,8 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: if isinstance(int_type, CheckFail): return int_type if not is_compatible(NatType(bounds=None), int_type): - return CheckFail.expected_type_got(instr.term_count, NatType(None), - int_type) + return CheckFail.expected_type_got(instr.term_count, + NatType(None), int_type) return None if isinstance(instr, LoopInstr): @@ -499,6 +524,8 @@ def check_instr(program: Program, instr: Instr) -> Optional[CheckFail]: return None raise Exception("unreachable") + + # pylint: enable = too-many-statements diff --git a/probably/pgcl/parser.py b/probably/pgcl/parser.py index 79565f6..dd56adf 100644 --- a/probably/pgcl/parser.py +++ b/probably/pgcl/parser.py @@ -19,8 +19,8 @@ """ import textwrap from decimal import Decimal -from typing import List, Optional, Callable, Dict, Tuple, Union from fractions import Fraction +from typing import Callable, Dict, List, Optional, Tuple, Union import attr from lark import Lark, Tree @@ -28,7 +28,7 @@ from probably.pgcl.ast import * from probably.pgcl.ast.walk import Walk, walk_expr from probably.util.lark_expr_parser import (atom, build_expr_parser, infixl, - prefix, infixr) + infixr, prefix) from probably.util.ref import Mut _PGCL_GRAMMAR = """ @@ -102,13 +102,19 @@ _illegal_variable_names = {"true", "false"} _OPERATOR_TABLE = [[infixl("or", "||")], [infixl("and", "&")], - [infixl("leq", "<="), - infixl("le", "<"), - infixl("ge", ">"), - infixl("geq", ">="), - infixl("eq", "=")], - [infixl("plus", "+"), infixl("minus", "-")], [infixl("likely", ":")], - [infixl("times", "*"), infixl("divide", "/"), infixl("mod", "%")], [infixr("power", "^")], + [ + infixl("leq", "<="), + infixl("le", "<"), + infixl("ge", ">"), + infixl("geq", ">="), + infixl("eq", "=") + ], [infixl("plus", "+"), + infixl("minus", "-")], [infixl("likely", ":")], + [ + infixl("times", "*"), + infixl("divide", "/"), + infixl("mod", "%") + ], [infixr("power", "^")], [ prefix("neg", "not "), atom("parens", '"(" expression ")"'), @@ -135,7 +141,6 @@ def _doc_parser_grammar(): _doc_parser_grammar.__doc__ = "The Lark grammar for pGCL::\n" + _PGCL_GRAMMAR + "\n\nThis function only exists for documentation purposes and should never be called in code." - # All known distribution types. Dictionary entry contains the token name as key. # Also the value of a given gey is a tuple consisting of the number of parameters and the Class name (constructor call) distributions: Dict[str, Tuple[int, Callable]] = { @@ -321,7 +326,8 @@ def _parse_rvalue(t: Tree) -> Expr: return _parse_distribution(t) elif t.data == "iid": - return IidSampleExpr(_parse_rvalue(_child_tree(t, 0)), VarExpr(_parse_var(_child_tree(t, 1)))) + return IidSampleExpr(_parse_rvalue(_child_tree(t, 0)), + VarExpr(_parse_var(_child_tree(t, 1)))) # otherwise we have an expression, but it may contain _LikelyExprs, which we # need to parse. @@ -376,7 +382,8 @@ def _parse_instr(t: Tree) -> Instr: return ObserveInstr(_parse_expr(_child_tree(t, 0))) elif t.data == 'loop': assert isinstance(t.children[0], str) - return LoopInstr(NatLitExpr(value=int(t.children[0])), _parse_instrs(_child_tree(t, 1))) + return LoopInstr(NatLitExpr(value=int(t.children[0])), + _parse_instrs(_child_tree(t, 1))) else: raise Exception(f'invalid AST: {t.data}') @@ -405,14 +412,19 @@ def _parse_query(t: Tree): elif mode == "MIN": opt_type = OptimizationType.MINIMIZE else: - raise SyntaxError(f"The optimization can either be 'MAX' or 'MIN', but not {mode}") + raise SyntaxError( + f"The optimization can either be 'MAX' or 'MIN', but not {mode}" + ) parameter = _parse_var(_child_tree(t, 1)) - return OptimizationQuery(_parse_expr(_child_tree(t, 0)), parameter, opt_type) + return OptimizationQuery(_parse_expr(_child_tree(t, 0)), parameter, + opt_type) elif t.data == "plot": if len(t.children) == 3: lit = _parse_literal(_child_tree(t, 2)) if isinstance(lit, BoolLitExpr): - raise SyntaxError("Plot instructions cannot handle boolean literals as arguments") + raise SyntaxError( + "Plot instructions cannot handle boolean literals as arguments" + ) assert isinstance(t.children[2], Tree) if t.children[2].data in ('real', 'infinity'): assert isinstance(lit, RealLitExpr) @@ -443,11 +455,13 @@ def _parse_query(t: Tree): prob=lit) elif t.children[1].data in ('true', 'false') or \ (t.children[1].data == 'var' and t.children[1].children[0] in ('true', 'false')): - raise SyntaxError("Plot instruction does not support boolean operators") + raise SyntaxError( + "Plot instruction does not support boolean operators") else: - return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))), - VarExpr(_parse_var(_child_tree(t, 1))), - ) + return PlotInstr( + VarExpr(_parse_var(_child_tree(t, 0))), + VarExpr(_parse_var(_child_tree(t, 1))), + ) else: return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0)))) else: diff --git a/probably/pgcl/simplify.py b/probably/pgcl/simplify.py index 003b61f..49ab36c 100644 --- a/probably/pgcl/simplify.py +++ b/probably/pgcl/simplify.py @@ -8,18 +8,17 @@ This is the right place for you! """ -from typing import Dict, List, Union, Optional +from typing import Dict, List, Optional, Union import attr from probably.util.ref import Mut from .ast import VarExpr # pylint:disable=unused-import -from .ast import (Binop, BinopExpr, BoolLitExpr, Expr, RealLitExpr, RealType, - NatLitExpr, NatType, Program, SubstExpr, TickExpr, Unop, - UnopExpr, Var, expr_str_parens) +from .ast import (Binop, BinopExpr, BoolLitExpr, Expr, NatLitExpr, NatType, + Program, RealLitExpr, RealType, SubstExpr, TickExpr, Unop, + UnopExpr, Var, Walk, expr_str_parens, walk_expr) from .check import CheckFail, get_type -from .ast import Walk, walk_expr from .wp import ExpectationTransformer @@ -351,7 +350,8 @@ def recurse(expr: Expr) -> Union[SnfExpectationTransformer, CheckFail]: # n] * 1/2 * ((𝑋)[r/0, x/x + 0] + tick(1))`. if isinstance(expr.rhs, TickExpr): for value in lhs: - value.ticks = TickExpr(simplifying_plus(value.ticks.expr, expr.rhs.expr)) + value.ticks = TickExpr( + simplifying_plus(value.ticks.expr, expr.rhs.expr)) return lhs else: rhs = recurse(expr.rhs) diff --git a/probably/pgcl/substitute.py b/probably/pgcl/substitute.py index 4b047d3..0c99170 100644 --- a/probably/pgcl/substitute.py +++ b/probably/pgcl/substitute.py @@ -94,7 +94,7 @@ from .ast import Expr, ExprClass, Program, SubstExpr, Var, VarExpr from .ast.walk import (Walk, mut_expr_children, mut_instr_exprs, walk_expr, - walk_instrs) + walk_instrs) @attr.s(hash=True) diff --git a/probably/pgcl/syntax.py b/probably/pgcl/syntax.py index e5fb4f2..f7c155c 100644 --- a/probably/pgcl/syntax.py +++ b/probably/pgcl/syntax.py @@ -95,8 +95,9 @@ from .ast import (AsgnInstr, Binop, BinopExpr, Expr, Instr, Program, Unop, UnopExpr, VarExpr, WhileInstr) +from .ast.walk import (Walk, instr_exprs, mut_expr_children, walk_expr, + walk_instrs) from .check import CheckFail -from .ast.walk import Walk, instr_exprs, mut_expr_children, walk_expr, walk_instrs def check_is_linear_program(program: Program) -> Optional[CheckFail]: @@ -128,7 +129,8 @@ def check_is_linear_program(program: Program) -> Optional[CheckFail]: return None -def check_is_linear_expr(context: Optional[Program], expr: Expr) -> Optional[CheckFail]: +def check_is_linear_expr(context: Optional[Program], + expr: Expr) -> Optional[CheckFail]: """ Linear expressions do not multiply variables with each other. However, they may contain multiplication with constants or Iverson brackets. @@ -155,13 +157,17 @@ def check_is_linear_expr(context: Optional[Program], expr: Expr) -> Optional[Che >>> check_is_linear_expr(None, parse_expectation("x/x")) CheckFail(location=..., message='General division is not linear (division of constants is)') """ - def _has_variable(expr: Expr) -> bool: - if isinstance(expr, VarExpr) and context is not None and expr.var in context.constants: - raise Exception(f"The expression must not contain constants. Found the constant '{expr.var}'") + if isinstance( + expr, VarExpr + ) and context is not None and expr.var in context.constants: + raise Exception( + f"The expression must not contain constants. Found the constant '{expr.var}'" + ) if isinstance(expr, UnopExpr) and expr.operator == Unop.IVERSON: return False - if isinstance(expr, VarExpr) and (context is None or expr.var not in context.parameters): + if isinstance(expr, VarExpr) and (context is None or expr.var + not in context.parameters): return True for child_ref in mut_expr_children(Mut.alloc(expr)): if _has_variable(child_ref.val): diff --git a/probably/pgcl/wp.py b/probably/pgcl/wp.py index 08bd223..0cc9780 100644 --- a/probably/pgcl/wp.py +++ b/probably/pgcl/wp.py @@ -88,12 +88,12 @@ from probably.util.ref import Mut from .ast import (AsgnInstr, Binop, BinopExpr, CategoricalExpr, ChoiceInstr, - Expr, RealLitExpr, IfInstr, Instr, Program, - SkipInstr, SubstExpr, TickExpr, TickInstr, DUniformExpr, Unop, - UnopExpr, Var, VarExpr, WhileInstr) + DUniformExpr, Expr, IfInstr, Instr, Program, RealLitExpr, + SkipInstr, SubstExpr, TickExpr, TickInstr, Unop, UnopExpr, + Var, VarExpr, WhileInstr) +from .ast.walk import Walk, walk_expr from .substitute import substitute_expr from .syntax import check_is_one_big_loop -from .ast.walk import Walk, walk_expr def loopfree_wp(instr: Union[Instr, Sequence[Instr]], @@ -182,9 +182,8 @@ def loopfree_wp(instr: Union[Instr, Sequence[Instr]], lhs_block = loopfree_wp(instr.lhs, postexpectation) rhs_block = loopfree_wp(instr.rhs, deepcopy(postexpectation)) lhs = BinopExpr(Binop.TIMES, lhs_block, instr.prob) - rhs = BinopExpr( - Binop.TIMES, rhs_block, - BinopExpr(Binop.MINUS, RealLitExpr("1.0"), instr.prob)) + rhs = BinopExpr(Binop.TIMES, rhs_block, + BinopExpr(Binop.MINUS, RealLitExpr("1.0"), instr.prob)) return BinopExpr(Binop.PLUS, lhs, rhs) if isinstance(instr, TickInstr): @@ -221,6 +220,7 @@ class ExpectationTransformer: def _expectation_ref(self) -> Mut[Expr]: def write_expectation(value): self.expectation = value + return Mut(lambda: self.expectation, write_expectation) def substitute(self) -> 'ExpectationTransformer': @@ -231,10 +231,11 @@ def substitute(self) -> 'ExpectationTransformer': Returns ``self`` for convenience. """ - substitute_expr(self._expectation_ref, symbolic=frozenset([self.variable])) + substitute_expr(self._expectation_ref, + symbolic=frozenset([self.variable])) return self - def apply(self, expectation: Expr, substitute: bool=True) -> Expr: + def apply(self, expectation: Expr, substitute: bool = True) -> Expr: """ Transform the given expectation with this expectation transformer. @@ -278,7 +279,6 @@ def apply(self, expectation: Expr, substitute: bool=True) -> Expr: substitute_expr(self._expectation_ref, deepcopy=True) return self.expectation - def __str__(self) -> str: return f"λ{self.variable}. {self.expectation}" @@ -356,7 +356,7 @@ def one_loop_wp_transformer( program: Program, instr: Union[Instr, List[Instr]], variable: str = '𝑋', - substitute: bool=True) -> LoopExpectationTransformer: + substitute: bool = True) -> LoopExpectationTransformer: """ Calculate the weakest pre-expectation transformer of a program that consists of exactly one while loop with some optional assignments at the beginning. @@ -385,7 +385,8 @@ def one_loop_wp_transformer( substitute: Whether to call :meth:`ExpectationTransformer.substitute` on the ``body``. """ # avoid a cyclic import - from .simplify import simplifying_neg # pylint: disable=import-outside-toplevel,cyclic-import + from .simplify import \ + simplifying_neg # pylint: disable=import-outside-toplevel,cyclic-import # extract assignments and the loop from the program instrs = list(instr) if isinstance(instr, list) else [instr] @@ -400,8 +401,13 @@ def one_loop_wp_transformer( assert isinstance(loop, WhileInstr), err # weakest pre-expectation of the loop body - body = loopfree_wp_transformer(program, loop.body, variable=variable, substitute=substitute) - body.expectation = BinopExpr(Binop.TIMES, UnopExpr(Unop.IVERSON, loop.cond), body.expectation) + body = loopfree_wp_transformer(program, + loop.body, + variable=variable, + substitute=substitute) + body.expectation = BinopExpr(Binop.TIMES, UnopExpr(Unop.IVERSON, + loop.cond), + body.expectation) # weakest pre-expectation of the done term done = UnopExpr(Unop.IVERSON, simplifying_neg(loop.cond)) @@ -409,7 +415,9 @@ def one_loop_wp_transformer( return LoopExpectationTransformer(init, body, done) -def general_wp_transformer(program: Program, substitute: bool=True) -> LoopExpectationTransformer: +def general_wp_transformer( + program: Program, + substitute: bool = True) -> LoopExpectationTransformer: """ Calculate the weakest pre-expectation transformer for any pGCL program. For programs that consist of one big loop (see :ref:`one_big_loop`), @@ -438,4 +446,6 @@ def general_wp_transformer(program: Program, substitute: bool=True) -> LoopExpec if one_big_loop_err is None: return one_loop_wp_transformer(program, program.instructions) program = program_one_big_loop(program, pc_var='pc') - return one_loop_wp_transformer(program, program.instructions, substitute=substitute) + return one_loop_wp_transformer(program, + program.instructions, + substitute=substitute) diff --git a/probably/pysmt/context.py b/probably/pysmt/context.py index 97c3c79..ab5c32e 100644 --- a/probably/pysmt/context.py +++ b/probably/pysmt/context.py @@ -15,7 +15,7 @@ from pysmt.shortcuts import Symbol from pysmt.typing import BOOL, INT, REAL -from probably.pgcl.ast import BoolType, RealType, NatType, Program, Type, Var +from probably.pgcl.ast import BoolType, NatType, Program, RealType, Type, Var def _translate_type(typ: Type): diff --git a/probably/pysmt/expr.py b/probably/pysmt/expr.py index 8595fee..a4ff020 100644 --- a/probably/pysmt/expr.py +++ b/probably/pysmt/expr.py @@ -15,9 +15,8 @@ get_type) from pysmt.typing import INT -from probably.pgcl.ast import (Binop, BinopExpr, BoolLitExpr, Expr, - RealLitExpr, NatLitExpr, SubstExpr, Unop, - UnopExpr, VarExpr) +from probably.pgcl.ast import (Binop, BinopExpr, BoolLitExpr, Expr, NatLitExpr, + RealLitExpr, SubstExpr, Unop, UnopExpr, VarExpr) from probably.pysmt.context import TranslationContext diff --git a/tests/test_loopfree_wp.py b/tests/test_loopfree_wp.py index 3745850..d4315a1 100644 --- a/tests/test_loopfree_wp.py +++ b/tests/test_loopfree_wp.py @@ -13,4 +13,6 @@ def test_uniform_sequence(): wp_expr = loopfree_wp(program.instructions, VarExpr("X")) wp_expr_ref = Mut.alloc(wp_expr) substitute_expr(wp_expr_ref, symbolic=set(["X"])) - assert str(wp_expr_ref.val) == '(1/2 * ((X)[jump/0, t/t + 1])) + (1/2 * ((X)[jump/1, t/t + 1]))' + assert str( + wp_expr_ref.val + ) == '(1/2 * ((X)[jump/0, t/t + 1])) + (1/2 * ((X)[jump/1, t/t + 1]))' diff --git a/tests/test_one_loop_ert.py b/tests/test_one_loop_ert.py index 5895027..03f41c1 100644 --- a/tests/test_one_loop_ert.py +++ b/tests/test_one_loop_ert.py @@ -1,6 +1,6 @@ from probably.pgcl.compiler import parse_pgcl -from probably.pgcl.wp import one_loop_wp_transformer from probably.pgcl.simplify import normalize_expectation_transformer +from probably.pgcl.wp import one_loop_wp_transformer def test_ber_ert(): diff --git a/tests/test_one_loop_wp.py b/tests/test_one_loop_wp.py index be0cac0..8c2dd17 100644 --- a/tests/test_one_loop_wp.py +++ b/tests/test_one_loop_wp.py @@ -3,8 +3,8 @@ """ from probably.pgcl.compiler import parse_pgcl -from probably.pgcl.wp import one_loop_wp_transformer from probably.pgcl.simplify import normalize_expectation_transformer +from probably.pgcl.wp import one_loop_wp_transformer def test_branchy(): diff --git a/tests/test_operator_precedence.py b/tests/test_operator_precedence.py index 2fb7036..2ec5cef 100644 --- a/tests/test_operator_precedence.py +++ b/tests/test_operator_precedence.py @@ -1,9 +1,12 @@ -from probably.pgcl.parser import parse_pgcl -from probably.pgcl.ast import * -from pytest import raises from decimal import Decimal from fractions import Fraction +from pytest import raises + +from probably.pgcl.ast import * +from probably.pgcl.parser import parse_pgcl + + def test_all_operators(): program = parse_pgcl(""" const pi := 3.14; @@ -19,20 +22,29 @@ def test_all_operators(): """) instr: List[AsgnInstr] = program.instructions - assert instr[0].rhs == BinopExpr(Binop.OR, BoolLitExpr(True), BinopExpr(Binop.AND, BoolLitExpr(False), BoolLitExpr(True))) + assert instr[0].rhs == BinopExpr( + Binop.OR, BoolLitExpr(True), + BinopExpr(Binop.AND, BoolLitExpr(False), BoolLitExpr(True))) assert instr[1].rhs == BinopExpr(Binop.AND, BinopExpr(Binop.GT, RealLitExpr(Decimal(6.0)), VarExpr("pi")),\ UnopExpr(Unop.NEG, BinopExpr(Binop.EQ, VarExpr("pi"), BinopExpr(Binop.TIMES, VarExpr("pi"), NatLitExpr(3))))) exprs = instr[2].rhs.exprs assert exprs[0] == (NatLitExpr(1), RealLitExpr(Decimal(0.5))) - assert exprs[1] == (NatLitExpr(2), RealLitExpr(Fraction(1,2))) + assert exprs[1] == (NatLitExpr(2), RealLitExpr(Fraction(1, 2))) + + assert instr[3].rhs == BinopExpr( + Binop.PLUS, BinopExpr(Binop.PLUS, NatLitExpr(1), NatLitExpr(2)), + NatLitExpr(3)) - assert instr[3].rhs == BinopExpr(Binop.PLUS, BinopExpr(Binop.PLUS, NatLitExpr(1), NatLitExpr(2)), NatLitExpr(3)) + assert instr[4].rhs == BinopExpr( + Binop.POWER, NatLitExpr(1), + BinopExpr(Binop.POWER, NatLitExpr(2), NatLitExpr(3))) - assert instr[4].rhs == BinopExpr(Binop.POWER, NatLitExpr(1), BinopExpr(Binop.POWER, NatLitExpr(2), NatLitExpr(3))) + assert instr[5].rhs == BinopExpr( + Binop.MODULO, NatLitExpr(1), + BinopExpr(Binop.POWER, NatLitExpr(2), NatLitExpr(3))) - assert instr[5].rhs == BinopExpr(Binop.MODULO, NatLitExpr(1), BinopExpr(Binop.POWER, NatLitExpr(2), NatLitExpr(3))) def test_likely_minus_error(): with raises(Exception) as e: diff --git a/tests/test_parser.py b/tests/test_parser.py index 407b249..5c9fd38 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1,7 +1,9 @@ -from probably.pgcl.parser import parse_pgcl -from probably.pgcl.ast import * from pytest import raises +from probably.pgcl.ast import * +from probably.pgcl.parser import parse_pgcl + + def test_all_distributions(): program = parse_pgcl(""" nat x; @@ -16,14 +18,17 @@ def test_all_distributions(): """) exprs = [instr.rhs for instr in program.instructions] - assert exprs == [DUniformExpr(NatLitExpr(1), NatLitExpr(2)), + assert exprs == [ + DUniformExpr(NatLitExpr(1), NatLitExpr(2)), DUniformExpr(NatLitExpr(1), NatLitExpr(2)), CUniformExpr(NatLitExpr(1), NatLitExpr(2)), GeometricExpr(NatLitExpr(1)), PoissonExpr(NatLitExpr(1)), LogDistExpr(NatLitExpr(1)), BernoulliExpr(NatLitExpr(1)), - BinomialExpr(NatLitExpr(1), NatLitExpr(2))] + BinomialExpr(NatLitExpr(1), NatLitExpr(2)) + ] + def test_syntax_errors(): illegal_names = {"true", "false"} diff --git a/tests/test_pgcl.py b/tests/test_pgcl.py index 3929801..29957ec 100644 --- a/tests/test_pgcl.py +++ b/tests/test_pgcl.py @@ -45,6 +45,7 @@ def test_comments(): assert len(program.instructions) == 0 + def test_params(): program = parse_pgcl(""" nparam x diff --git a/tests/test_substitution.py b/tests/test_substitution.py index cae02ac..d6e472b 100644 --- a/tests/test_substitution.py +++ b/tests/test_substitution.py @@ -5,9 +5,9 @@ from hypothesis import given from probably.pgcl.ast import Expr, SubstExpr, Unop, UnopExpr, VarExpr +from probably.pgcl.ast.walk import Walk, walk_expr from probably.pgcl.parser import parse_pgcl from probably.pgcl.substitute import substitute_expr -from probably.pgcl.ast.walk import Walk, walk_expr from probably.pgcl.wp import loopfree_wp from probably.util.ref import Mut diff --git a/tests/test_typechecking.py b/tests/test_typechecking.py index f4c52c8..49752ff 100644 --- a/tests/test_typechecking.py +++ b/tests/test_typechecking.py @@ -4,6 +4,7 @@ from probably.pgcl.check import CheckFail, check_program from probably.pgcl.parser import parse_pgcl + def test_correct_program(): program = parse_pgcl(""" const pi := 3.14 From a2adf9fb972167b8cb2d0cc96e80e8d11544bd95 Mon Sep 17 00:00:00 2001 From: Legotier Date: Thu, 9 Jun 2022 15:00:42 +0200 Subject: [PATCH 67/67] Add format target to makefile --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ddf2a47..4aaa9cb 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ .DEFAULT: help help: - @echo "Available targets: install, lint, mypy, test, docs, clean" + @echo "Available targets: install, lint, mypy, test, docs, clean, format" install: poetry install @@ -21,3 +21,7 @@ docs: clean: rm -rf docs/build + +format: + poetry run yapf -r -i probably/ tests/ + poetry run isort probably/ tests/