Repository: google/qhbm-library (language: python)

Issue:
Lint code
Do initial linting with flake8


Discussion / hints:

Fix patch:
diff --git a/.flake8 b/.flake8
new file mode 100644
index 00000000..c5c6294e
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,4 @@
+[flake8]
+max-line-length = 88
+extend-ignore = E203
+
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b22da6ca..4859c169 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,4 +13,20 @@ jobs:
       - uses: psf/black@2f52e4b4929370ec503ee272bcc10d3176db8e89
         with:
           args: ". --diff"
-
+  test:
+    name: Lint check
+    runs-on: ubuntu-16.04
+    timeout-minutes: 5
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions/setup-python@v2
+        with:
+          python-version: '3.8'
+          architecture: 'x64'
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install flake8==3.9.2
+      - name: Lint with flake8
+        run: |
+          flake8 .
diff --git a/.gitignore b/.gitignore
index 0f698af5..cc03c869 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,8 +13,10 @@
 # limitations under the License.
 # ==============================================================================
 
+/.coverage
+
 # ignore pycache
-__pycache__*
+__pycache__/
 
 # ignore emacs temp files
 *#
diff --git a/dev-requirements.txt b/dev-requirements.txt
deleted file mode 100644
index feba473c..00000000
--- a/dev-requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-black==21.5b1
-flake8==3.9.2
-pytest==6.2.4
diff --git a/poetry.lock b/poetry.lock
new file mode 100644
index 00000000..8b8e0dd2
--- /dev/null
+++ b/poetry.lock
@@ -0,0 +1,1584 @@
+[[package]]
+name = "absl-py"
+version = "0.12.0"
+description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py."
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = "*"
+
+[[package]]
+name = "appdirs"
+version = "1.4.4"
+description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "astunparse"
+version = "1.6.3"
+description = "An AST unparser for Python"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = ">=1.6.1,<2.0"
+
+[[package]]
+name = "atomicwrites"
+version = "1.4.0"
+description = "Atomic file writes."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "attrs"
+version = "21.2.0"
+description = "Classes Without Boilerplate"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.extras]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
+docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
+
+[[package]]
+name = "black"
+version = "21.5b1"
+description = "The uncompromising code formatter."
+category = "dev"
+optional = false
+python-versions = ">=3.6.2"
+
+[package.dependencies]
+appdirs = "*"
+click = ">=7.1.2"
+mypy-extensions = ">=0.4.3"
+pathspec = ">=0.8.1,<1"
+regex = ">=2020.1.8"
+toml = ">=0.10.1"
+
+[package.extras]
+colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.6.0)", "aiohttp-cors"]
+python2 = ["typed-ast (>=1.4.2)"]
+
+[[package]]
+name = "cachetools"
+version = "4.2.2"
+description = "Extensible memoizing collections and decorators"
+category = "main"
+optional = false
+python-versions = "~=3.5"
+
+[[package]]
+name = "certifi"
+version = "2020.12.5"
+description = "Python package for providing Mozilla's CA Bundle."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "chardet"
+version = "4.0.0"
+description = "Universal encoding detector for Python 2 and 3"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "cirq"
+version = "0.9.1"
+description = "A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits."
+category = "main"
+optional = false
+python-versions = ">=3.6.0"
+
+[package.dependencies]
+freezegun = ">=0.3.15,<0.4.0"
+google-api-core = {version = ">=1.14.0,<2.0.0dev", extras = ["grpc"]}
+matplotlib = ">=3.0,<4.0"
+networkx = ">=2.4,<3.0"
+numpy = ">=1.16,<2.0"
+pandas = "*"
+protobuf = ">=3.12.0,<3.13.0"
+requests = ">=2.18,<3.0"
+scipy = "*"
+sortedcontainers = ">=2.0,<3.0"
+sympy = "*"
+typing-extensions = "*"
+
+[package.extras]
+contrib = ["ply (>=3.4)", "pylatex (>=1.3.0,<1.4.0)", "quimb", "opt-einsum", "autoray", "pyquil (>=2.21.0,<2.22.0)"]
+dev_env = ["mypy (>=0.782.0,<0.783.0)", "pylint (>=2.3.0,<2.4.0)", "pytest (>=5.4.1,<5.5.0)", "pytest-asyncio (>=0.12.0,<0.13.0)", "pytest-cov (>=2.5.0,<2.6.0)", "pytest-benchmark (>=3.2.0,<3.3.0)", "yapf (>=0.27.0,<0.28.0)", "grpcio-tools (>=1.26,<2.0)", "mypy-protobuf (==1.10)", "twine", "pyquil (>=2.21.0,<2.22.0)", "qiskit (>=0.20.0,<0.21.0)", "pypandoc", "myst-parser", "Sphinx (>=3.2.0,<3.3.0)", "sphinx-rtd-theme", "sphinx-markdown-tables", "nbsphinx", "ipython", "ipykernel", "rstcheck (>=3.3.1,<3.4.0)", "ply (>=3.4)", "pylatex (>=1.3.0,<1.4.0)", "quimb", "opt-einsum", "autoray"]
+
+[[package]]
+name = "click"
+version = "8.0.0"
+description = "Composable command line interface toolkit"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "cloudpickle"
+version = "1.3.0"
+description = "Extended pickling support for Python objects"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "colorama"
+version = "0.4.4"
+description = "Cross-platform colored terminal text."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "coverage"
+version = "5.5"
+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"
+
+[package.dependencies]
+toml = {version = "*", optional = true, markers = "extra == \"toml\""}
+
+[package.extras]
+toml = ["toml"]
+
+[[package]]
+name = "cycler"
+version = "0.10.0"
+description = "Composable style cycles"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = "*"
+
+[[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 = "dm-tree"
+version = "0.1.6"
+description = "Tree is a library for working with nested data structures."
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = ">=1.12.0"
+
+[[package]]
+name = "flake8"
+version = "3.9.2"
+description = "the modular source code checker: pep8 pyflakes and co"
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+
+[package.dependencies]
+mccabe = ">=0.6.0,<0.7.0"
+pycodestyle = ">=2.7.0,<2.8.0"
+pyflakes = ">=2.3.0,<2.4.0"
+
+[[package]]
+name = "freezegun"
+version = "0.3.15"
+description = "Let your Python tests travel through time"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+python-dateutil = ">=1.0,<2.0 || >2.0"
+six = "*"
+
+[[package]]
+name = "gast"
+version = "0.3.3"
+description = "Python AST that abstracts the underlying Python version"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "google-api-core"
+version = "1.26.3"
+description = "Google API client core library"
+category = "main"
+optional = false
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
+
+[package.dependencies]
+google-auth = ">=1.21.1,<2.0dev"
+googleapis-common-protos = ">=1.6.0,<2.0dev"
+grpcio = {version = ">=1.29.0,<2.0dev", optional = true, markers = "extra == \"grpc\""}
+packaging = ">=14.3"
+protobuf = ">=3.12.0"
+pytz = "*"
+requests = ">=2.18.0,<3.0.0dev"
+six = ">=1.13.0"
+
+[package.extras]
+grpc = ["grpcio (>=1.29.0,<2.0dev)"]
+grpcgcp = ["grpcio-gcp (>=0.2.2)"]
+grpcio-gcp = ["grpcio-gcp (>=0.2.2)"]
+
+[[package]]
+name = "google-auth"
+version = "1.30.0"
+description = "Google Authentication Library"
+category = "main"
+optional = false
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
+
+[package.dependencies]
+cachetools = ">=2.0.0,<5.0"
+pyasn1-modules = ">=0.2.1"
+rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""}
+six = ">=1.9.0"
+
+[package.extras]
+aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"]
+pyopenssl = ["pyopenssl (>=20.0.0)"]
+reauth = ["pyu2f (>=0.1.5)"]
+
+[[package]]
+name = "google-auth-oauthlib"
+version = "0.4.4"
+description = "Google Authentication Library"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+google-auth = ">=1.0.0"
+requests-oauthlib = ">=0.7.0"
+
+[package.extras]
+tool = ["click (>=6.0.0)"]
+
+[[package]]
+name = "google-pasta"
+version = "0.2.0"
+description = "pasta is an AST-based Python refactoring library"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = "*"
+
+[[package]]
+name = "googleapis-common-protos"
+version = "1.53.0"
+description = "Common protobufs used in Google APIs"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+protobuf = ">=3.12.0"
+
+[package.extras]
+grpc = ["grpcio (>=1.0.0)"]
+
+[[package]]
+name = "grpcio"
+version = "1.37.1"
+description = "HTTP/2-based RPC framework"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = ">=1.5.2"
+
+[package.extras]
+protobuf = ["grpcio-tools (>=1.37.1)"]
+
+[[package]]
+name = "h5py"
+version = "2.10.0"
+description = "Read and write HDF5 files from Python"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+numpy = ">=1.7"
+six = "*"
+
+[[package]]
+name = "idna"
+version = "2.10"
+description = "Internationalized Domain Names in Applications (IDNA)"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "iniconfig"
+version = "1.1.1"
+description = "iniconfig: brain-dead simple config-ini parsing"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "keras-preprocessing"
+version = "1.1.2"
+description = "Easy data preprocessing and data augmentation for deep learning models"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+numpy = ">=1.9.1"
+six = ">=1.9.0"
+
+[package.extras]
+image = ["scipy (>=0.14)", "Pillow (>=5.2.0)"]
+pep8 = ["flake8"]
+tests = ["pandas", "pillow", "tensorflow", "keras", "pytest", "pytest-xdist", "pytest-cov"]
+
+[[package]]
+name = "kiwisolver"
+version = "1.3.1"
+description = "A fast implementation of the Cassowary constraint solver"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "markdown"
+version = "3.3.4"
+description = "Python implementation of Markdown."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+testing = ["coverage", "pyyaml"]
+
+[[package]]
+name = "matplotlib"
+version = "3.4.2"
+description = "Python plotting package"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+
+[package.dependencies]
+cycler = ">=0.10"
+kiwisolver = ">=1.0.1"
+numpy = ">=1.16"
+pillow = ">=6.2.0"
+pyparsing = ">=2.2.1"
+python-dateutil = ">=2.7"
+
+[[package]]
+name = "mccabe"
+version = "0.6.1"
+description = "McCabe checker, plugin for flake8"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "mpmath"
+version = "1.2.1"
+description = "Python library for arbitrary-precision floating-point arithmetic"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.extras]
+develop = ["pytest (>=4.6)", "pycodestyle", "pytest-cov", "codecov", "wheel"]
+tests = ["pytest (>=4.6)"]
+
+[[package]]
+name = "mypy-extensions"
+version = "0.4.3"
+description = "Experimental type system extensions for programs checked with the mypy typechecker."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "networkx"
+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,<5"
+
+[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"]
+
+[[package]]
+name = "numpy"
+version = "1.18.5"
+description = "NumPy is the fundamental package for array computing with Python."
+category = "main"
+optional = false
+python-versions = ">=3.5"
+
+[[package]]
+name = "oauthlib"
+version = "3.1.0"
+description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.extras]
+rsa = ["cryptography"]
+signals = ["blinker"]
+signedtoken = ["cryptography", "pyjwt (>=1.0.0)"]
+
+[[package]]
+name = "opt-einsum"
+version = "3.3.0"
+description = "Optimizing numpys einsum function"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+
+[package.dependencies]
+numpy = ">=1.7"
+
+[package.extras]
+docs = ["sphinx (==1.2.3)", "sphinxcontrib-napoleon", "sphinx-rtd-theme", "numpydoc"]
+tests = ["pytest", "pytest-cov", "pytest-pep8"]
+
+[[package]]
+name = "packaging"
+version = "20.9"
+description = "Core utilities for Python packages"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.dependencies]
+pyparsing = ">=2.0.2"
+
+[[package]]
+name = "pandas"
+version = "1.2.4"
+description = "Powerful data structures for data analysis, time series, and statistics"
+category = "main"
+optional = false
+python-versions = ">=3.7.1"
+
+[package.dependencies]
+numpy = ">=1.16.5"
+python-dateutil = ">=2.7.3"
+pytz = ">=2017.3"
+
+[package.extras]
+test = ["pytest (>=5.0.1)", "pytest-xdist", "hypothesis (>=3.58)"]
+
+[[package]]
+name = "pathspec"
+version = "0.8.1"
+description = "Utility library for gitignore style pattern matching of file paths."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "pillow"
+version = "8.2.0"
+description = "Python Imaging Library (Fork)"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "pluggy"
+version = "0.13.1"
+description = "plugin and hook calling mechanisms for python"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+
+[[package]]
+name = "protobuf"
+version = "3.12.4"
+description = "Protocol Buffers"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = ">=1.9"
+
+[[package]]
+name = "py"
+version = "1.10.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.*"
+
+[[package]]
+name = "pyasn1"
+version = "0.4.8"
+description = "ASN.1 types and codecs"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "pyasn1-modules"
+version = "0.2.8"
+description = "A collection of ASN.1-based protocols modules."
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+pyasn1 = ">=0.4.6,<0.5.0"
+
+[[package]]
+name = "pycodestyle"
+version = "2.7.0"
+description = "Python style guide checker"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pyflakes"
+version = "2.3.1"
+description = "passive checker of Python programs"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pyparsing"
+version = "2.4.7"
+description = "Python parsing module"
+category = "main"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "pytest"
+version = "6.2.4"
+description = "pytest: simple powerful testing with Python"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
+attrs = ">=19.2.0"
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=0.12,<1.0.0a1"
+py = ">=1.8.2"
+toml = "*"
+
+[package.extras]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+
+[[package]]
+name = "pytest-cov"
+version = "2.11.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 = ">=5.2.1"
+pytest = ">=4.6"
+
+[package.extras]
+testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", "virtualenv"]
+
+[[package]]
+name = "python-dateutil"
+version = "2.8.1"
+description = "Extensions to the standard Python datetime module"
+category = "main"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+
+[package.dependencies]
+six = ">=1.5"
+
+[[package]]
+name = "pytz"
+version = "2021.1"
+description = "World timezone definitions, modern and historical"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "regex"
+version = "2021.4.4"
+description = "Alternative regular expression module, to replace re."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "requests"
+version = "2.25.1"
+description = "Python HTTP for Humans."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+chardet = ">=3.0.2,<5"
+idna = ">=2.5,<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"]
+
+[[package]]
+name = "requests-oauthlib"
+version = "1.3.0"
+description = "OAuthlib authentication support for Requests."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.dependencies]
+oauthlib = ">=3.0.0"
+requests = ">=2.0.0"
+
+[package.extras]
+rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
+
+[[package]]
+name = "rsa"
+version = "4.7.2"
+description = "Pure-Python RSA implementation"
+category = "main"
+optional = false
+python-versions = ">=3.5, <4"
+
+[package.dependencies]
+pyasn1 = ">=0.1.3"
+
+[[package]]
+name = "scipy"
+version = "1.6.3"
+description = "SciPy: Scientific Library for Python"
+category = "main"
+optional = false
+python-versions = ">=3.7,<3.10"
+
+[package.dependencies]
+numpy = ">=1.16.5,<1.23.0"
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "sortedcontainers"
+version = "2.3.0"
+description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "sympy"
+version = "1.5"
+description = "Computer algebra system (CAS) in Python"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+mpmath = ">=0.19"
+
+[[package]]
+name = "tensorboard"
+version = "2.5.0"
+description = "TensorBoard lets you watch Tensors Flow"
+category = "main"
+optional = false
+python-versions = ">= 2.7, != 3.0.*, != 3.1.*"
+
+[package.dependencies]
+absl-py = ">=0.4"
+google-auth = ">=1.6.3,<2"
+google-auth-oauthlib = ">=0.4.1,<0.5"
+grpcio = ">=1.24.3"
+markdown = ">=2.6.8"
+numpy = ">=1.12.0"
+protobuf = ">=3.6.0"
+requests = ">=2.21.0,<3"
+tensorboard-data-server = ">=0.6.0,<0.7.0"
+tensorboard-plugin-wit = ">=1.6.0"
+werkzeug = ">=0.11.15"
+
+[[package]]
+name = "tensorboard-data-server"
+version = "0.6.1"
+description = "Fast data loading for TensorBoard"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "tensorboard-plugin-wit"
+version = "1.8.0"
+description = "What-If Tool TensorBoard plugin."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "tensorflow"
+version = "2.3.1"
+description = "TensorFlow is an open source machine learning framework for everyone."
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+absl-py = ">=0.7.0"
+astunparse = "1.6.3"
+gast = "0.3.3"
+google-pasta = ">=0.1.8"
+grpcio = ">=1.8.6"
+h5py = ">=2.10.0,<2.11.0"
+keras-preprocessing = ">=1.1.1,<1.2"
+numpy = ">=1.16.0,<1.19.0"
+opt-einsum = ">=2.3.2"
+protobuf = ">=3.9.2"
+six = ">=1.12.0"
+tensorboard = ">=2.3.0,<3"
+tensorflow-estimator = ">=2.3.0,<2.4.0"
+termcolor = ">=1.1.0"
+wrapt = ">=1.11.1"
+
+[[package]]
+name = "tensorflow-estimator"
+version = "2.3.0"
+description = "TensorFlow Estimator."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "tensorflow-probability"
+version = "0.11.0"
+description = "Probabilistic modeling and statistical inference in TensorFlow"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+cloudpickle = "1.3"
+decorator = "*"
+dm-tree = "*"
+gast = ">=0.3.2"
+numpy = ">=1.13.3"
+six = ">=1.10.0"
+
+[package.extras]
+jax = ["jax", "jaxlib"]
+tfds = ["tensorflow-datasets (>=2.2.0)"]
+
+[[package]]
+name = "tensorflow-quantum"
+version = "0.4.0"
+description = "TensorFlow Quantum is a library for hybrid quantum-classical machine learning."
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+cirq = "0.9.1"
+sympy = "1.5"
+
+[package.extras]
+extras = ["tensorflow (==2.3.1)"]
+
+[[package]]
+name = "termcolor"
+version = "1.1.0"
+description = "ANSII Color formatting for output in terminal."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+description = "Python Library for Tom's Obvious, Minimal Language"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "typing-extensions"
+version = "3.10.0.0"
+description = "Backported and Experimental Type Hints for Python 3.5+"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "urllib3"
+version = "1.26.4"
+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]
+secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
+socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+brotli = ["brotlipy (>=0.6.0)"]
+
+[[package]]
+name = "werkzeug"
+version = "2.0.0"
+description = "The comprehensive WSGI web application library."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+watchdog = ["watchdog"]
+
+[[package]]
+name = "wrapt"
+version = "1.12.1"
+description = "Module for decorators, wrappers and monkey patching."
+category = "main"
+optional = false
+python-versions = "*"
+
+[metadata]
+lock-version = "1.1"
+python-versions = "~3.8"
+content-hash = "6c959625fa83ebb5ffd83904e3f40781d6b8f55409cb6c47d2f845790fc290c0"
+
+[metadata.files]
+absl-py = [
+    {file = "absl-py-0.12.0.tar.gz", hash = "sha256:b44f68984a5ceb2607d135a615999b93924c771238a63920d17d3387b0d229d5"},
+    {file = "absl_py-0.12.0-py3-none-any.whl", hash = "sha256:afe94e3c751ff81aad55d33ab6e630390da32780110b5af72ae81ecff8418d9e"},
+]
+appdirs = [
+    {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
+    {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
+]
+astunparse = [
+    {file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"},
+    {file = "astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"},
+]
+atomicwrites = [
+    {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
+    {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
+]
+attrs = [
+    {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
+    {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
+]
+black = [
+    {file = "black-21.5b1-py3-none-any.whl", hash = "sha256:8a60071a0043876a4ae96e6c69bd3a127dad2c1ca7c8083573eb82f92705d008"},
+    {file = "black-21.5b1.tar.gz", hash = "sha256:23695358dbcb3deafe7f0a3ad89feee5999a46be5fec21f4f1d108be0bcdb3b1"},
+]
+cachetools = [
+    {file = "cachetools-4.2.2-py3-none-any.whl", hash = "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001"},
+    {file = "cachetools-4.2.2.tar.gz", hash = "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"},
+]
+certifi = [
+    {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"},
+    {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"},
+]
+chardet = [
+    {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
+    {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
+]
+cirq = [
+    {file = "cirq-0.9.1-py3-none-any.whl", hash = "sha256:d900b861f2132a673b511b22ec80955cedec34c1bfa95d8f39cdc1eab5309242"},
+]
+click = [
+    {file = "click-8.0.0-py3-none-any.whl", hash = "sha256:e90e62ced43dc8105fb9a26d62f0d9340b5c8db053a814e25d95c19873ae87db"},
+    {file = "click-8.0.0.tar.gz", hash = "sha256:7d8c289ee437bcb0316820ccee14aefcb056e58d31830ecab8e47eda6540e136"},
+]
+cloudpickle = [
+    {file = "cloudpickle-1.3.0-py2.py3-none-any.whl", hash = "sha256:8664761f810efc07dbb301459e413c99b68fcc6d8703912bd39d86618ac631e3"},
+    {file = "cloudpickle-1.3.0.tar.gz", hash = "sha256:38af54d0e7705d87a287bdefe1df00f936aadb1f629dca383e825cca927fa753"},
+]
+colorama = [
+    {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.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"},
+    {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"},
+    {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"},
+    {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"},
+    {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"},
+    {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"},
+    {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"},
+    {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"},
+    {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"},
+    {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"},
+    {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"},
+    {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"},
+    {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"},
+    {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"},
+    {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"},
+    {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"},
+    {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"},
+    {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"},
+    {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"},
+    {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"},
+    {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"},
+    {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"},
+    {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"},
+    {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"},
+    {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"},
+    {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"},
+    {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"},
+    {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"},
+    {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"},
+    {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"},
+    {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"},
+    {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"},
+    {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"},
+    {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"},
+    {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"},
+    {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"},
+    {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"},
+    {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"},
+    {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"},
+    {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"},
+    {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"},
+    {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"},
+    {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"},
+    {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"},
+    {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"},
+    {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"},
+    {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"},
+    {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"},
+    {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"},
+    {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"},
+    {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"},
+    {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"},
+]
+cycler = [
+    {file = "cycler-0.10.0-py2.py3-none-any.whl", hash = "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d"},
+    {file = "cycler-0.10.0.tar.gz", hash = "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"},
+]
+decorator = [
+    {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"},
+    {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"},
+]
+dm-tree = [
+    {file = "dm-tree-0.1.6.tar.gz", hash = "sha256:6776404b23b4522c01012ffb314632aba092c9541577004ab153321e87da439a"},
+    {file = "dm_tree-0.1.6-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a8814a5c838f79e9db22a51369c74f4d92e7f1485ec55d7f665ae4d98478cb4f"},
+    {file = "dm_tree-0.1.6-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:e28ba91d3d97230b831716db401ce116ae5c7dcd025161ac16ecb8bd5c870a85"},
+    {file = "dm_tree-0.1.6-cp36-cp36m-manylinux_2_24_x86_64.whl", hash = "sha256:603392f1a7818a4f43a7033c2061ae7c2085a4a728171b0bbca76bd107fcdfb0"},
+    {file = "dm_tree-0.1.6-cp36-cp36m-win_amd64.whl", hash = "sha256:2c91e472aab5c5e083c12d0a9396bbd7695031348721f709a9c6f2449e53dab6"},
+    {file = "dm_tree-0.1.6-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:889eae86e0d2d4b8da8eb2edc7186b45a5f92e00c8dd77f2a5c8422f03db18f4"},
+    {file = "dm_tree-0.1.6-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:2fa9c6e56cbd22cdffec42dc8b20464872b07c4535d8effc537fe0d31930b084"},
+    {file = "dm_tree-0.1.6-cp37-cp37m-manylinux_2_24_x86_64.whl", hash = "sha256:c4e8d868fc9a75cbdb67e78069b33e62a4c69bc182c1d2adc29ab08e283912d8"},
+    {file = "dm_tree-0.1.6-cp37-cp37m-win_amd64.whl", hash = "sha256:6d5f64d89f657b11f429e13b1378c8cfbe4baef50e7ab31f3689bfe0cf4a2508"},
+    {file = "dm_tree-0.1.6-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8d59c5098456667b28c607110537c86c25cbd0ee455f21d033c60ef2d7f48d81"},
+    {file = "dm_tree-0.1.6-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:f3bec40e658fe7546c3a56849c743ac9a498e620b3236e82e171801938a56679"},
+    {file = "dm_tree-0.1.6-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:e87d06478356a2d92c3940dedebcd92a14ad37fba10ebb1839c8140693b83c0a"},
+    {file = "dm_tree-0.1.6-cp38-cp38-win_amd64.whl", hash = "sha256:02ffa673f20b1756dcf085ef2c354bc59416d843b384c7b71c421f873ffc36c0"},
+    {file = "dm_tree-0.1.6-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:affc7a6d29442a143c60efb2f03bcb95424d4fe6168f3d31de892c1e601fa0e6"},
+    {file = "dm_tree-0.1.6-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:bd347c74254ba320d57b0e102558c1189e3b4ae1bae952f9aef156b5914567c8"},
+    {file = "dm_tree-0.1.6-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:8425454192e954692d9a1e0f7b374b3b7030916b17b6055951dc17d58b6fe1b8"},
+    {file = "dm_tree-0.1.6-cp39-cp39-win_amd64.whl", hash = "sha256:5269183f80f1ae37543a2a30a8f78e4b0460d5da74fb5ac42dc8a476ef8d707e"},
+]
+flake8 = [
+    {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
+    {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
+]
+freezegun = [
+    {file = "freezegun-0.3.15-py2.py3-none-any.whl", hash = "sha256:82c757a05b7c7ca3e176bfebd7d6779fd9139c7cb4ef969c38a28d74deef89b2"},
+    {file = "freezegun-0.3.15.tar.gz", hash = "sha256:e2062f2c7f95cc276a834c22f1a17179467176b624cc6f936e8bc3be5535ad1b"},
+]
+gast = [
+    {file = "gast-0.3.3-py2.py3-none-any.whl", hash = "sha256:8f46f5be57ae6889a4e16e2ca113b1703ef17f2b0abceb83793eaba9e1351a45"},
+    {file = "gast-0.3.3.tar.gz", hash = "sha256:b881ef288a49aa81440d2c5eb8aeefd4c2bb8993d5f50edae7413a85bfdb3b57"},
+]
+google-api-core = [
+    {file = "google-api-core-1.26.3.tar.gz", hash = "sha256:b914345c7ea23861162693a27703bab804a55504f7e6e9abcaff174d80df32ac"},
+    {file = "google_api_core-1.26.3-py2.py3-none-any.whl", hash = "sha256:099762d4b4018cd536bcf85136bf337957da438807572db52f21dc61251be089"},
+]
+google-auth = [
+    {file = "google-auth-1.30.0.tar.gz", hash = "sha256:9ad25fba07f46a628ad4d0ca09f38dcb262830df2ac95b217f9b0129c9e42206"},
+    {file = "google_auth-1.30.0-py2.py3-none-any.whl", hash = "sha256:588bdb03a41ecb4978472b847881e5518b5d9ec6153d3d679aa127a55e13b39f"},
+]
+google-auth-oauthlib = [
+    {file = "google-auth-oauthlib-0.4.4.tar.gz", hash = "sha256:09832c6e75032f93818edf1affe4746121d640c625a5bef9b5c96af676e98eee"},
+    {file = "google_auth_oauthlib-0.4.4-py2.py3-none-any.whl", hash = "sha256:0e92aacacfb94978de3b7972cf4b0f204c3cd206f74ddd0dc0b31e91164e6317"},
+]
+google-pasta = [
+    {file = "google-pasta-0.2.0.tar.gz", hash = "sha256:c9f2c8dfc8f96d0d5808299920721be30c9eec37f2389f28904f454565c8a16e"},
+    {file = "google_pasta-0.2.0-py2-none-any.whl", hash = "sha256:4612951da876b1a10fe3960d7226f0c7682cf901e16ac06e473b267a5afa8954"},
+    {file = "google_pasta-0.2.0-py3-none-any.whl", hash = "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed"},
+]
+googleapis-common-protos = [
+    {file = "googleapis-common-protos-1.53.0.tar.gz", hash = "sha256:a88ee8903aa0a81f6c3cec2d5cf62d3c8aa67c06439b0496b49048fb1854ebf4"},
+    {file = "googleapis_common_protos-1.53.0-py2.py3-none-any.whl", hash = "sha256:f6d561ab8fb16b30020b940e2dd01cd80082f4762fa9f3ee670f4419b4b8dbd0"},
+]
+grpcio = [
+    {file = "grpcio-1.37.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:0d64b5995e17eb9f086e82e6a4edadd1295827b593be71b516e7a442067784b5"},
+    {file = "grpcio-1.37.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:6f44b8244bafcbea63daff222ae1b27d048b9d8fd47eb3d11e61ee092078e766"},
+    {file = "grpcio-1.37.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:37e265b72e69ef8e33efca8d1123bdc349ae3eabb92563e76adfce209c9df51a"},
+    {file = "grpcio-1.37.1-cp27-cp27m-win32.whl", hash = "sha256:ee0537fe2423307b885ba44e6789249e6d7624247cb38a20b9f38f4b40f5ab03"},
+    {file = "grpcio-1.37.1-cp27-cp27m-win_amd64.whl", hash = "sha256:1de472a3c2a3d89d4d400d8179f2777ec99f7da0e87c0c1f196226141816d621"},
+    {file = "grpcio-1.37.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:99a627471275f93d400399b55e4c1d798602ff79d693e7def0a0b276912bff7e"},
+    {file = "grpcio-1.37.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:e7da0319003d150611b30cd864e0474a283324b3db9107107aa3ef9a71c53130"},
+    {file = "grpcio-1.37.1-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:22b0cc3531d3c405fae9a8519004a0e62ecbd1f005b55b3622098a4881d36b96"},
+    {file = "grpcio-1.37.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:f6a73167fce4a41e5c0b34ceaad1048a14e9eeb4fc324da49da0537c199efab7"},
+    {file = "grpcio-1.37.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fa279b99878bae9b804c09e023f2b47de79d0b5e813ab85ddf28673784d610f0"},
+    {file = "grpcio-1.37.1-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:9674fffd1f599aec7389a61d48c1a8c8aaba69591609895911c6d8386d86dd45"},
+    {file = "grpcio-1.37.1-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:80c3c9d24ecd236571d3c86657243431a8bafef022dcce83f9f2aeb6eecb96b9"},
+    {file = "grpcio-1.37.1-cp35-cp35m-win32.whl", hash = "sha256:e236d0580f7e69a35c420ce60f960b294e9dc973b8c31499fa476eb4d4ba4088"},
+    {file = "grpcio-1.37.1-cp35-cp35m-win_amd64.whl", hash = "sha256:30ba9712547c9497a438bfeb2c7f393fa983df1609e1c81243d4b0d1b1bfefbf"},
+    {file = "grpcio-1.37.1-cp36-cp36m-linux_armv7l.whl", hash = "sha256:ad03ff6b15f3481f3c999d5d22b5c56295dffc49b8e2cbdbc04c7bf358d3034e"},
+    {file = "grpcio-1.37.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:728292f5ccb849f30774c0805ef5c39452b3a5f4d193ac499ae5b78d268ff64b"},
+    {file = "grpcio-1.37.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:5dabaac759a98bcfd979d22874dcd7ccf8779678a2fe841d355dd93fee143974"},
+    {file = "grpcio-1.37.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f933dd10948a5e5ed4258a1581e45aec1bb84069e62368084eb2dcf4cce51e78"},
+    {file = "grpcio-1.37.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:67b482c810d05d9317e29b82900864ab888b9f842701906ba54c3eb176cd8eab"},
+    {file = "grpcio-1.37.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:494cce1709f7cd63c2610c25b41f886048f1d993511ddb23f766b77ac142ba78"},
+    {file = "grpcio-1.37.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:264f6d9a922f5124f79f50b1880349fd16c657a9b4fdf0f29fca939d40584f7f"},
+    {file = "grpcio-1.37.1-cp36-cp36m-win32.whl", hash = "sha256:e3e0fb7d32f163699cef5132b060e3f613dc914408164eb3e3ac69095861ea04"},
+    {file = "grpcio-1.37.1-cp36-cp36m-win_amd64.whl", hash = "sha256:640f49187105fb6c2b1b7acea06df3b0ccf5fe33a075c73b8a741013bc5cc802"},
+    {file = "grpcio-1.37.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:f1287ae8a3bef97fd702dac95967aaf52031a6dceb2bd30da165f16e3b617293"},
+    {file = "grpcio-1.37.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:30807f3979ebb3872588fa166876a2a24febe17e0db5950d5bedd67320d11b8c"},
+    {file = "grpcio-1.37.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:23666be3ed366f647f09c9caf89c48ca0daa12be8fe4786e5a368a6cd69de1f6"},
+    {file = "grpcio-1.37.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:8f5a16f8b650efddd5ff3f750cca5b45c045923be13e79cdd1b886332307f46a"},
+    {file = "grpcio-1.37.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e72d8df53624098d8b1fe01c961888d61f90d7c0aa8116d76db80a535da9b445"},
+    {file = "grpcio-1.37.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:4850c96d3a22d941b0d6af4dccbc739caec7f367b783aad049c843b28b458ff0"},
+    {file = "grpcio-1.37.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:4493365334baaa3d775f5e4a91d9a844ac676560232223405a0964dfddb31924"},
+    {file = "grpcio-1.37.1-cp37-cp37m-win32.whl", hash = "sha256:34d6f626062e7ef47ab30ff8976825c58fa8846ccd8c645b57291ccc74b9d413"},
+    {file = "grpcio-1.37.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4c0503b5ef6fcabc52c296d750a095ef29fd707d0f85322e95e5c261b3a684f9"},
+    {file = "grpcio-1.37.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:ac4174b1cf4daea0653fcfee7676bb04a8a43644e9ddf1913834d1542a9c697b"},
+    {file = "grpcio-1.37.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:d232802ba15b465000263bc17171f9863173b7669bdd72dbdffdfcc0f6e637dc"},
+    {file = "grpcio-1.37.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c87599137f6022ed5079b0df47da83134b9810d4b00999b87edfc901347f26a9"},
+    {file = "grpcio-1.37.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:609297d3d5d32f47e04bf7dc61c7756df50bc37dec4dfd63e996388eba42fb3b"},
+    {file = "grpcio-1.37.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:025fa7dffb0cf724070cfcbe2ff600a18b0cf84642ede5c92f2717162e2a8c95"},
+    {file = "grpcio-1.37.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0b8817acef140cb9a3543208c13282d3bf4bb0103e930ddbb779677604085ada"},
+    {file = "grpcio-1.37.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a1cd40eac72d3c914eea73f8f7730ddbd86061098a8ce712d1ce108e9d87d449"},
+    {file = "grpcio-1.37.1-cp38-cp38-win32.whl", hash = "sha256:d7ae05ded17c4697ef80784dc89cad3025db0d90c5a8a0ada47a8d0749617d58"},
+    {file = "grpcio-1.37.1-cp38-cp38-win_amd64.whl", hash = "sha256:b948a00764fee55cf111e0bf3d987167557152abf879f2c13bd2f278a6247ded"},
+    {file = "grpcio-1.37.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:8d3cdca5cfd6761a8824bc8acc8ac7bc37ad5ef75899308ca0458cf7952ce12d"},
+    {file = "grpcio-1.37.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9364f35949c3cff5470b583a03ccfd927b71cbe1ab7583a6529d5d67ed76e91e"},
+    {file = "grpcio-1.37.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:1aab01ee3e4b88ed6419f0b25ff21c83deb6c823c6fb77e655def0796526e3a3"},
+    {file = "grpcio-1.37.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:74aad86c7c1b9163d01c3d9e75861e9b09c65e0947592ca315c30353a0f6c4d1"},
+    {file = "grpcio-1.37.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3ee1bef5f5e4208998cdef44933db3c30c52a7ebde424cfc4186404ffded1d35"},
+    {file = "grpcio-1.37.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:7533d2c9698dd3038fcf3dd0df243b76a9e0db8008f8575c305e20a3593189eb"},
+    {file = "grpcio-1.37.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:b7cc965538da06c9e9cf0e01bae91f274c75baf224ca6a734717c0f003ddf1f2"},
+    {file = "grpcio-1.37.1-cp39-cp39-win32.whl", hash = "sha256:6ad11c1ea337720a42fc31959bd44a38b8837e3ae25bdab681e2e1a28096b02a"},
+    {file = "grpcio-1.37.1-cp39-cp39-win_amd64.whl", hash = "sha256:7b2a2cf3621f94b123a9d7a68e4a8d948b29520136f096927f7c9653f24c8fca"},
+    {file = "grpcio-1.37.1.tar.gz", hash = "sha256:df8305806311d3fe913d4f7eb3ef28e2072159ea12f95baab5d447f1380a71e3"},
+]
+h5py = [
+    {file = "h5py-2.10.0-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:ecf4d0b56ee394a0984de15bceeb97cbe1fe485f1ac205121293fc44dcf3f31f"},
+    {file = "h5py-2.10.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:86868dc07b9cc8cb7627372a2e6636cdc7a53b7e2854ad020c9e9d8a4d3fd0f5"},
+    {file = "h5py-2.10.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aac4b57097ac29089f179bbc2a6e14102dd210618e94d77ee4831c65f82f17c0"},
+    {file = "h5py-2.10.0-cp27-cp27m-win32.whl", hash = "sha256:7be5754a159236e95bd196419485343e2b5875e806fe68919e087b6351f40a70"},
+    {file = "h5py-2.10.0-cp27-cp27m-win_amd64.whl", hash = "sha256:13c87efa24768a5e24e360a40e0bc4c49bcb7ce1bb13a3a7f9902cec302ccd36"},
+    {file = "h5py-2.10.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:79b23f47c6524d61f899254f5cd5e486e19868f1823298bc0c29d345c2447172"},
+    {file = "h5py-2.10.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbf28ae4b5af0f05aa6e7551cee304f1d317dbed1eb7ac1d827cee2f1ef97a99"},
+    {file = "h5py-2.10.0-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:c0d4b04bbf96c47b6d360cd06939e72def512b20a18a8547fa4af810258355d5"},
+    {file = "h5py-2.10.0-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:549ad124df27c056b2e255ea1c44d30fb7a17d17676d03096ad5cd85edb32dc1"},
+    {file = "h5py-2.10.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:a5f82cd4938ff8761d9760af3274acf55afc3c91c649c50ab18fcff5510a14a5"},
+    {file = "h5py-2.10.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:3dad1730b6470fad853ef56d755d06bb916ee68a3d8272b3bab0c1ddf83bb99e"},
+    {file = "h5py-2.10.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:063947eaed5f271679ed4ffa36bb96f57bc14f44dd4336a827d9a02702e6ce6b"},
+    {file = "h5py-2.10.0-cp35-cp35m-win32.whl", hash = "sha256:c54a2c0dd4957776ace7f95879d81582298c5daf89e77fb8bee7378f132951de"},
+    {file = "h5py-2.10.0-cp35-cp35m-win_amd64.whl", hash = "sha256:6998be619c695910cb0effe5eb15d3a511d3d1a5d217d4bd0bebad1151ec2262"},
+    {file = "h5py-2.10.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:ff7d241f866b718e4584fa95f520cb19405220c501bd3a53ee11871ba5166ea2"},
+    {file = "h5py-2.10.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:54817b696e87eb9e403e42643305f142cd8b940fe9b3b490bbf98c3b8a894cf4"},
+    {file = "h5py-2.10.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d3c59549f90a891691991c17f8e58c8544060fdf3ccdea267100fa5f561ff62f"},
+    {file = "h5py-2.10.0-cp36-cp36m-win32.whl", hash = "sha256:d7ae7a0576b06cb8e8a1c265a8bc4b73d05fdee6429bffc9a26a6eb531e79d72"},
+    {file = "h5py-2.10.0-cp36-cp36m-win_amd64.whl", hash = "sha256:bffbc48331b4a801d2f4b7dac8a72609f0b10e6e516e5c480a3e3241e091c878"},
+    {file = "h5py-2.10.0-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:51ae56894c6c93159086ffa2c94b5b3388c0400548ab26555c143e7cfa05b8e5"},
+    {file = "h5py-2.10.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:16ead3c57141101e3296ebeed79c9c143c32bdd0e82a61a2fc67e8e6d493e9d1"},
+    {file = "h5py-2.10.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0e25bb91e7a02efccb50aba6591d3fe2c725479e34769802fcdd4076abfa917"},
+    {file = "h5py-2.10.0-cp37-cp37m-win32.whl", hash = "sha256:f23951a53d18398ef1344c186fb04b26163ca6ce449ebd23404b153fd111ded9"},
+    {file = "h5py-2.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8bb1d2de101f39743f91512a9750fb6c351c032e5cd3204b4487383e34da7f75"},
+    {file = "h5py-2.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:64f74da4a1dd0d2042e7d04cf8294e04ddad686f8eba9bb79e517ae582f6668d"},
+    {file = "h5py-2.10.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d35f7a3a6cefec82bfdad2785e78359a0e6a5fbb3f605dd5623ce88082ccd681"},
+    {file = "h5py-2.10.0-cp38-cp38-win32.whl", hash = "sha256:6ef7ab1089e3ef53ca099038f3c0a94d03e3560e6aff0e9d6c64c55fb13fc681"},
+    {file = "h5py-2.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:769e141512b54dee14ec76ed354fcacfc7d97fea5a7646b709f7400cf1838630"},
+    {file = "h5py-2.10.0.tar.gz", hash = "sha256:84412798925dc870ffd7107f045d7659e60f5d46d1c70c700375248bf6bf512d"},
+]
+idna = [
+    {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
+    {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
+]
+iniconfig = [
+    {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
+    {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
+]
+keras-preprocessing = [
+    {file = "Keras_Preprocessing-1.1.2-py2.py3-none-any.whl", hash = "sha256:7b82029b130ff61cc99b55f3bd27427df4838576838c5b2f65940e4fcec99a7b"},
+    {file = "Keras_Preprocessing-1.1.2.tar.gz", hash = "sha256:add82567c50c8bc648c14195bf544a5ce7c1f76761536956c3d2978970179ef3"},
+]
+kiwisolver = [
+    {file = "kiwisolver-1.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fd34fbbfbc40628200730bc1febe30631347103fc8d3d4fa012c21ab9c11eca9"},
+    {file = "kiwisolver-1.3.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:d3155d828dec1d43283bd24d3d3e0d9c7c350cdfcc0bd06c0ad1209c1bbc36d0"},
+    {file = "kiwisolver-1.3.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5a7a7dbff17e66fac9142ae2ecafb719393aaee6a3768c9de2fd425c63b53e21"},
+    {file = "kiwisolver-1.3.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f8d6f8db88049a699817fd9178782867bf22283e3813064302ac59f61d95be05"},
+    {file = "kiwisolver-1.3.1-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:5f6ccd3dd0b9739edcf407514016108e2280769c73a85b9e59aa390046dbf08b"},
+    {file = "kiwisolver-1.3.1-cp36-cp36m-win32.whl", hash = "sha256:225e2e18f271e0ed8157d7f4518ffbf99b9450fca398d561eb5c4a87d0986dd9"},
+    {file = "kiwisolver-1.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cf8b574c7b9aa060c62116d4181f3a1a4e821b2ec5cbfe3775809474113748d4"},
+    {file = "kiwisolver-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:232c9e11fd7ac3a470d65cd67e4359eee155ec57e822e5220322d7b2ac84fbf0"},
+    {file = "kiwisolver-1.3.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b38694dcdac990a743aa654037ff1188c7a9801ac3ccc548d3341014bc5ca278"},
+    {file = "kiwisolver-1.3.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ca3820eb7f7faf7f0aa88de0e54681bddcb46e485beb844fcecbcd1c8bd01689"},
+    {file = "kiwisolver-1.3.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:c8fd0f1ae9d92b42854b2979024d7597685ce4ada367172ed7c09edf2cef9cb8"},
+    {file = "kiwisolver-1.3.1-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:1e1bc12fb773a7b2ffdeb8380609f4f8064777877b2225dec3da711b421fda31"},
+    {file = "kiwisolver-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:72c99e39d005b793fb7d3d4e660aed6b6281b502e8c1eaf8ee8346023c8e03bc"},
+    {file = "kiwisolver-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:8be8d84b7d4f2ba4ffff3665bcd0211318aa632395a1a41553250484a871d454"},
+    {file = "kiwisolver-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:31dfd2ac56edc0ff9ac295193eeaea1c0c923c0355bf948fbd99ed6018010b72"},
+    {file = "kiwisolver-1.3.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:563c649cfdef27d081c84e72a03b48ea9408c16657500c312575ae9d9f7bc1c3"},
+    {file = "kiwisolver-1.3.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:78751b33595f7f9511952e7e60ce858c6d64db2e062afb325985ddbd34b5c131"},
+    {file = "kiwisolver-1.3.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a357fd4f15ee49b4a98b44ec23a34a95f1e00292a139d6015c11f55774ef10de"},
+    {file = "kiwisolver-1.3.1-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:5989db3b3b34b76c09253deeaf7fbc2707616f130e166996606c284395da3f18"},
+    {file = "kiwisolver-1.3.1-cp38-cp38-win32.whl", hash = "sha256:c08e95114951dc2090c4a630c2385bef681cacf12636fb0241accdc6b303fd81"},
+    {file = "kiwisolver-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:44a62e24d9b01ba94ae7a4a6c3fb215dc4af1dde817e7498d901e229aaf50e4e"},
+    {file = "kiwisolver-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:50af681a36b2a1dee1d3c169ade9fdc59207d3c31e522519181e12f1b3ba7000"},
+    {file = "kiwisolver-1.3.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:a53d27d0c2a0ebd07e395e56a1fbdf75ffedc4a05943daf472af163413ce9598"},
+    {file = "kiwisolver-1.3.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:834ee27348c4aefc20b479335fd422a2c69db55f7d9ab61721ac8cd83eb78882"},
+    {file = "kiwisolver-1.3.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5c3e6455341008a054cccee8c5d24481bcfe1acdbc9add30aa95798e95c65621"},
+    {file = "kiwisolver-1.3.1-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:acef3d59d47dd85ecf909c359d0fd2c81ed33bdff70216d3956b463e12c38a54"},
+    {file = "kiwisolver-1.3.1-cp39-cp39-win32.whl", hash = "sha256:c5518d51a0735b1e6cee1fdce66359f8d2b59c3ca85dc2b0813a8aa86818a030"},
+    {file = "kiwisolver-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:b9edd0110a77fc321ab090aaa1cfcaba1d8499850a12848b81be2222eab648f6"},
+    {file = "kiwisolver-1.3.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0cd53f403202159b44528498de18f9285b04482bab2a6fc3f5dd8dbb9352e30d"},
+    {file = "kiwisolver-1.3.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:33449715e0101e4d34f64990352bce4095c8bf13bed1b390773fc0a7295967b3"},
+    {file = "kiwisolver-1.3.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:401a2e9afa8588589775fe34fc22d918ae839aaaf0c0e96441c0fdbce6d8ebe6"},
+    {file = "kiwisolver-1.3.1.tar.gz", hash = "sha256:950a199911a8d94683a6b10321f9345d5a3a8433ec58b217ace979e18f16e248"},
+]
+markdown = [
+    {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"},
+    {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"},
+]
+matplotlib = [
+    {file = "matplotlib-3.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c541ee5a3287efe066bbe358320853cf4916bc14c00c38f8f3d8d75275a405a9"},
+    {file = "matplotlib-3.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3a5c18dbd2c7c366da26a4ad1462fe3e03a577b39e3b503bbcf482b9cdac093c"},
+    {file = "matplotlib-3.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a9d8cb5329df13e0cdaa14b3b43f47b5e593ec637f13f14db75bb16e46178b05"},
+    {file = "matplotlib-3.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:7ad19f3fb6145b9eb41c08e7cbb9f8e10b91291396bee21e9ce761bb78df63ec"},
+    {file = "matplotlib-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:7a58f3d8fe8fac3be522c79d921c9b86e090a59637cb88e3bc51298d7a2c862a"},
+    {file = "matplotlib-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6382bc6e2d7e481bcd977eb131c31dee96e0fb4f9177d15ec6fb976d3b9ace1a"},
+    {file = "matplotlib-3.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6a6a44f27aabe720ec4fd485061e8a35784c2b9ffa6363ad546316dfc9cea04e"},
+    {file = "matplotlib-3.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1c1779f7ab7d8bdb7d4c605e6ffaa0614b3e80f1e3c8ccf7b9269a22dbc5986b"},
+    {file = "matplotlib-3.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5826f56055b9b1c80fef82e326097e34dc4af8c7249226b7dd63095a686177d1"},
+    {file = "matplotlib-3.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0bea5ec5c28d49020e5d7923c2725b837e60bc8be99d3164af410eb4b4c827da"},
+    {file = "matplotlib-3.4.2-cp38-cp38-win32.whl", hash = "sha256:6475d0209024a77f869163ec3657c47fed35d9b6ed8bccba8aa0f0099fbbdaa8"},
+    {file = "matplotlib-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:21b31057bbc5e75b08e70a43cefc4c0b2c2f1b1a850f4a0f7af044eb4163086c"},
+    {file = "matplotlib-3.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b26535b9de85326e6958cdef720ecd10bcf74a3f4371bf9a7e5b2e659c17e153"},
+    {file = "matplotlib-3.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:32fa638cc10886885d1ca3d409d4473d6a22f7ceecd11322150961a70fab66dd"},
+    {file = "matplotlib-3.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:956c8849b134b4a343598305a3ca1bdd3094f01f5efc8afccdebeffe6b315247"},
+    {file = "matplotlib-3.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:85f191bb03cb1a7b04b5c2cca4792bef94df06ef473bc49e2818105671766fee"},
+    {file = "matplotlib-3.4.2-cp39-cp39-win32.whl", hash = "sha256:b1d5a2cedf5de05567c441b3a8c2651fbde56df08b82640e7f06c8cd91e201f6"},
+    {file = "matplotlib-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:df815378a754a7edd4559f8c51fc7064f779a74013644a7f5ac7a0c31f875866"},
+    {file = "matplotlib-3.4.2.tar.gz", hash = "sha256:d8d994cefdff9aaba45166eb3de4f5211adb4accac85cbf97137e98f26ea0219"},
+]
+mccabe = [
+    {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
+    {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
+]
+mpmath = [
+    {file = "mpmath-1.2.1-py3-none-any.whl", hash = "sha256:604bc21bd22d2322a177c73bdb573994ef76e62edd595d17e00aff24b0667e5c"},
+    {file = "mpmath-1.2.1.tar.gz", hash = "sha256:79ffb45cf9f4b101a807595bcb3e72e0396202e0b1d25d689134b48c4216a81a"},
+]
+mypy-extensions = [
+    {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
+    {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"},
+]
+numpy = [
+    {file = "numpy-1.18.5-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:e91d31b34fc7c2c8f756b4e902f901f856ae53a93399368d9a0dc7be17ed2ca0"},
+    {file = "numpy-1.18.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7d42ab8cedd175b5ebcb39b5208b25ba104842489ed59fbb29356f671ac93583"},
+    {file = "numpy-1.18.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a78e438db8ec26d5d9d0e584b27ef25c7afa5a182d1bf4d05e313d2d6d515271"},
+    {file = "numpy-1.18.5-cp35-cp35m-win32.whl", hash = "sha256:a87f59508c2b7ceb8631c20630118cc546f1f815e034193dc72390db038a5cb3"},
+    {file = "numpy-1.18.5-cp35-cp35m-win_amd64.whl", hash = "sha256:965df25449305092b23d5145b9bdaeb0149b6e41a77a7d728b1644b3c99277c1"},
+    {file = "numpy-1.18.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ac792b385d81151bae2a5a8adb2b88261ceb4976dbfaaad9ce3a200e036753dc"},
+    {file = "numpy-1.18.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:ef627986941b5edd1ed74ba89ca43196ed197f1a206a3f18cc9faf2fb84fd675"},
+    {file = "numpy-1.18.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f718a7949d1c4f622ff548c572e0c03440b49b9531ff00e4ed5738b459f011e8"},
+    {file = "numpy-1.18.5-cp36-cp36m-win32.whl", hash = "sha256:4064f53d4cce69e9ac613256dc2162e56f20a4e2d2086b1956dd2fcf77b7fac5"},
+    {file = "numpy-1.18.5-cp36-cp36m-win_amd64.whl", hash = "sha256:b03b2c0badeb606d1232e5f78852c102c0a7989d3a534b3129e7856a52f3d161"},
+    {file = "numpy-1.18.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a7acefddf994af1aeba05bbbafe4ba983a187079f125146dc5859e6d817df824"},
+    {file = "numpy-1.18.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cd49930af1d1e49a812d987c2620ee63965b619257bd76eaaa95870ca08837cf"},
+    {file = "numpy-1.18.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b39321f1a74d1f9183bf1638a745b4fd6fe80efbb1f6b32b932a588b4bc7695f"},
+    {file = "numpy-1.18.5-cp37-cp37m-win32.whl", hash = "sha256:cae14a01a159b1ed91a324722d746523ec757357260c6804d11d6147a9e53e3f"},
+    {file = "numpy-1.18.5-cp37-cp37m-win_amd64.whl", hash = "sha256:0172304e7d8d40e9e49553901903dc5f5a49a703363ed756796f5808a06fc233"},
+    {file = "numpy-1.18.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e15b382603c58f24265c9c931c9a45eebf44fe2e6b4eaedbb0d025ab3255228b"},
+    {file = "numpy-1.18.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3676abe3d621fc467c4c1469ee11e395c82b2d6b5463a9454e37fe9da07cd0d7"},
+    {file = "numpy-1.18.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:4674f7d27a6c1c52a4d1aa5f0881f1eff840d2206989bae6acb1c7668c02ebfb"},
+    {file = "numpy-1.18.5-cp38-cp38-win32.whl", hash = "sha256:9c9d6531bc1886454f44aa8f809268bc481295cf9740827254f53c30104f074a"},
+    {file = "numpy-1.18.5-cp38-cp38-win_amd64.whl", hash = "sha256:3dd6823d3e04b5f223e3e265b4a1eae15f104f4366edd409e5a5e413a98f911f"},
+    {file = "numpy-1.18.5.zip", hash = "sha256:34e96e9dae65c4839bd80012023aadd6ee2ccb73ce7fdf3074c62f301e63120b"},
+]
+oauthlib = [
+    {file = "oauthlib-3.1.0-py2.py3-none-any.whl", hash = "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"},
+    {file = "oauthlib-3.1.0.tar.gz", hash = "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889"},
+]
+opt-einsum = [
+    {file = "opt_einsum-3.3.0-py3-none-any.whl", hash = "sha256:2455e59e3947d3c275477df7f5205b30635e266fe6dc300e3d9f9646bfcea147"},
+    {file = "opt_einsum-3.3.0.tar.gz", hash = "sha256:59f6475f77bbc37dcf7cd748519c0ec60722e91e63ca114e68821c0c54a46549"},
+]
+packaging = [
+    {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"},
+    {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"},
+]
+pandas = [
+    {file = "pandas-1.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c601c6fdebc729df4438ec1f62275d6136a0dd14d332fc0e8ce3f7d2aadb4dd6"},
+    {file = "pandas-1.2.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8d4c74177c26aadcfb4fd1de6c1c43c2bf822b3e0fc7a9b409eeaf84b3e92aaa"},
+    {file = "pandas-1.2.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b730add5267f873b3383c18cac4df2527ac4f0f0eed1c6cf37fcb437e25cf558"},
+    {file = "pandas-1.2.4-cp37-cp37m-win32.whl", hash = "sha256:2cb7e8f4f152f27dc93f30b5c7a98f6c748601ea65da359af734dd0cf3fa733f"},
+    {file = "pandas-1.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:2111c25e69fa9365ba80bbf4f959400054b2771ac5d041ed19415a8b488dc70a"},
+    {file = "pandas-1.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:167693a80abc8eb28051fbd184c1b7afd13ce2c727a5af47b048f1ea3afefff4"},
+    {file = "pandas-1.2.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:612add929bf3ba9d27b436cc8853f5acc337242d6b584203f207e364bb46cb12"},
+    {file = "pandas-1.2.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:971e2a414fce20cc5331fe791153513d076814d30a60cd7348466943e6e909e4"},
+    {file = "pandas-1.2.4-cp38-cp38-win32.whl", hash = "sha256:68d7baa80c74aaacbed597265ca2308f017859123231542ff8a5266d489e1858"},
+    {file = "pandas-1.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:bd659c11a4578af740782288cac141a322057a2e36920016e0fc7b25c5a4b686"},
+    {file = "pandas-1.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9db70ffa8b280bb4de83f9739d514cd0735825e79eef3a61d312420b9f16b758"},
+    {file = "pandas-1.2.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:298f0553fd3ba8e002c4070a723a59cdb28eda579f3e243bc2ee397773f5398b"},
+    {file = "pandas-1.2.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52d2472acbb8a56819a87aafdb8b5b6d2b3386e15c95bde56b281882529a7ded"},
+    {file = "pandas-1.2.4-cp39-cp39-win32.whl", hash = "sha256:d0877407359811f7b853b548a614aacd7dea83b0c0c84620a9a643f180060950"},
+    {file = "pandas-1.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:2b063d41803b6a19703b845609c0b700913593de067b552a8b24dd8eeb8c9895"},
+    {file = "pandas-1.2.4.tar.gz", hash = "sha256:649ecab692fade3cbfcf967ff936496b0cfba0af00a55dfaacd82bdda5cb2279"},
+]
+pathspec = [
+    {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"},
+    {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"},
+]
+pillow = [
+    {file = "Pillow-8.2.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:dc38f57d8f20f06dd7c3161c59ca2c86893632623f33a42d592f097b00f720a9"},
+    {file = "Pillow-8.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a013cbe25d20c2e0c4e85a9daf438f85121a4d0344ddc76e33fd7e3965d9af4b"},
+    {file = "Pillow-8.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8bb1e155a74e1bfbacd84555ea62fa21c58e0b4e7e6b20e4447b8d07990ac78b"},
+    {file = "Pillow-8.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c5236606e8570542ed424849f7852a0ff0bce2c4c8d0ba05cc202a5a9c97dee9"},
+    {file = "Pillow-8.2.0-cp36-cp36m-win32.whl", hash = "sha256:12e5e7471f9b637762453da74e390e56cc43e486a88289995c1f4c1dc0bfe727"},
+    {file = "Pillow-8.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5afe6b237a0b81bd54b53f835a153770802f164c5570bab5e005aad693dab87f"},
+    {file = "Pillow-8.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:cb7a09e173903541fa888ba010c345893cd9fc1b5891aaf060f6ca77b6a3722d"},
+    {file = "Pillow-8.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0d19d70ee7c2ba97631bae1e7d4725cdb2ecf238178096e8c82ee481e189168a"},
+    {file = "Pillow-8.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:083781abd261bdabf090ad07bb69f8f5599943ddb539d64497ed021b2a67e5a9"},
+    {file = "Pillow-8.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:c6b39294464b03457f9064e98c124e09008b35a62e3189d3513e5148611c9388"},
+    {file = "Pillow-8.2.0-cp37-cp37m-win32.whl", hash = "sha256:01425106e4e8cee195a411f729cff2a7d61813b0b11737c12bd5991f5f14bcd5"},
+    {file = "Pillow-8.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3b570f84a6161cf8865c4e08adf629441f56e32f180f7aa4ccbd2e0a5a02cba2"},
+    {file = "Pillow-8.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:031a6c88c77d08aab84fecc05c3cde8414cd6f8406f4d2b16fed1e97634cc8a4"},
+    {file = "Pillow-8.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:66cc56579fd91f517290ab02c51e3a80f581aba45fd924fcdee01fa06e635812"},
+    {file = "Pillow-8.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c32cc3145928c4305d142ebec682419a6c0a8ce9e33db900027ddca1ec39178"},
+    {file = "Pillow-8.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:624b977355cde8b065f6d51b98497d6cd5fbdd4f36405f7a8790e3376125e2bb"},
+    {file = "Pillow-8.2.0-cp38-cp38-win32.whl", hash = "sha256:5cbf3e3b1014dddc45496e8cf38b9f099c95a326275885199f427825c6522232"},
+    {file = "Pillow-8.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:463822e2f0d81459e113372a168f2ff59723e78528f91f0bd25680ac185cf797"},
+    {file = "Pillow-8.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:95d5ef984eff897850f3a83883363da64aae1000e79cb3c321915468e8c6add5"},
+    {file = "Pillow-8.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b91c36492a4bbb1ee855b7d16fe51379e5f96b85692dc8210831fbb24c43e484"},
+    {file = "Pillow-8.2.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d68cb92c408261f806b15923834203f024110a2e2872ecb0bd2a110f89d3c602"},
+    {file = "Pillow-8.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f217c3954ce5fd88303fc0c317af55d5e0204106d86dea17eb8205700d47dec2"},
+    {file = "Pillow-8.2.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5b70110acb39f3aff6b74cf09bb4169b167e2660dabc304c1e25b6555fa781ef"},
+    {file = "Pillow-8.2.0-cp39-cp39-win32.whl", hash = "sha256:a7d5e9fad90eff8f6f6106d3b98b553a88b6f976e51fce287192a5d2d5363713"},
+    {file = "Pillow-8.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:238c197fc275b475e87c1453b05b467d2d02c2915fdfdd4af126145ff2e4610c"},
+    {file = "Pillow-8.2.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0e04d61f0064b545b989126197930807c86bcbd4534d39168f4aa5fda39bb8f9"},
+    {file = "Pillow-8.2.0-pp36-pypy36_pp73-manylinux2010_i686.whl", hash = "sha256:63728564c1410d99e6d1ae8e3b810fe012bc440952168af0a2877e8ff5ab96b9"},
+    {file = "Pillow-8.2.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:c03c07ed32c5324939b19e36ae5f75c660c81461e312a41aea30acdd46f93a7c"},
+    {file = "Pillow-8.2.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:4d98abdd6b1e3bf1a1cbb14c3895226816e666749ac040c4e2554231068c639b"},
+    {file = "Pillow-8.2.0-pp37-pypy37_pp73-manylinux2010_i686.whl", hash = "sha256:aac00e4bc94d1b7813fe882c28990c1bc2f9d0e1aa765a5f2b516e8a6a16a9e4"},
+    {file = "Pillow-8.2.0-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:22fd0f42ad15dfdde6c581347eaa4adb9a6fc4b865f90b23378aa7914895e120"},
+    {file = "Pillow-8.2.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:e98eca29a05913e82177b3ba3d198b1728e164869c613d76d0de4bde6768a50e"},
+    {file = "Pillow-8.2.0.tar.gz", hash = "sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1"},
+]
+pluggy = [
+    {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
+    {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
+]
+protobuf = [
+    {file = "protobuf-3.12.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3d59825cba9447e8f4fcacc1f3c892cafd28b964e152629b3f420a2fb5918b5a"},
+    {file = "protobuf-3.12.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6009f3ebe761fad319b52199a49f1efa7a3729302947a78a3f5ea8e7e89e3ac2"},
+    {file = "protobuf-3.12.4-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:e2bd5c98952db3f1bb1af2e81b6a208909d3b8a2d32f7525c5cc10a6338b6593"},
+    {file = "protobuf-3.12.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:2becd0e238ae34caf96fa7365b87f65b88aebcf7864dfe5ab461c5005f4256d9"},
+    {file = "protobuf-3.12.4-cp35-cp35m-win32.whl", hash = "sha256:ef991cbe34d7bb935ba6349406a210d3558b9379c21621c6ed7b99112af7350e"},
+    {file = "protobuf-3.12.4-cp35-cp35m-win_amd64.whl", hash = "sha256:a7b6cf201e67132ca99b8a6c4812fab541fdce1ceb54bb6f66bc336ab7259138"},
+    {file = "protobuf-3.12.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4794a7748ee645d2ae305f3f4f0abd459e789c973b5bc338008960f83e0c554b"},
+    {file = "protobuf-3.12.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f1796e0eb911bf5b08e76b753953effbeb6bc42c95c16597177f627eaa52c375"},
+    {file = "protobuf-3.12.4-cp36-cp36m-win32.whl", hash = "sha256:c0c8d7c8f07eacd9e98a907941b56e57883cf83de069cfaeaa7e02c582f72ddb"},
+    {file = "protobuf-3.12.4-cp36-cp36m-win_amd64.whl", hash = "sha256:2db6940c1914fa3fbfabc0e7c8193d9e18b01dbb4650acac249b113be3ba8d9e"},
+    {file = "protobuf-3.12.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6842284bb15f1b19c50c5fd496f1e2a4cfefdbdfa5d25c02620cb82793295a7"},
+    {file = "protobuf-3.12.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0b00429b87821f1e6f3d641327864e6f271763ae61799f7540bc58a352825fe2"},
+    {file = "protobuf-3.12.4-cp37-cp37m-win32.whl", hash = "sha256:f10ba89f9cd508dc00e469918552925ef7cba38d101ca47af1e78f2f9982c6b3"},
+    {file = "protobuf-3.12.4-cp37-cp37m-win_amd64.whl", hash = "sha256:2636c689a6a2441da9a2ef922a21f9b8bfd5dfe676abd77d788db4b36ea86bee"},
+    {file = "protobuf-3.12.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:50b7bb2124f6a1fb0ddc6a44428ae3a21e619ad2cdf08130ac6c00534998ef07"},
+    {file = "protobuf-3.12.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e77ca4e1403b363a88bde9e31c11d093565e925e1685f40b29385a52f2320794"},
+    {file = "protobuf-3.12.4-py2.py3-none-any.whl", hash = "sha256:32f0bcdf85e0040f36b4f548c71177027f2a618cab00ba235197fa9e230b7289"},
+    {file = "protobuf-3.12.4.tar.gz", hash = "sha256:c99e5aea75b6f2b29c8d8da5bdc5f5ed8d9a5b4f15115c8316a3f0a850f94656"},
+]
+py = [
+    {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
+    {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
+]
+pyasn1 = [
+    {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"},
+    {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"},
+    {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"},
+    {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"},
+    {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"},
+    {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"},
+    {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"},
+    {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"},
+    {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"},
+    {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"},
+    {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"},
+    {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"},
+    {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"},
+]
+pyasn1-modules = [
+    {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"},
+    {file = "pyasn1_modules-0.2.8-py2.4.egg", hash = "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"},
+    {file = "pyasn1_modules-0.2.8-py2.5.egg", hash = "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"},
+    {file = "pyasn1_modules-0.2.8-py2.6.egg", hash = "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb"},
+    {file = "pyasn1_modules-0.2.8-py2.7.egg", hash = "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8"},
+    {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"},
+    {file = "pyasn1_modules-0.2.8-py3.1.egg", hash = "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d"},
+    {file = "pyasn1_modules-0.2.8-py3.2.egg", hash = "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45"},
+    {file = "pyasn1_modules-0.2.8-py3.3.egg", hash = "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4"},
+    {file = "pyasn1_modules-0.2.8-py3.4.egg", hash = "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811"},
+    {file = "pyasn1_modules-0.2.8-py3.5.egg", hash = "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed"},
+    {file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"},
+    {file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"},
+]
+pycodestyle = [
+    {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"},
+    {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
+]
+pyflakes = [
+    {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
+    {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
+]
+pyparsing = [
+    {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
+    {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
+]
+pytest = [
+    {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"},
+    {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"},
+]
+pytest-cov = [
+    {file = "pytest-cov-2.11.1.tar.gz", hash = "sha256:359952d9d39b9f822d9d29324483e7ba04a3a17dd7d05aa6beb7ea01e359e5f7"},
+    {file = "pytest_cov-2.11.1-py2.py3-none-any.whl", hash = "sha256:bdb9fdb0b85a7cc825269a4c56b48ccaa5c7e365054b6038772c32ddcdc969da"},
+]
+python-dateutil = [
+    {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
+    {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
+]
+pytz = [
+    {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"},
+    {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
+]
+regex = [
+    {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"},
+    {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"},
+    {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"},
+    {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"},
+    {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"},
+    {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"},
+    {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"},
+    {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"},
+    {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"},
+    {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"},
+    {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"},
+    {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"},
+    {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"},
+]
+requests = [
+    {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
+    {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
+]
+requests-oauthlib = [
+    {file = "requests-oauthlib-1.3.0.tar.gz", hash = "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"},
+    {file = "requests_oauthlib-1.3.0-py2.py3-none-any.whl", hash = "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d"},
+    {file = "requests_oauthlib-1.3.0-py3.7.egg", hash = "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"},
+]
+rsa = [
+    {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"},
+    {file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"},
+]
+scipy = [
+    {file = "scipy-1.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2a799714bf1f791fb2650d73222b248d18d53fd40d6af2df2c898db048189606"},
+    {file = "scipy-1.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9e3302149a369697c6aaea18b430b216e3c88f9a61b62869f6104881e5f9ef85"},
+    {file = "scipy-1.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:b79104878003487e2b4639a20b9092b02e1bad07fc4cf924b495cf413748a777"},
+    {file = "scipy-1.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:44d452850f77e65e25b1eb1ac01e25770323a782bfe3a1a3e43847ad4266d93d"},
+    {file = "scipy-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:b30280fbc1fd8082ac822994a98632111810311a9ece71a0e48f739df3c555a2"},
+    {file = "scipy-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:10dbcc7de03b8d635a1031cb18fd3eaa997969b64fdf78f99f19ac163a825445"},
+    {file = "scipy-1.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b21c6e0dc97b1762590b70dee0daddb291271be0580384d39f02c480b78290a"},
+    {file = "scipy-1.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1caade0ede6967cc675e235c41451f9fb89ae34319ddf4740194094ab736b88d"},
+    {file = "scipy-1.6.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:19aeac1ad3e57338723f4657ac8520f41714804568f2e30bd547d684d72c392e"},
+    {file = "scipy-1.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:ad7269254de06743fb4768f658753de47d8b54e4672c5ebe8612a007a088bd48"},
+    {file = "scipy-1.6.3-cp38-cp38-win32.whl", hash = "sha256:d647757373985207af3343301d89fe738d5a294435a4f2aafb04c13b4388c896"},
+    {file = "scipy-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:33d1677d46111cfa1c84b87472a0274dde9ef4a7ef2e1f155f012f5f1e995d8f"},
+    {file = "scipy-1.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d449d40e830366b4c612692ad19fbebb722b6b847f78a7b701b1e0d6cda3cc13"},
+    {file = "scipy-1.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:23995dfcf269ec3735e5a8c80cfceaf384369a47699df111a6246b83a55da582"},
+    {file = "scipy-1.6.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fdf606341cd798530b05705c87779606fcdfaf768a8129c348ea94441da15b04"},
+    {file = "scipy-1.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f68eb46b86b2c246af99fcaa6f6e37c7a7a413e1084a794990b877f2ff71f7b6"},
+    {file = "scipy-1.6.3-cp39-cp39-win32.whl", hash = "sha256:01b38dec7e9f897d4db04f8de4e20f0f5be3feac98468188a0f47a991b796055"},
+    {file = "scipy-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:3274ce145b5dc416c49c0cf8b6119f787f0965cd35e22058fe1932c09fe15d77"},
+    {file = "scipy-1.6.3.tar.gz", hash = "sha256:a75b014d3294fce26852a9d04ea27b5671d86736beb34acdfc05859246260707"},
+]
+six = [
+    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+sortedcontainers = [
+    {file = "sortedcontainers-2.3.0-py2.py3-none-any.whl", hash = "sha256:37257a32add0a3ee490bb170b599e93095eed89a55da91fa9f48753ea12fd73f"},
+    {file = "sortedcontainers-2.3.0.tar.gz", hash = "sha256:59cc937650cf60d677c16775597c89a960658a09cf7c1a668f86e1e4464b10a1"},
+]
+sympy = [
+    {file = "sympy-1.5-py2.py3-none-any.whl", hash = "sha256:8ae4a95378304ed4081921767fe46f0adf5921bf471c9f5df425abf2c655d751"},
+    {file = "sympy-1.5.tar.gz", hash = "sha256:31567dc010bff0967ef7a87210acf3f938c6ab24481581fc143536fb103e9ce8"},
+]
+tensorboard = [
+    {file = "tensorboard-2.5.0-py3-none-any.whl", hash = "sha256:e167460085b6528956b33bab1c970c989cdce47a6616273880733f5e7bde452e"},
+]
+tensorboard-data-server = [
+    {file = "tensorboard_data_server-0.6.1-py3-none-any.whl", hash = "sha256:809fe9887682d35c1f7d1f54f0f40f98bb1f771b14265b453ca051e2ce58fca7"},
+    {file = "tensorboard_data_server-0.6.1-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:fa8cef9be4fcae2f2363c88176638baf2da19c5ec90addb49b1cde05c95c88ee"},
+    {file = "tensorboard_data_server-0.6.1-py3-none-manylinux2010_x86_64.whl", hash = "sha256:d8237580755e58eff68d1f3abefb5b1e39ae5c8b127cc40920f9c4fb33f4b98a"},
+]
+tensorboard-plugin-wit = [
+    {file = "tensorboard_plugin_wit-1.8.0-py3-none-any.whl", hash = "sha256:2a80d1c551d741e99b2f197bb915d8a133e24adb8da1732b840041860f91183a"},
+]
+tensorflow = [
+    {file = "tensorflow-2.3.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:8490c06c72d6b2227f0bda4800bfbe9004ade3f25f5ccaac2581531bf2885ab5"},
+    {file = "tensorflow-2.3.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:85c49c951d735c651ae989a6dd7a40ab8032317179d634f871e2e7556dc82a69"},
+    {file = "tensorflow-2.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:94c7d1916844fd7db53dd8d9b2c88b48119d39992ae542ec8a076d6f806cc989"},
+    {file = "tensorflow-2.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:68afc5f01f32827a53c23a9aa8cd404cdcf308e90942d4a8023e7f9e669a330a"},
+    {file = "tensorflow-2.3.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f4aa1dd6e7a040c29b3567ad1f4537aebeb58fcb6bafbc11f11c2c461d6fda63"},
+    {file = "tensorflow-2.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:4632c2c6c84ed3b5e29e4b292704a1a646e1aa06587b7a2404b6ecc99e07758a"},
+    {file = "tensorflow-2.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f72edee9d2e8861edbb9e082608fd21de7113580b3fdaa4e194b472c2e196d0"},
+    {file = "tensorflow-2.3.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:859afb9166ace41ee71f62938fc645981113bb3227b847c8cd2875549c9fa1dc"},
+    {file = "tensorflow-2.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b69a6f0a8e7158c3bc14b22ec0d03bd303e196644d5428094bacea0ed8507af7"},
+    {file = "tensorflow-2.3.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:cdce1f71f592d840dd3e05b67f1010f616311d9856250ff772db537f39ef2992"},
+    {file = "tensorflow-2.3.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:87750a476aa6f76b3aad5e6182faf2a3036a3d4c0db3b6d7463ebbaf4b184a23"},
+    {file = "tensorflow-2.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:87b62ab25816597a5e5352604b383b292eafd19a33ae7848b5275ea74fc4da1d"},
+]
+tensorflow-estimator = [
+    {file = "tensorflow_estimator-2.3.0-py2.py3-none-any.whl", hash = "sha256:b75e034300ccb169403cf2695adf3368da68863aeb0c14c3760064c713d5c486"},
+]
+tensorflow-probability = [
+    {file = "tensorflow_probability-0.11.0-py2.py3-none-any.whl", hash = "sha256:60e66a376f8b3602d3f61b0ac0bf844796b2cc10c104a13bced5cb65e1770eae"},
+]
+tensorflow-quantum = [
+    {file = "tensorflow_quantum-0.4.0-cp36-cp36m-macosx_10_11_x86_64.whl", hash = "sha256:918c4bfb54d8c077671e8fe510ce80fbe3fbe050fc370ab11c3d00250b0724ac"},
+    {file = "tensorflow_quantum-0.4.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f5253091301b8131639b49abe160b08d507fe8a92fd8575842f50b881c299dcd"},
+    {file = "tensorflow_quantum-0.4.0-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:a2375b9e0978d2451a4da8b0df8dd723a705e8997bb50c46bc7f524c8d8a0342"},
+    {file = "tensorflow_quantum-0.4.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7e5630b129c68d000cde1a92d9c58a193bdc6d2417610d781fd5493fc20dfdc0"},
+    {file = "tensorflow_quantum-0.4.0-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:213745062ab58e73f8c217976cf45e8c391ee2d624885620d78ff1c64797722b"},
+    {file = "tensorflow_quantum-0.4.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a8833a6d754819e3ef34791ce0c258b34dcf6d689bc1147f5f864637a029754a"},
+]
+termcolor = [
+    {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"},
+]
+toml = [
+    {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
+    {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
+]
+typing-extensions = [
+    {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
+    {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
+    {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"},
+]
+urllib3 = [
+    {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"},
+    {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"},
+]
+werkzeug = [
+    {file = "Werkzeug-2.0.0-py3-none-any.whl", hash = "sha256:64c02f6495ba01eddd6625b3675f357cd358a73f1e38458a56ad86c5baa30b53"},
+    {file = "Werkzeug-2.0.0.tar.gz", hash = "sha256:3389bbfe6d40c6dd25e6d3f974155163c8b3de5bbda6a89342d4ab93fae80ba0"},
+]
+wrapt = [
+    {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"},
+]
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..76923339
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,36 @@
+[tool.poetry]
+name = "qhbm-library"
+version = "0.1.0"
+description = "Quantum Hamiltonian-Based Models built on TensorFlow Quantum"
+license = "Apache-2.0"
+readme = "README.md"
+homepage = "https://github.com/google/qhbm-library"
+repository = "https://github.com/google/qhbm-library"
+keywords = ["quantum-computing"]
+authors = ["The QHBM Library Authors"]
+
+[tool.poetry.dependencies]
+python = "~3.8"
+tensorflow-quantum = "0.4.0"
+tensorflow = "2.3.1"
+tensorflow-probability = "0.11.0"
+
+[tool.poetry.dev-dependencies]
+coverage = {extras = ["toml"], version = "~5.5"}
+pytest-cov = "~2.11.1"
+black = "21.5b1"
+flake8 = "3.9.2"
+
+[tool.coverage.paths]
+source = ["qhbm_libary"]
+
+[tool.coverage.run]
+branch = true
+source = ["qhbm_library"]
+
+[tool.coverage.report]
+show_missing = true
+
+[build-system]
+requires = ["poetry-core~=1.1.6"]
+build-backend = "poetry.core.masonry.api"
diff --git a/qhbm_library/__init__.py b/qhbm_library/__init__.py
index e69de29b..3dc1f76b 100644
--- a/qhbm_library/__init__.py
+++ b/qhbm_library/__init__.py
@@ -0,0 +1,1 @@
+__version__ = "0.1.0"
diff --git a/qhbm_library/architectures.py b/qhbm_library/architectures.py
index 07f9ba93..4384fa23 100644
--- a/qhbm_library/architectures.py
+++ b/qhbm_library/architectures.py
@@ -489,38 +489,39 @@ def two_qubit_pool(source_qubit, sink_qubit, symbols):
     return pool_circuit
 
 
-def quantum_convolutional_layer(qubits, layer_num, name):
-    """Assumes the qubits are arranged on a grid."""
-    qubit_grid = qubits_to_grid(qubits)
-    layer_symbols = []
-    circuit = cirq.Circuit()
-    tied_2q_symbols = [
-        sympy.Symbol("s_conv_I{0}_L{1}_N{2}".format(name, layer_num, s_num))
-        for s_num in range(15)
-    ]
-    # Apply horizontal bonds
-    for r in qubit_grid:
-        r_clipped = r[1:]
-        for alt_r in [r, r_clipped]:
-            for q0, q1 in zip(alt_r[::2], alt_r[1::2]):
-                circuit += two_qubit_unitary(q0, q1, tied_2q_symbols)
-    # Apply vertical bonds
-    grid_clipped = qubit_grid[1:]
-    for r0, r1 in zip(qubit_grid[::2], qubit_grid[1::2]):
-        for q0, q1 in zip(r0, r1):
-            circuit += two_qubit_unitary(q0, q1, tied_2q_symbols)
-    for r0, r1 in zip(grid_clipped[::2], grid_clipped[1::2]):
-        for q0, q1 in zip(r0, r1):
-            circuit += two_qubit_unitary(q0, q1, tied_2q_symbols)
-    return circuit, tied_2q_symbols
-
-
-def quantum_pool_layer(qubits, layer_num, name, direction_flag):
-    """Assumes the qubits are arranged on a grid."""
-    qubit_grid = qubits_to_grid(qubits)
-    layer_symbols = []
-    circuit = cirq.Circuit()
-    tied_pool_symbols = [
-        sympy.Symbol("s_pool_I{0}_L{1}_N{2}".format(name, layer_num, s_num))
-        for s_num in range(6)
-    ]
+# TODO(#19)
+# def quantum_convolutional_layer(qubits, layer_num, name):
+#     """Assumes the qubits are arranged on a grid."""
+#     qubit_grid = qubits_to_grid(qubits)
+#     layer_symbols = []
+#     circuit = cirq.Circuit()
+#     tied_2q_symbols = [
+#         sympy.Symbol("s_conv_I{0}_L{1}_N{2}".format(name, layer_num, s_num))
+#         for s_num in range(15)
+#     ]
+#     # Apply horizontal bonds
+#     for r in qubit_grid:
+#         r_clipped = r[1:]
+#         for alt_r in [r, r_clipped]:
+#             for q0, q1 in zip(alt_r[::2], alt_r[1::2]):
+#                 circuit += two_qubit_unitary(q0, q1, tied_2q_symbols)
+#     # Apply vertical bonds
+#     grid_clipped = qubit_grid[1:]
+#     for r0, r1 in zip(qubit_grid[::2], qubit_grid[1::2]):
+#         for q0, q1 in zip(r0, r1):
+#             circuit += two_qubit_unitary(q0, q1, tied_2q_symbols)
+#     for r0, r1 in zip(grid_clipped[::2], grid_clipped[1::2]):
+#         for q0, q1 in zip(r0, r1):
+#             circuit += two_qubit_unitary(q0, q1, tied_2q_symbols)
+#     return circuit, tied_2q_symbols
+
+
+# def quantum_pool_layer(qubits, layer_num, name, direction_flag):
+#     """Assumes the qubits are arranged on a grid."""
+#     qubit_grid = qubits_to_grid(qubits)
+#     layer_symbols = []
+#     circuit = cirq.Circuit()
+#     tied_pool_symbols = [
+#         sympy.Symbol("s_pool_I{0}_L{1}_N{2}".format(name, layer_num, s_num))
+#         for s_num in range(6)
+#     ]
diff --git a/qhbm_library/ebm.py b/qhbm_library/ebm.py
index f4309b5a..c43d6e6d 100644
--- a/qhbm_library/ebm.py
+++ b/qhbm_library/ebm.py
@@ -184,8 +184,6 @@ def all_probabilities(thetas):
         @tf.function
         def sampler_boltzmann(thetas, num_samples):
             print("retracing: sampler_boltzmann_{}".format(identifier))
-            Z = partition_boltzmann(thetas)
-            exponentials = all_exponentials(thetas)
             raw_samples = tfp.distributions.Categorical(
                 logits=tf.multiply(
                     tf.constant(-1, dtype=tf.float32), all_energies(thetas)
@@ -366,7 +364,6 @@ def get_swish_network(num_bits, num_layers):
     n_init_params = num_bits * h_w + h_w
     n_hidden_params = h_w ** 2 + h_w
     n_hidden_params_total = n_hidden_params * num_layers
-    n_final_params = h_w + 1
 
     this_initial_layer = get_initial_layer(num_bits)
 
@@ -563,7 +560,7 @@ def __init__(self, inner_kernel):
     @tf.function
     def one_step(self, current_state, previous_kernel_results):
         print("retracing: one_step")
-        [proposed_state, proposed_results,] = self.inner_kernel.one_step(
+        [proposed_state, proposed_results] = self.inner_kernel.one_step(
             current_state, previous_kernel_results.accepted_results
         )
         log_accept_ratio = (
diff --git a/qhbm_library/qhbm_base.py b/qhbm_library/qhbm_base.py
index 26029578..5dd3a48c 100644
--- a/qhbm_library/qhbm_base.py
+++ b/qhbm_library/qhbm_base.py
@@ -518,294 +518,295 @@ def fidelity(self, sigma: tf.Tensor):
         )
 
 
-class QHBMQ(tf.Module):
-    def __init__(
-        self,
-        p,
-        initial_etas,
-        initial_classical_thetas,
-        eta_theta_symbols,
-        energy,
-        sampler,
-        log_partition,
-        entropy,
-        initial_phis,
-        phis_symbols,
-        u,
-        name,
-    ):
-        """Initialize a QHBM with all the required parameters."""
-        if not isinstance(name, str):
-            raise TypeError("name must be a string")
-        super().__init__(name)
-
-        self.p = tf.constant(p, dtype=tf.int32)
-
-        if isinstance(initial_etas, tf.Variable):
-            self.etas = tf.Variable(
-                tf.cast(initial_etas.read_value(), tf.float32), dtype=tf.float32
-            )
-        elif isinstance(initial_etas, (list, np.ndarray, tf.Tensor)):
-            self.etas = tf.Variable(tf.cast(initial_etas, tf.float32), dtype=tf.float32)
-        else:
-            raise TypeError(
-                "initial_etas needs to be a numeric type, got {}".format(
-                    type(initial_etas)
-                )
-            )
-        if self.etas.shape[0] != self.p:
-            raise ValueError("must have as many eta values as trotter steps.")
-
-        if isinstance(initial_classical_thetas, tf.Variable):
-            self.classical_thetas = tf.Variable(
-                tf.cast(initial_classical_thetas.read_value(), tf.float32),
-                dtype=tf.float32,
-            )
-        elif isinstance(initial_classical_thetas, (list, np.ndarray, tf.Tensor)):
-            self.classical_thetas = tf.Variable(
-                tf.cast(initial_classical_thetas, tf.float32), dtype=tf.float32
-            )
-        else:
-            raise TypeError(
-                "initial_classical_thetas needs to be a numeric type, got {}".format(
-                    type(initial_classical_thetas)
-                )
-            )
-
-        if not isinstance(eta_theta_symbols, (list, tuple)) or not all(
-            [isinstance(s, sympy.Symbol) for row_s in eta_theta_symbols for s in row_s]
-        ):
-            raise TypeError(
-                "eta_theta_symbols must be a 2-D list or tuple of sympy.Symbols."
-            )
-        self.raw_eta_theta_symbols = copy.deepcopy(eta_theta_symbols)
-        self.eta_theta_symbols = tf.constant(
-            [str(s) for row_s in eta_theta_symbols for s in row_s], dtype=tf.string
-        )
-        if (
-            self.classical_thetas.shape[0] * self.etas.shape[0]
-            != self.eta_theta_symbols.shape[0]
-        ):
-            raise ValueError(
-                "Due to TFQ limitations, "
-                "there must be as many eta-theta symbols as etas times thetas."
-            )
-
-        if not isinstance(energy, collections.Callable):
-            raise TypeError("energy must be a function, got {}".format(type(energy)))
-        self.energy_function = energy
-        if not isinstance(sampler, collections.Callable):
-            raise TypeError("sampler must be a function, got {}".format(type(sampler)))
-        self.sampler_function = sampler
-        if not isinstance(log_partition, collections.Callable):
-            raise TypeError(
-                "log_partition must be a function, got {}".format(type(log_partition))
-            )
-        self.log_partition_function = log_partition
-        if not isinstance(entropy, collections.Callable):
-            raise TypeError("entropy must be a function, got {}".format(type(entropy)))
-        self.entropy_function = entropy
-        if isinstance(initial_phis, tf.Variable):
-            self.phis = tf.Variable(initial_phis.read_value(), dtype=tf.float32)
-        elif isinstance(initial_phis, (list, np.ndarray, tf.Tensor)):
-            self.phis = tf.Variable(initial_phis, dtype=tf.float32)
-        else:
-            raise TypeError(
-                "initial_phis needs to be a numeric type, got {}".format(
-                    type(initial_phis)
-                )
-            )
-        if not isinstance(phis_symbols, (list, tuple)) or not all(
-            [isinstance(s, sympy.Symbol) for s in phis_symbols]
-        ):
-            raise TypeError("phis_symbols must be a list or tuple of sympy.Symbols.")
-        self.raw_phis_symbols = copy.deepcopy(phis_symbols)
-        self.phis_symbols = tf.constant([str(s) for s in phis_symbols], dtype=tf.string)
-        if self.phis.shape != self.phis_symbols.shape:
-            raise ValueError("There must be one symbol per quantum circuit parameter")
-        if not isinstance(u, cirq.Circuit):
-            raise TypeError("u must be a cirq.Circuit, got {}".format(type(u)))
-        self.raw_u = copy.deepcopy(u)
-        if set(tfq.util.get_circuit_symbols(u)) != set(
-            [str(s) for s in self.raw_phis_symbols]
-            + [str(s) for row_s in self.raw_eta_theta_symbols for s in row_s]
-        ):
-            raise ValueError(
-                "u must contain all and only the symbols "
-                "in phis_symbols and eta_theta_symbols."
-            )
-        self.u = tfq.convert_to_tensor([u])
-        self.u_dagger = tfq.convert_to_tensor([u ** -1])
-
-        self.raw_qubits = sorted(u.all_qubits())
-        raw_bit_circuit, raw_bit_symbols = util.build_bit_circuit(self.raw_qubits, name)
-        self.qubits = tf.constant([[q.row, q.col] for q in self.raw_qubits])
-        self.num_qubits = tf.constant(len(self.raw_qubits))
-        self.bit_symbols = tf.constant(
-            [str(s) for s in raw_bit_symbols], dtype=tf.string
-        )
-        self.bit_injector = tfq.convert_to_tensor([raw_bit_circuit])
-
-    def copy(self):
-        return QHBM(
-            self.p,
-            self.etas,
-            self.classical_thetas,
-            self.eta_theta_symbols,
-            self.energy_function,
-            self.sampler_function,
-            self.log_partition_function,
-            self.entropy_function,
-            self.phis,
-            self.raw_phis_symbols,
-            self.raw_u,
-            self.name,
-        )
-
-
-@tf.function
-def get_eta_theta_vals(etas, classical_thetas):
-    """Get the quantum circuit params induced by the classical model."""
-    print("retracing: get_eta_theta_vals")
-    p = tf.shape(etas)[0]
-    num_classical_thetas = tf.shape(classical_thetas)[0]
-    classical_thetas_tiled = tf.tile(tf.expand_dims(classical_thetas, 0), [p, 1])
-    etas_tiled = tf.tile(tf.expand_dims(etas, 1), [1, num_classical_thetas])
-    return tf.reshape(etas_tiled * classical_thetas_tiled, [p * num_classical_thetas])
-
-
-@tf.function
-def sample_bitstrings(this_qhbm, num_samples):
-    """Returns unique bitstrings and counts from this QHBM's classical dist.
-
-    Args:
-      this_qhbm: QHBM representation of a density matrix.
-      num_samples: number of bitstrings to sample from the classical probability
-          distribution parameterizing this QHBM.
-
-    Returns:
-      unique_samples:
-      counts:
-    """
-    print("retracing: sample_bitstrings")
-    samples = this_qhbm.sampler_function(this_qhbm.classical_thetas, num_samples)
-    unique_samples, _, counts = util.unique_with_counts(samples)
-    return unique_samples, counts
-
-
-@tf.function
-def sample_state_circuits(this_qhbm, num_samples):
-    """Returns tensor of circuits generating pure state samples from this QHBM.
-
-    Args:
-      this_qhbm: QHBM representation of a density matrix.
-      num_samples: number of pure state samples to draw from this QHBM.
-
-    Returns:
-      circuit_samples: 1-D `tf.Tensor` containing the string representations of
-          the circuits to generate pures state samples from this QHBM.
-      bitstring_samples:
-      counts: 1-D `tf.Tensor` of type `tf.int32` such that `counts[i]` says how
-          many times circuit `circuit_samples[i]` occurs in the sum used to
-          approximate this QHBM.
-    """
-    print("retracing: sample_state_circuits")
-    # Fill in quantum circuit values
-    eta_theta_vals = get_eta_theta_vals(this_qhbm.etas, this_qhbm.classical_thetas)
-    total_vals = tf.concat([eta_theta_vals, this_qhbm.phis], 0)
-    total_symbols = tf.concat([this_qhbm.eta_theta_symbols, this_qhbm.phis_symbols], 0)
-    u_model_concrete = tfq.resolve_parameters(
-        this_qhbm.u, total_symbols, tf.expand_dims(total_vals, 0)
-    )
-
-    # Inject the unique bitstrings
-    bitstring_samples, counts = sample_bitstrings(this_qhbm, num_samples)
-    tiled_bit_injector = tf.tile(this_qhbm.bit_injector, [tf.shape(counts)[0]])
-    bit_injector_samples = tfq.resolve_parameters(
-        tiled_bit_injector, this_qhbm.bit_symbols, bitstring_samples
-    )
-    circuit_samples = tfq.append_circuit(
-        bit_injector_samples, tf.tile(u_model_concrete, [tf.shape(counts)[0]])
-    )
-    return circuit_samples, bitstring_samples, counts
-
-
-@tf.function
-def sample_pulled_back_bitstrings(this_qhbm, circuit_samples, counts):
-    """Returns samples from the pulled back data distribution.
-
-    The inputs represent the data density matrix. The inverse of this QHBM's
-    unitary is appended to create the set of circuits representing the
-    pulled back data density matrix. Then, the requested number of bitstrings
-    are sampled from each circuit.
-
-    Args:
-      this_qhbm: QHBM representation of a density matrix.
-    """
-    print("retracing: sample_pulled_back_bitstrings")
-    # Fill in quantum circuit values
-    eta_theta_vals = get_eta_theta_vals(this_qhbm.etas, this_qhbm.classical_thetas)
-    total_vals = tf.concat([eta_theta_vals, this_qhbm.phis], 0)
-    total_symbols = tf.concat([this_qhbm.eta_theta_symbols, this_qhbm.phis_symbols], 0)
-    u_dagger_concrete = tfq.resolve_parameters(
-        this_qhbm.u_dagger, total_symbols, tf.expand_dims(total_vals, 0)
-    )
-    pulled_back_circuits = tfq.append_circuit(
-        circuit_samples, tf.tile(u_dagger_concrete, [tf.shape(circuit_samples)[0]])
-    )
-    raw_samples = tfq.layers.Sample()(
-        pulled_back_circuits, repetitions=tf.expand_dims(tf.math.reduce_max(counts), 0)
-    )
-    num_samples_mask = tf.cast((tf.ragged.range(counts) + 1).to_tensor(), tf.bool)
-    ragged_samples = tf.ragged.boolean_mask(raw_samples, num_samples_mask)
-    return ragged_samples
-
-
-@tf.function
-def approximate_density_matrix(this_qhbm, num_samples):
-    """Returns an estimate of the density matrix represented by this QHBM.
-
-    Args:
-      num_samples: number of pure state samples to use when computing the
-          density matrix represented by this QHBM.
-
-    Returns:
-      density_matrix: 2-D tensor containing a numeric approximation to the
-          density matrix represented by this QHBM.
-    """
-    print("retracing: approximate_density_matrix")
-    state_circuits, _, counts = sample_state_circuits(this_qhbm, num_samples)
-    return util.circuits_and_counts_to_density_matrix(state_circuits, counts)
-
-
-@tf.function
-def energy_and_energy_grad(this_qhbm, bitstring):
-    print("retracing: energy_and_energy_grad")
-    # Need fresh tensor for gradient
-    new_dup_thetas = tf.identity(this_qhbm.classical_thetas)
-    with tf.GradientTape() as tape:
-        tape.watch(new_dup_thetas)
-        this_energy = this_qhbm.energy_function(new_dup_thetas, bitstring)
-    this_grad = tape.gradient(this_energy, new_dup_thetas)
-    return this_energy, this_grad
-
-
-@tf.function
-def pulled_back_energy_expectation(this_qhbm, circuit_samples, circuit_counts):
-    """Calculates the average energy of bitstrings from the pulled back dist."""
-    print("retracing: pulled_back_energy_expectation")
-    ragged_samples_pb = sample_pulled_back_bitstrings(
-        this_qhbm, circuit_samples, circuit_counts
-    )
-    # safe when all circuits have the same number of qubits
-    all_samples_pb = ragged_samples_pb.values.to_tensor()
-    unique_samples_pb, _, counts_pb = util.unique_with_counts(all_samples_pb)
-    counts_pb = tf.cast(counts_pb, tf.float32)
-    e_list, _ = tf.map_fn(
-        lambda x: energy_and_energy_grad(this_qhbm, x),
-        unique_samples_pb,
-        fn_output_signature=(tf.float32, tf.float32),
-    )
-    e_list_full = tf.multiply(counts_pb, e_list)
-    average_energy = tf.divide(tf.reduce_sum(e_list_full), tf.reduce_sum(counts_pb))
-    return average_energy
+# TODO(#16)
+# class QHBMQ(tf.Module):
+#     def __init__(
+#         self,
+#         p,
+#         initial_etas,
+#         initial_classical_thetas,
+#         eta_theta_symbols,
+#         energy,
+#         sampler,
+#         log_partition,
+#         entropy,
+#         initial_phis,
+#         phis_symbols,
+#         u,
+#         name,
+#     ):
+#         """Initialize a QHBM with all the required parameters."""
+#         if not isinstance(name, str):
+#             raise TypeError("name must be a string")
+#         super().__init__(name)
+
+#         self.p = tf.constant(p, dtype=tf.int32)
+
+#         if isinstance(initial_etas, tf.Variable):
+#             self.etas = tf.Variable(
+#                 tf.cast(initial_etas.read_value(), tf.float32), dtype=tf.float32
+#             )
+#         elif isinstance(initial_etas, (list, np.ndarray, tf.Tensor)):
+#           self.etas = tf.Variable(tf.cast(initial_etas, tf.float32), dtype=tf.float32)
+#         else:
+#             raise TypeError(
+#                 "initial_etas needs to be a numeric type, got {}".format(
+#                     type(initial_etas)
+#                 )
+#             )
+#         if self.etas.shape[0] != self.p:
+#             raise ValueError("must have as many eta values as trotter steps.")
+
+#         if isinstance(initial_classical_thetas, tf.Variable):
+#             self.classical_thetas = tf.Variable(
+#                 tf.cast(initial_classical_thetas.read_value(), tf.float32),
+#                 dtype=tf.float32,
+#             )
+#         elif isinstance(initial_classical_thetas, (list, np.ndarray, tf.Tensor)):
+#             self.classical_thetas = tf.Variable(
+#                 tf.cast(initial_classical_thetas, tf.float32), dtype=tf.float32
+#             )
+#         else:
+#             raise TypeError(
+#                 "initial_classical_thetas needs to be a numeric type, got {}".format(
+#                     type(initial_classical_thetas)
+#                 )
+#             )
+
+#         if not isinstance(eta_theta_symbols, (list, tuple)) or not all(
+#            [isinstance(s, sympy.Symbol) for row_s in eta_theta_symbols for s in row_s]
+#         ):
+#             raise TypeError(
+#                 "eta_theta_symbols must be a 2-D list or tuple of sympy.Symbols."
+#             )
+#         self.raw_eta_theta_symbols = copy.deepcopy(eta_theta_symbols)
+#         self.eta_theta_symbols = tf.constant(
+#             [str(s) for row_s in eta_theta_symbols for s in row_s], dtype=tf.string
+#         )
+#         if (
+#             self.classical_thetas.shape[0] * self.etas.shape[0]
+#             != self.eta_theta_symbols.shape[0]
+#         ):
+#             raise ValueError(
+#                 "Due to TFQ limitations, "
+#                 "there must be as many eta-theta symbols as etas times thetas."
+#             )
+
+#         if not isinstance(energy, collections.Callable):
+#             raise TypeError("energy must be a function, got {}".format(type(energy)))
+#         self.energy_function = energy
+#         if not isinstance(sampler, collections.Callable):
+#            raise TypeError("sampler must be a function, got {}".format(type(sampler)))
+#         self.sampler_function = sampler
+#         if not isinstance(log_partition, collections.Callable):
+#             raise TypeError(
+#                 "log_partition must be a function, got {}".format(type(log_partition))
+#             )
+#         self.log_partition_function = log_partition
+#         if not isinstance(entropy, collections.Callable):
+#            raise TypeError("entropy must be a function, got {}".format(type(entropy)))
+#         self.entropy_function = entropy
+#         if isinstance(initial_phis, tf.Variable):
+#             self.phis = tf.Variable(initial_phis.read_value(), dtype=tf.float32)
+#         elif isinstance(initial_phis, (list, np.ndarray, tf.Tensor)):
+#             self.phis = tf.Variable(initial_phis, dtype=tf.float32)
+#         else:
+#             raise TypeError(
+#                 "initial_phis needs to be a numeric type, got {}".format(
+#                     type(initial_phis)
+#                 )
+#             )
+#         if not isinstance(phis_symbols, (list, tuple)) or not all(
+#             [isinstance(s, sympy.Symbol) for s in phis_symbols]
+#         ):
+#             raise TypeError("phis_symbols must be a list or tuple of sympy.Symbols.")
+#         self.raw_phis_symbols = copy.deepcopy(phis_symbols)
+#       self.phis_symbols = tf.constant([str(s) for s in phis_symbols], dtype=tf.string)
+#         if self.phis.shape != self.phis_symbols.shape:
+#             raise ValueError("There must be one symbol per quantum circuit parameter")
+#         if not isinstance(u, cirq.Circuit):
+#             raise TypeError("u must be a cirq.Circuit, got {}".format(type(u)))
+#         self.raw_u = copy.deepcopy(u)
+#         if set(tfq.util.get_circuit_symbols(u)) != set(
+#             [str(s) for s in self.raw_phis_symbols]
+#             + [str(s) for row_s in self.raw_eta_theta_symbols for s in row_s]
+#         ):
+#             raise ValueError(
+#                 "u must contain all and only the symbols "
+#                 "in phis_symbols and eta_theta_symbols."
+#             )
+#         self.u = tfq.convert_to_tensor([u])
+#         self.u_dagger = tfq.convert_to_tensor([u ** -1])
+
+#         self.raw_qubits = sorted(u.all_qubits())
+#       raw_bit_circuit, raw_bit_symbols = util.build_bit_circuit(self.raw_qubits, name)
+#         self.qubits = tf.constant([[q.row, q.col] for q in self.raw_qubits])
+#         self.num_qubits = tf.constant(len(self.raw_qubits))
+#         self.bit_symbols = tf.constant(
+#             [str(s) for s in raw_bit_symbols], dtype=tf.string
+#         )
+#         self.bit_injector = tfq.convert_to_tensor([raw_bit_circuit])
+
+#     def copy(self):
+#         return QHBM(
+#             self.p,
+#             self.etas,
+#             self.classical_thetas,
+#             self.eta_theta_symbols,
+#             self.energy_function,
+#             self.sampler_function,
+#             self.log_partition_function,
+#             self.entropy_function,
+#             self.phis,
+#             self.raw_phis_symbols,
+#             self.raw_u,
+#             self.name,
+#         )
+
+
+# @tf.function
+# def get_eta_theta_vals(etas, classical_thetas):
+#     """Get the quantum circuit params induced by the classical model."""
+#     print("retracing: get_eta_theta_vals")
+#     p = tf.shape(etas)[0]
+#     num_classical_thetas = tf.shape(classical_thetas)[0]
+#     classical_thetas_tiled = tf.tile(tf.expand_dims(classical_thetas, 0), [p, 1])
+#     etas_tiled = tf.tile(tf.expand_dims(etas, 1), [1, num_classical_thetas])
+#     return tf.reshape(etas_tiled * classical_thetas_tiled, [p * num_classical_thetas])
+
+
+# @tf.function
+# def sample_bitstrings(this_qhbm, num_samples):
+#     """Returns unique bitstrings and counts from this QHBM's classical dist.
+
+#     Args:
+#       this_qhbm: QHBM representation of a density matrix.
+#       num_samples: number of bitstrings to sample from the classical probability
+#           distribution parameterizing this QHBM.
+
+#     Returns:
+#       unique_samples:
+#       counts:
+#     """
+#     print("retracing: sample_bitstrings")
+#     samples = this_qhbm.sampler_function(this_qhbm.classical_thetas, num_samples)
+#     unique_samples, _, counts = util.unique_with_counts(samples)
+#     return unique_samples, counts
+
+
+# @tf.function
+# def sample_state_circuits(this_qhbm, num_samples):
+#     """Returns tensor of circuits generating pure state samples from this QHBM.
+
+#     Args:
+#       this_qhbm: QHBM representation of a density matrix.
+#       num_samples: number of pure state samples to draw from this QHBM.
+
+#     Returns:
+#       circuit_samples: 1-D `tf.Tensor` containing the string representations of
+#           the circuits to generate pures state samples from this QHBM.
+#       bitstring_samples:
+#       counts: 1-D `tf.Tensor` of type `tf.int32` such that `counts[i]` says how
+#           many times circuit `circuit_samples[i]` occurs in the sum used to
+#           approximate this QHBM.
+#     """
+#     print("retracing: sample_state_circuits")
+#     # Fill in quantum circuit values
+#     eta_theta_vals = get_eta_theta_vals(this_qhbm.etas, this_qhbm.classical_thetas)
+#     total_vals = tf.concat([eta_theta_vals, this_qhbm.phis], 0)
+#    total_symbols = tf.concat([this_qhbm.eta_theta_symbols, this_qhbm.phis_symbols], 0)
+#     u_model_concrete = tfq.resolve_parameters(
+#         this_qhbm.u, total_symbols, tf.expand_dims(total_vals, 0)
+#     )
+
+#     # Inject the unique bitstrings
+#     bitstring_samples, counts = sample_bitstrings(this_qhbm, num_samples)
+#     tiled_bit_injector = tf.tile(this_qhbm.bit_injector, [tf.shape(counts)[0]])
+#     bit_injector_samples = tfq.resolve_parameters(
+#         tiled_bit_injector, this_qhbm.bit_symbols, bitstring_samples
+#     )
+#     circuit_samples = tfq.append_circuit(
+#         bit_injector_samples, tf.tile(u_model_concrete, [tf.shape(counts)[0]])
+#     )
+#     return circuit_samples, bitstring_samples, counts
+
+
+# @tf.function
+# def sample_pulled_back_bitstrings(this_qhbm, circuit_samples, counts):
+#     """Returns samples from the pulled back data distribution.
+
+#     The inputs represent the data density matrix. The inverse of this QHBM's
+#     unitary is appended to create the set of circuits representing the
+#     pulled back data density matrix. Then, the requested number of bitstrings
+#     are sampled from each circuit.
+
+#     Args:
+#       this_qhbm: QHBM representation of a density matrix.
+#     """
+#     print("retracing: sample_pulled_back_bitstrings")
+#     # Fill in quantum circuit values
+#     eta_theta_vals = get_eta_theta_vals(this_qhbm.etas, this_qhbm.classical_thetas)
+#     total_vals = tf.concat([eta_theta_vals, this_qhbm.phis], 0)
+#    total_symbols = tf.concat([this_qhbm.eta_theta_symbols, this_qhbm.phis_symbols], 0)
+#     u_dagger_concrete = tfq.resolve_parameters(
+#         this_qhbm.u_dagger, total_symbols, tf.expand_dims(total_vals, 0)
+#     )
+#     pulled_back_circuits = tfq.append_circuit(
+#         circuit_samples, tf.tile(u_dagger_concrete, [tf.shape(circuit_samples)[0]])
+#     )
+#     raw_samples = tfq.layers.Sample()(
+#        pulled_back_circuits, repetitions=tf.expand_dims(tf.math.reduce_max(counts), 0)
+#     )
+#     num_samples_mask = tf.cast((tf.ragged.range(counts) + 1).to_tensor(), tf.bool)
+#     ragged_samples = tf.ragged.boolean_mask(raw_samples, num_samples_mask)
+#     return ragged_samples
+
+
+# @tf.function
+# def approximate_density_matrix(this_qhbm, num_samples):
+#     """Returns an estimate of the density matrix represented by this QHBM.
+
+#     Args:
+#       num_samples: number of pure state samples to use when computing the
+#           density matrix represented by this QHBM.
+
+#     Returns:
+#       density_matrix: 2-D tensor containing a numeric approximation to the
+#           density matrix represented by this QHBM.
+#     """
+#     print("retracing: approximate_density_matrix")
+#     state_circuits, _, counts = sample_state_circuits(this_qhbm, num_samples)
+#     return util.circuits_and_counts_to_density_matrix(state_circuits, counts)
+
+
+# @tf.function
+# def energy_and_energy_grad(this_qhbm, bitstring):
+#     print("retracing: energy_and_energy_grad")
+#     # Need fresh tensor for gradient
+#     new_dup_thetas = tf.identity(this_qhbm.classical_thetas)
+#     with tf.GradientTape() as tape:
+#         tape.watch(new_dup_thetas)
+#         this_energy = this_qhbm.energy_function(new_dup_thetas, bitstring)
+#     this_grad = tape.gradient(this_energy, new_dup_thetas)
+#     return this_energy, this_grad
+
+
+# @tf.function
+# def pulled_back_energy_expectation(this_qhbm, circuit_samples, circuit_counts):
+#     """Calculates the average energy of bitstrings from the pulled back dist."""
+#     print("retracing: pulled_back_energy_expectation")
+#     ragged_samples_pb = sample_pulled_back_bitstrings(
+#         this_qhbm, circuit_samples, circuit_counts
+#     )
+#     # safe when all circuits have the same number of qubits
+#     all_samples_pb = ragged_samples_pb.values.to_tensor()
+#     unique_samples_pb, _, counts_pb = util.unique_with_counts(all_samples_pb)
+#     counts_pb = tf.cast(counts_pb, tf.float32)
+#     e_list, _ = tf.map_fn(
+#         lambda x: energy_and_energy_grad(this_qhbm, x),
+#         unique_samples_pb,
+#         fn_output_signature=(tf.float32, tf.float32),
+#     )
+#     e_list_full = tf.multiply(counts_pb, e_list)
+#     average_energy = tf.divide(tf.reduce_sum(e_list_full), tf.reduce_sum(counts_pb))
+#     return average_energy
diff --git a/qhbm_library/qmhl.py b/qhbm_library/qmhl.py
index 09417092..83e9b220 100644
--- a/qhbm_library/qmhl.py
+++ b/qhbm_library/qmhl.py
@@ -18,7 +18,6 @@
 import tensorflow_quantum as tfq
 
 from qhbm_library import qhbm_base
-from qhbm_library import util
 
 
 # ============================================================================ #
@@ -180,140 +179,141 @@ def exact_qmhl_loss_phis_grad(
 # ============================================================================ #
 
 
-@tf.function
-def qmhl_loss_thetas_grad(qhbm_model, num_model_samples, target_density):
-    """Calculate thetas gradient of the QMHL loss of the model against the target.
-
-    Args:
-      qhbm_model: `QHBM` which is the parameterized model density operator.
-      num_model_samples: number of bitstrings sampled from the classical
-        distribution of `qhbm_model` to average over when estimating the model
-        density operator.
-      target_density: `DensityOperator` which is the distribution whose logarithm
-        we are trying to learn.
-
-    Returns:
-      Stochastic estimate of the gradient of the QMHL loss with respect to the
-        classical model parameters.
-    """
-    print("retracing: qmhl_loss_thetas_grad")
-
-    # Get energy gradients for the classical bitstrings
-    unique_samples_c, counts_c = qhbm.sample_bitstrings(
-        qhbm_model.sampler_function, qhbm_model.thetas, num_model_samples
-    )
-    expanded_counts_c = tf.cast(
-        tf.tile(tf.expand_dims(counts_c, 1), [1, tf.shape(qhbm_model.thetas)[0]]),
-        tf.dtypes.float32,
-    )
-
-    def loop(x):
-        return qhbm.energy_and_energy_grad(
-            qhbm_model.energy_function, qhbm_model.thetas, x
-        )
-
-    _, e_grad_list_c = tf.map_fn(
-        loop, unique_samples_c, fn_output_signature=(tf.float32, tf.float32)
-    )
-
-    # Get energy gradients for the pulled-back data bitstrings
-    ragged_samples_pb = qhbm.sample_pulled_back_bitstrings(
-        qhbm_model.u_dagger,
-        qhbm_model.phis_symbols,
-        qhbm_model.phis,
-        target_density.circuits,
-        target_density.counts,
-    )
-    # safe when all circuits have the same number of qubits
-    all_samples_pb = ragged_samples_pb.values.to_tensor()
-    unique_samples_pb, _, counts_pb = qhbm_base.unique_with_counts(all_samples_pb)
-    expanded_counts_pb = tf.cast(
-        tf.tile(tf.expand_dims(counts_pb, 1), [1, tf.shape(qhbm_model.thetas)[0]]),
-        tf.dtypes.float32,
-    )
-    _, e_grad_list_pb = tf.map_fn(
-        loop, unique_samples_pb, fn_output_signature=(tf.float32, tf.float32)
-    )
-
-    # Build theta gradients after reweighting
-    e_grad_c_avg = tf.divide(
-        tf.reduce_sum(expanded_counts_c * e_grad_list_c, 0),
-        tf.cast(tf.reduce_sum(counts_c), tf.float32),
-    )
-    e_grad_pb_avg = tf.divide(
-        tf.reduce_sum(expanded_counts_pb * e_grad_list_pb, 0),
-        tf.cast(tf.reduce_sum(counts_pb), tf.float32),
-    )
-    return tf.math.subtract(e_grad_pb_avg, e_grad_c_avg)
-
-
-@tf.function
-def phis_grad_sub_func(
-    i,
-    qhbm_energy_function,
-    qhbm_thetas,
-    qhbm_u_dagger,
-    qhbm_phis_symbols,
-    qhbm_phis,
-    circuit_samples,
-    circuit_counts,
-    num_phis,
-    eps,
-):
-    """phis_grad_sub_func."""
-    print("retracing: phis_grad_sub_func")
-    p_axis = tf.one_hot(i, num_phis, dtype=tf.float32)
-    perturbation = p_axis * eps
-    forward = qhbm.pulled_back_energy_expectation(
-        qhbm_energy_function,
-        qhbm_thetas,
-        qhbm_u_dagger,
-        qhbm_phis_symbols,
-        qhbm_phis + perturbation,
-        circuit_samples,
-        circuit_counts,
-    )
-    backward = qhbm.pulled_back_energy_expectation(
-        qhbm_energy_function,
-        qhbm_thetas,
-        qhbm_u_dagger,
-        qhbm_phis_symbols,
-        qhbm_phis - perturbation,
-        circuit_samples,
-        circuit_counts,
-    )
-    return tf.divide(forward - backward, (2.0 * eps))
-
-
-@tf.function
-def qmhl_loss_phis_grad(qhbm_model, target_density, eps=0.1):
-    """Calculate phis gradient of the QMHL loss of the model against the target.
-
-    Args:
-      qhbm_model: `QHBM` which is the parameterized model density operator.
-      target_density: `DensityOperator` which is the distribution whose logarithm
-        we are trying to learn.
-      eps: the size of the finite difference step.
-
-    Returns:
-      Stochastic estimate of the gradient of the QMHL loss with respect to the
-        unitary model parameters.
-    """
-    print("retracing: qmhl_loss_phis_grad")
-    num_phis = tf.shape(qhbm_model.phis)[0]
-
-    def loop(x):
-        phis_grad_sub_func(
-            x,
-            qhbm_model.energy_function,
-            qhbm_model.thetas,
-            qhbm_model.u_dagger,
-            qhbm_model.phis_symbols,
-            qhbm_model.phis,
-            target_density.circuits,
-            target_density.counts,
-            num_phis,
-            eps,
-        )
-
-    return tf.map_fn(loop, tf.range(num_phis), fn_output_signature=tf.float32)
+# TODO(#18)
+# @tf.function
+# def qmhl_loss_thetas_grad(qhbm_model, num_model_samples, target_density):
+#     """Calculate thetas gradient of the QMHL loss of the model against the target.
+
+#     Args:
+#       qhbm_model: `QHBM` which is the parameterized model density operator.
+#       num_model_samples: number of bitstrings sampled from the classical
+#         distribution of `qhbm_model` to average over when estimating the model
+#         density operator.
+#       target_density: `DensityOperator` which is the distribution whose logarithm
+#         we are trying to learn.
+
+#     Returns:
+#       Stochastic estimate of the gradient of the QMHL loss with respect to the
+#         classical model parameters.
+#     """
+#     print("retracing: qmhl_loss_thetas_grad")
+
+#     # Get energy gradients for the classical bitstrings
+#     unique_samples_c, counts_c = qhbm.sample_bitstrings(
+#         qhbm_model.sampler_function, qhbm_model.thetas, num_model_samples
+#     )
+#     expanded_counts_c = tf.cast(
+#         tf.tile(tf.expand_dims(counts_c, 1), [1, tf.shape(qhbm_model.thetas)[0]]),
+#         tf.dtypes.float32,
+#     )
+
+#     def loop(x):
+#         return qhbm.energy_and_energy_grad(
+#             qhbm_model.energy_function, qhbm_model.thetas, x
+#         )
+
+#     _, e_grad_list_c = tf.map_fn(
+#         loop, unique_samples_c, fn_output_signature=(tf.float32, tf.float32)
+#     )
+
+#     # Get energy gradients for the pulled-back data bitstrings
+#     ragged_samples_pb = qhbm.sample_pulled_back_bitstrings(
+#         qhbm_model.u_dagger,
+#         qhbm_model.phis_symbols,
+#         qhbm_model.phis,
+#         target_density.circuits,
+#         target_density.counts,
+#     )
+#     # safe when all circuits have the same number of qubits
+#     all_samples_pb = ragged_samples_pb.values.to_tensor()
+#     unique_samples_pb, _, counts_pb = qhbm_base.unique_with_counts(all_samples_pb)
+#     expanded_counts_pb = tf.cast(
+#         tf.tile(tf.expand_dims(counts_pb, 1), [1, tf.shape(qhbm_model.thetas)[0]]),
+#         tf.dtypes.float32,
+#     )
+#     _, e_grad_list_pb = tf.map_fn(
+#         loop, unique_samples_pb, fn_output_signature=(tf.float32, tf.float32)
+#     )
+
+#     # Build theta gradients after reweighting
+#     e_grad_c_avg = tf.divide(
+#         tf.reduce_sum(expanded_counts_c * e_grad_list_c, 0),
+#         tf.cast(tf.reduce_sum(counts_c), tf.float32),
+#     )
+#     e_grad_pb_avg = tf.divide(
+#         tf.reduce_sum(expanded_counts_pb * e_grad_list_pb, 0),
+#         tf.cast(tf.reduce_sum(counts_pb), tf.float32),
+#     )
+#     return tf.math.subtract(e_grad_pb_avg, e_grad_c_avg)
+
+
+# @tf.function
+# def phis_grad_sub_func(
+#     i,
+#     qhbm_energy_function,
+#     qhbm_thetas,
+#     qhbm_u_dagger,
+#     qhbm_phis_symbols,
+#     qhbm_phis,
+#     circuit_samples,
+#     circuit_counts,
+#     num_phis,
+#     eps,
+# ):
+#     """phis_grad_sub_func."""
+#     print("retracing: phis_grad_sub_func")
+#     p_axis = tf.one_hot(i, num_phis, dtype=tf.float32)
+#     perturbation = p_axis * eps
+#     forward = qhbm.pulled_back_energy_expectation(
+#         qhbm_energy_function,
+#         qhbm_thetas,
+#         qhbm_u_dagger,
+#         qhbm_phis_symbols,
+#         qhbm_phis + perturbation,
+#         circuit_samples,
+#         circuit_counts,
+#     )
+#     backward = qhbm.pulled_back_energy_expectation(
+#         qhbm_energy_function,
+#         qhbm_thetas,
+#         qhbm_u_dagger,
+#         qhbm_phis_symbols,
+#         qhbm_phis - perturbation,
+#         circuit_samples,
+#         circuit_counts,
+#     )
+#     return tf.divide(forward - backward, (2.0 * eps))
+
+
+# @tf.function
+# def qmhl_loss_phis_grad(qhbm_model, target_density, eps=0.1):
+#     """Calculate phis gradient of the QMHL loss of the model against the target.
+
+#     Args:
+#       qhbm_model: `QHBM` which is the parameterized model density operator.
+#       target_density: `DensityOperator` which is the distribution whose logarithm
+#         we are trying to learn.
+#       eps: the size of the finite difference step.
+
+#     Returns:
+#       Stochastic estimate of the gradient of the QMHL loss with respect to the
+#         unitary model parameters.
+#     """
+#     print("retracing: qmhl_loss_phis_grad")
+#     num_phis = tf.shape(qhbm_model.phis)[0]
+
+#     def loop(x):
+#         phis_grad_sub_func(
+#             x,
+#             qhbm_model.energy_function,
+#             qhbm_model.thetas,
+#             qhbm_model.u_dagger,
+#             qhbm_model.phis_symbols,
+#             qhbm_model.phis,
+#             target_density.circuits,
+#             target_density.counts,
+#             num_phis,
+#             eps,
+#         )
+
+#     return tf.map_fn(loop, tf.range(num_phis), fn_output_signature=tf.float32)
diff --git a/qhbm_library/util.py b/qhbm_library/util.py
index c054bd8d..e1bc0ec4 100644
--- a/qhbm_library/util.py
+++ b/qhbm_library/util.py
@@ -14,9 +14,7 @@
 # ==============================================================================
 """Utility functions."""
 
-import cirq
 import numpy as np
-import sympy
 
 import tensorflow as tf
 import tensorflow_quantum as tfq
diff --git a/qhbm_library/vqt.py b/qhbm_library/vqt.py
index fb93d6ce..ccde9e0f 100644
--- a/qhbm_library/vqt.py
+++ b/qhbm_library/vqt.py
@@ -18,7 +18,6 @@
 import tensorflow_quantum as tfq
 
 from qhbm_library import qhbm_base
-from qhbm_library import util
 
 
 # ============================================================================ #
@@ -284,212 +283,212 @@ def exact_vqt_loss_phis_grad(
 # Version of VQT that takes a list of QHBMs as the target Hamiltonian.
 # ============================================================================ #
 
-
-@tf.function
-def get_avg_sub_energy(
-    full_y_samples_j, qhbm_energy_function, qhbm_thetas_j, bit_sub_indices_j
-):
-    print("retracing: get_avg_sub_energy")
-    sub_samples = tf.gather(full_y_samples_j, bit_sub_indices_j, axis=1)
-    unique_sub_samples, _, counts = qhbm_base.unique_with_counts(sub_samples)
-    counts = tf.cast(counts, tf.float32)
-    unique_sub_energies, _ = tf.map_fn(
-        lambda x: qhbm.energy_and_energy_grad(qhbm_energy_function, qhbm_thetas_j, x),
-        unique_sub_samples,
-        fn_output_signature=(tf.float32, tf.float32),
-    )
-    sub_energies = tf.multiply(counts, unique_sub_energies)
-    return tf.divide(tf.reduce_sum(sub_energies), tf.reduce_sum(counts))
-
-
-def build_sub_term_energy_func(qhbm_vqt, qhbm_hamiltonian_list):
-    bit_sub_indices_list = [
-        util.get_bit_sub_indices(qhbm_vqt.qubits, this_qhbm.qubits)
-        for this_qhbm in qhbm_hamiltonian_list
-    ]
-    qhbm_thetas = [this_qhbm.thetas for this_qhbm in qhbm_hamiltonian_list]
-    qhbm_u_dagger = [this_qhbm.u_dagger for this_qhbm in qhbm_hamiltonian_list]
-    qhbm_phis_symbols = [this_qhbm.phis_symbols for this_qhbm in qhbm_hamiltonian_list]
-    qhbm_phis = [this_qhbm.phis for this_qhbm in qhbm_hamiltonian_list]
-    qhbm_energy_list = [
-        this_qhbm.energy_function for this_qhbm in qhbm_hamiltonian_list
-    ]
-
-    def inner_build_sub_term_energy_func(
-        energy_list, thetas, sub_indices, daggers, phis_s, phis
-    ):
-        list_of_get_avg_energy_lists = []
-
-        def inner_jth_sampled_circuits_energy_list(
-            j, i_energy_list, i_thetas, i_sub_indices, i_daggers, i_phis_s, i_phis
-        ):
-            @tf.function
-            def jth_sampled_circuits_energy_list(circuits, counts):
-                print("retracing: jth_sampled_circuits_energy_list_{}".format(j))
-                return tf.map_fn(
-                    lambda x: get_avg_sub_energy(
-                        x.to_tensor(), energy_list[j], thetas[j], sub_indices[j]
-                    ),
-                    qhbm.sample_pulled_back_bitstrings(
-                        daggers[j], phis_s[j], phis[j], circuits, counts
-                    ),
-                    fn_output_signature=tf.float32,
-                )
-
-            return jth_sampled_circuits_energy_list
-
-        for j, _ in enumerate(energy_list):
-            list_of_get_avg_energy_lists.append(
-                inner_jth_sampled_circuits_energy_list(
-                    j, energy_list, thetas, sub_indices, daggers, phis_s, phis
-                )
-            )
-
-        @tf.function
-        def sub_term_energy_func(
-            vqt_circuits, vqt_circuits_counts, le=list_of_get_avg_energy_lists
-        ):
-            print("retracing: sub_term_energy_func")
-            avg_energy_lists = tf.stack(
-                [f(vqt_circuits, vqt_circuits_counts) for f in le]
-            )
-            return tf.reduce_sum(avg_energy_lists, 0)
-
-        return sub_term_energy_func
-
-    return inner_build_sub_term_energy_func(
-        qhbm_energy_list,
-        qhbm_thetas,
-        bit_sub_indices_list,
-        qhbm_u_dagger,
-        qhbm_phis_symbols,
-        qhbm_phis,
-    )
-
-
-@tf.function
-def vqt_qhbm_loss(qhbm_vqt, num_vqt_samples, sub_term_energy_func):
-    print("retracing: vqt_qhbm_loss")
-    vqt_circuits, _, vqt_circuits_counts = qhbm_vqt.sample_state_circuits(
-        num_vqt_samples,
-    )
-    sub_energy_list = sub_term_energy_func(vqt_circuits, vqt_circuits_counts)
-    e_avg = tf.divide(
-        tf.reduce_sum(tf.cast(vqt_circuits_counts, tf.float32) * sub_energy_list),
-        num_vqt_samples,
-    )
-    return e_avg - qhbm_vqt.entropy_function()
-
-
-@tf.function
-def vqt_qhbm_loss_thetas_grad(qhbm_vqt, num_vqt_samples, sub_term_energy_func):
-    print("retracing: vqt_qhbm_loss_thetas_grad")
-    # Build components of the gradient
-    (
-        vqt_circuits,
-        vqt_bitstrings,
-        vqt_circuits_counts,
-    ) = qhbm_vqt.sample_state_circuits(
-        num_vqt_samples,
-    )
-    vqt_expanded_circuits_counts = tf.cast(
-        tf.expand_dims(vqt_circuits_counts, 1), tf.dtypes.float32
-    )
-    vqt_energies, vqt_energy_grads = tf.map_fn(
-        lambda x: qhbm_vqt.energy_and_energy_grad(x),
-        vqt_bitstrings,
-        fn_output_signature=(tf.float32, tf.float32),
-    )
-
-    # Compute the per vqt bitstring diff list
-    sub_energy_list = sub_term_energy_func(vqt_circuits, vqt_circuits_counts)
-    diff_list = sub_energy_list - vqt_energies
-    expanded_diff_list = tf.expand_dims(diff_list, 1)
-
-    # Compute the positive term in the gradient
-    diff_list_avg = tf.divide(
-        tf.reduce_sum(tf.cast(vqt_circuits_counts, tf.float32) * diff_list),
-        num_vqt_samples,
-    )
-    vqt_energy_grads_avg = tf.divide(
-        tf.reduce_sum(vqt_expanded_circuits_counts * vqt_energy_grads, 0),
-        num_vqt_samples,
-    )
-    positive = vqt_energy_grads_avg * diff_list_avg
-
-    # Compute the negative term in the gradient
-    prod_list = vqt_energy_grads * expanded_diff_list
-    negative = tf.divide(
-        tf.reduce_sum(vqt_expanded_circuits_counts * prod_list, 0), num_vqt_samples
-    )
-
-    return positive - negative
-
-
-@tf.function
-def phis_grad_sub_func(
-    i,
-    qhbm,
-    num_vqt_samples,
-    D,
-    eps,
-    sub_term_energy_func,
-):
-    p_axis = tf.one_hot(i, D, dtype=tf.float32)
-    perturbation = p_axis * eps
-
-    # Forward
-    original_phis = qhbm.phis.read_value()
-    qhbm.phis.assign_add(perturbation)
-    (vqt_circuits_forward, _, vqt_circuits_counts_forward) = qhbm.sample_state_circuits(
-        num_vqt_samples,
-    )
-    sub_energy_list = sub_term_energy_func(
-        vqt_circuits_forward, vqt_circuits_counts_forward
-    )
-    forward = tf.divide(
-        tf.reduce_sum(
-            tf.cast(vqt_circuits_counts_forward, tf.float32) * sub_energy_list
-        ),
-        num_vqt_samples,
-    )
-
-    # Backward
-    qhbm.phis.assign_add(-2.0 * perturbation)
-    (
-        vqt_circuits_backward,
-        _,
-        vqt_circuits_counts_backward,
-    ) = qhbm.sample_state_circuits(
-        num_vqt_samples,
-    )
-    sub_energy_list = sub_term_energy_func(
-        vqt_circuits_backward, vqt_circuits_counts_backward
-    )
-    backward = tf.divide(
-        tf.reduce_sum(
-            tf.cast(vqt_circuits_counts_backward, tf.float32) * sub_energy_list
-        ),
-        num_vqt_samples,
-    )
-    qhbm.phis.assign(original_phis)
-
-    return tf.divide(forward - backward, (2.0 * eps))
-
-
-@tf.function
-def vqt_qhbm_loss_phis_grad(qhbm_vqt, num_vqt_samples, sub_term_energy_func, eps=0.1):
-    print("retracing: vqt_qhbm_loss_phis_grad")
-    D = tf.shape(qhbm_vqt.phis)[0]
-    return tf.map_fn(
-        lambda x: phis_grad_sub_func(
-            x,
-            qhbm_vqt,
-            num_vqt_samples,
-            D,
-            eps,
-            sub_term_energy_func,
-        ),
-        tf.range(D),
-        fn_output_signature=tf.float32,
-    )
+# TODO(#14)
+# @tf.function
+# def get_avg_sub_energy(
+#     full_y_samples_j, qhbm_energy_function, qhbm_thetas_j, bit_sub_indices_j
+# ):
+#     print("retracing: get_avg_sub_energy")
+#     sub_samples = tf.gather(full_y_samples_j, bit_sub_indices_j, axis=1)
+#     unique_sub_samples, _, counts = qhbm_base.unique_with_counts(sub_samples)
+#     counts = tf.cast(counts, tf.float32)
+#     unique_sub_energies, _ = tf.map_fn(
+#         lambda x: qhbm.energy_and_energy_grad(qhbm_energy_function, qhbm_thetas_j, x),
+#         unique_sub_samples,
+#         fn_output_signature=(tf.float32, tf.float32),
+#     )
+#     sub_energies = tf.multiply(counts, unique_sub_energies)
+#     return tf.divide(tf.reduce_sum(sub_energies), tf.reduce_sum(counts))
+
+
+# def build_sub_term_energy_func(qhbm_vqt, qhbm_hamiltonian_list):
+#     bit_sub_indices_list = [
+#         util.get_bit_sub_indices(qhbm_vqt.qubits, this_qhbm.qubits)
+#         for this_qhbm in qhbm_hamiltonian_list
+#     ]
+#     qhbm_thetas = [this_qhbm.thetas for this_qhbm in qhbm_hamiltonian_list]
+#     qhbm_u_dagger = [this_qhbm.u_dagger for this_qhbm in qhbm_hamiltonian_list]
+#     qhbm_phis_symbols=[this_qhbm.phis_symbols for this_qhbm in qhbm_hamiltonian_list]
+#     qhbm_phis = [this_qhbm.phis for this_qhbm in qhbm_hamiltonian_list]
+#     qhbm_energy_list = [
+#         this_qhbm.energy_function for this_qhbm in qhbm_hamiltonian_list
+#     ]
+
+#     def inner_build_sub_term_energy_func(
+#         energy_list, thetas, sub_indices, daggers, phis_s, phis
+#     ):
+#         list_of_get_avg_energy_lists = []
+
+#         def inner_jth_sampled_circuits_energy_list(
+#             j, i_energy_list, i_thetas, i_sub_indices, i_daggers, i_phis_s, i_phis
+#         ):
+#             @tf.function
+#             def jth_sampled_circuits_energy_list(circuits, counts):
+#                 print("retracing: jth_sampled_circuits_energy_list_{}".format(j))
+#                 return tf.map_fn(
+#                     lambda x: get_avg_sub_energy(
+#                         x.to_tensor(), energy_list[j], thetas[j], sub_indices[j]
+#                     ),
+#                     qhbm.sample_pulled_back_bitstrings(
+#                         daggers[j], phis_s[j], phis[j], circuits, counts
+#                     ),
+#                     fn_output_signature=tf.float32,
+#                 )
+
+#             return jth_sampled_circuits_energy_list
+
+#         for j, _ in enumerate(energy_list):
+#             list_of_get_avg_energy_lists.append(
+#                 inner_jth_sampled_circuits_energy_list(
+#                     j, energy_list, thetas, sub_indices, daggers, phis_s, phis
+#                 )
+#             )
+
+#         @tf.function
+#         def sub_term_energy_func(
+#             vqt_circuits, vqt_circuits_counts, le=list_of_get_avg_energy_lists
+#         ):
+#             print("retracing: sub_term_energy_func")
+#             avg_energy_lists = tf.stack(
+#                 [f(vqt_circuits, vqt_circuits_counts) for f in le]
+#             )
+#             return tf.reduce_sum(avg_energy_lists, 0)
+
+#         return sub_term_energy_func
+
+#     return inner_build_sub_term_energy_func(
+#         qhbm_energy_list,
+#         qhbm_thetas,
+#         bit_sub_indices_list,
+#         qhbm_u_dagger,
+#         qhbm_phis_symbols,
+#         qhbm_phis,
+#     )
+
+
+# @tf.function
+# def vqt_qhbm_loss(qhbm_vqt, num_vqt_samples, sub_term_energy_func):
+#     print("retracing: vqt_qhbm_loss")
+#     vqt_circuits, _, vqt_circuits_counts = qhbm_vqt.sample_state_circuits(
+#         num_vqt_samples,
+#     )
+#     sub_energy_list = sub_term_energy_func(vqt_circuits, vqt_circuits_counts)
+#     e_avg = tf.divide(
+#         tf.reduce_sum(tf.cast(vqt_circuits_counts, tf.float32) * sub_energy_list),
+#         num_vqt_samples,
+#     )
+#     return e_avg - qhbm_vqt.entropy_function()
+
+
+# @tf.function
+# def vqt_qhbm_loss_thetas_grad(qhbm_vqt, num_vqt_samples, sub_term_energy_func):
+#     print("retracing: vqt_qhbm_loss_thetas_grad")
+#     # Build components of the gradient
+#     (
+#         vqt_circuits,
+#         vqt_bitstrings,
+#         vqt_circuits_counts,
+#     ) = qhbm_vqt.sample_state_circuits(
+#         num_vqt_samples,
+#     )
+#     vqt_expanded_circuits_counts = tf.cast(
+#         tf.expand_dims(vqt_circuits_counts, 1), tf.dtypes.float32
+#     )
+#     vqt_energies, vqt_energy_grads = tf.map_fn(
+#         lambda x: qhbm_vqt.energy_and_energy_grad(x),
+#         vqt_bitstrings,
+#         fn_output_signature=(tf.float32, tf.float32),
+#     )
+
+#     # Compute the per vqt bitstring diff list
+#     sub_energy_list = sub_term_energy_func(vqt_circuits, vqt_circuits_counts)
+#     diff_list = sub_energy_list - vqt_energies
+#     expanded_diff_list = tf.expand_dims(diff_list, 1)
+
+#     # Compute the positive term in the gradient
+#     diff_list_avg = tf.divide(
+#         tf.reduce_sum(tf.cast(vqt_circuits_counts, tf.float32) * diff_list),
+#         num_vqt_samples,
+#     )
+#     vqt_energy_grads_avg = tf.divide(
+#         tf.reduce_sum(vqt_expanded_circuits_counts * vqt_energy_grads, 0),
+#         num_vqt_samples,
+#     )
+#     positive = vqt_energy_grads_avg * diff_list_avg
+
+#     # Compute the negative term in the gradient
+#     prod_list = vqt_energy_grads * expanded_diff_list
+#     negative = tf.divide(
+#         tf.reduce_sum(vqt_expanded_circuits_counts * prod_list, 0), num_vqt_samples
+#     )
+
+#     return positive - negative
+
+
+# @tf.function
+# def phis_grad_sub_func(
+#     i,
+#     qhbm,
+#     num_vqt_samples,
+#     D,
+#     eps,
+#     sub_term_energy_func,
+# ):
+#     p_axis = tf.one_hot(i, D, dtype=tf.float32)
+#     perturbation = p_axis * eps
+
+#     # Forward
+#     original_phis = qhbm.phis.read_value()
+#     qhbm.phis.assign_add(perturbation)
+#     (vqt_circuits_forward,_,vqt_circuits_counts_forward) = qhbm.sample_state_circuits(
+#         num_vqt_samples,
+#     )
+#     sub_energy_list = sub_term_energy_func(
+#         vqt_circuits_forward, vqt_circuits_counts_forward
+#     )
+#     forward = tf.divide(
+#         tf.reduce_sum(
+#             tf.cast(vqt_circuits_counts_forward, tf.float32) * sub_energy_list
+#         ),
+#         num_vqt_samples,
+#     )
+
+#     # Backward
+#     qhbm.phis.assign_add(-2.0 * perturbation)
+#     (
+#         vqt_circuits_backward,
+#         _,
+#         vqt_circuits_counts_backward,
+#     ) = qhbm.sample_state_circuits(
+#         num_vqt_samples,
+#     )
+#     sub_energy_list = sub_term_energy_func(
+#         vqt_circuits_backward, vqt_circuits_counts_backward
+#     )
+#     backward = tf.divide(
+#         tf.reduce_sum(
+#             tf.cast(vqt_circuits_counts_backward, tf.float32) * sub_energy_list
+#         ),
+#         num_vqt_samples,
+#     )
+#     qhbm.phis.assign(original_phis)
+
+#     return tf.divide(forward - backward, (2.0 * eps))
+
+
+# @tf.function
+# def vqt_qhbm_loss_phis_grad(qhbm_vqt, num_vqt_samples, sub_term_energy_func, eps=0.1):
+#     print("retracing: vqt_qhbm_loss_phis_grad")
+#     D = tf.shape(qhbm_vqt.phis)[0]
+#     return tf.map_fn(
+#         lambda x: phis_grad_sub_func(
+#             x,
+#             qhbm_vqt,
+#             num_vqt_samples,
+#             D,
+#             eps,
+#             sub_term_energy_func,
+#         ),
+#         tf.range(D),
+#         fn_output_signature=tf.float32,
+#     )
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index fc63372e..00000000
--- a/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-black==21.5b1
-tensorflow-quantum==2.4.1
diff --git a/scripts/prepare_pr.sh b/scripts/prepare_pr.sh
new file mode 100755
index 00000000..a14668c4
--- /dev/null
+++ b/scripts/prepare_pr.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Copyright 2021 The QHBM Library Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+poetry run black qhbm_library/ tests/
+poetry run flake8


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/qhbm_library/architectures_test.py b/tests/architectures_test.py
similarity index 99%
rename from qhbm_library/architectures_test.py
rename to tests/architectures_test.py
index 0adcd555..07b181b7 100644
--- a/qhbm_library/architectures_test.py
+++ b/tests/architectures_test.py
@@ -282,7 +282,7 @@ def test_get_2d_hea(self):
         name = "test_hea"
         circuit_expect = cirq.Circuit()
         symbols_expect = []
-        for layer in range(2):
+        for layer in range(num_layers):
             xz_circuit, xz_symbols = architectures.get_2d_xz_rotation_layer(
                 2, 3, layer, name
             )
diff --git a/qhbm_library/ebm_test.py b/tests/ebm_test.py
similarity index 99%
rename from qhbm_library/ebm_test.py
rename to tests/ebm_test.py
index 3a8976b8..9ede6b7b 100644
--- a/qhbm_library/ebm_test.py
+++ b/tests/ebm_test.py
@@ -139,7 +139,7 @@ def test_sampler_bernoulli(self):
         num_bitstrings = tf.constant(int(1e7), dtype=tf.int32)
         bitstrings = sampler_bernoulli(test_logits, num_bitstrings)
         _, _, counts = qhbm_base.unique_with_counts(bitstrings)
-        # check that we got all bitstrings.
+
         @tf.function
         def check_bitstring_exists(bitstring, bitstring_list):
             print("retracing: check_bitstring_exists")
@@ -281,7 +281,7 @@ def test_sampler_boltzmann(self):
         num_bitstrings = tf.constant(int(1e7), dtype=tf.int32)
         bitstrings = sampler_boltzmann(test_thetas, num_bitstrings)
         _, _, counts = qhbm_base.unique_with_counts(bitstrings)
-        # check that we got all bitstrings.
+
         @tf.function
         def check_bitstring_exists(bitstring, bitstring_list):
             print("retracing: check_bitstring_exists")
diff --git a/qhbm_library/hamiltonian_test.py b/tests/hamiltonian_test.py
similarity index 99%
rename from qhbm_library/hamiltonian_test.py
rename to tests/hamiltonian_test.py
index 49ce08f8..bdda720a 100644
--- a/qhbm_library/hamiltonian_test.py
+++ b/tests/hamiltonian_test.py
@@ -150,4 +150,4 @@ def test_tfim_zz_shard(self):
 
 if __name__ == "__main__":
     print("Running hamiltonian_test.py ...")
-    googletest.main()
+    tf.test.main()
diff --git a/qhbm_library/qhbm_base_test.py b/tests/qhbm_base_test.py
similarity index 99%
rename from qhbm_library/qhbm_base_test.py
rename to tests/qhbm_base_test.py
index 12d15a2d..4acc456c 100644
--- a/qhbm_library/qhbm_base_test.py
+++ b/tests/qhbm_base_test.py
@@ -21,7 +21,7 @@
 import tensorflow_quantum as tfq
 
 from qhbm_library import qhbm_base
-from qhbm_library import test_util
+from tests import test_util
 
 
 # Global tolerance, set for float32.
diff --git a/qhbm_library/qmhl_test.py b/tests/qmhl_test.py
similarity index 91%
rename from qhbm_library/qmhl_test.py
rename to tests/qmhl_test.py
index cd125b9c..4957c9e5 100644
--- a/qhbm_library/qmhl_test.py
+++ b/tests/qmhl_test.py
@@ -15,14 +15,10 @@
 """Tests for the QMHL loss and gradients."""
 
 import cirq
-import sympy
 import tensorflow as tf
-import tensorflow_quantum as tfq
 
-from qhbm_library import ebm
-from qhbm_library import qhbm_base
 from qhbm_library import qmhl
-from qhbm_library import test_util
+from tests import test_util
 
 
 class QMHLExactLossTest(tf.test.TestCase):
@@ -37,7 +33,6 @@ def test_zero_grad(self):
             )
             model_qhbm = target_qhbm.copy()
             shape_thetas = target_qhbm.thetas.shape
-            shape_phis = target_qhbm.phis.shape
 
             # Get the QMHL loss gradients
             model_samples = 1e6
diff --git a/qhbm_library/test_util.py b/tests/test_util.py
similarity index 100%
rename from qhbm_library/test_util.py
rename to tests/test_util.py
diff --git a/qhbm_library/util_test.py b/tests/util_test.py
similarity index 99%
rename from qhbm_library/util_test.py
rename to tests/util_test.py
index 07aee942..f1d0af75 100644
--- a/qhbm_library/util_test.py
+++ b/tests/util_test.py
@@ -16,12 +16,11 @@
 import math
 
 import cirq
-import sympy
 import tensorflow as tf
 import tensorflow_quantum as tfq
 
-from qhbm_library import test_util
 from qhbm_library import util
+from tests import test_util
 
 
 # ============================================================================ #
diff --git a/qhbm_library/vqt_test.py b/tests/vqt_test.py
similarity index 97%
rename from qhbm_library/vqt_test.py
rename to tests/vqt_test.py
index 8d823104..959c2072 100644
--- a/qhbm_library/vqt_test.py
+++ b/tests/vqt_test.py
@@ -19,11 +19,9 @@
 import tensorflow as tf
 import tensorflow_quantum as tfq
 
-from qhbm_library import ebm
 from qhbm_library import qhbm_base
-from qhbm_library import test_util
-from qhbm_library import util
 from qhbm_library import vqt
+from tests import test_util
 
 
 class VQTTest(tf.test.TestCase):
@@ -94,7 +92,7 @@ def test_loss_consistency(self):
 #             )
 #             print("Current num qubits: {}".format(num_qubits))
 #             self.assertAllClose(
-#                 loss, -target_qhbm.log_partition_function(target_qhbm.thetas), atol=1e-2
+#               loss, -target_qhbm.log_partition_function(target_qhbm.thetas), atol=1e-2
 #             )
 #             self.assertAllClose(thetas_grad, tf.zeros(shape_thetas), atol=1e-2)
 #             self.assertAllClose(phis_grad, tf.zeros(shape_phis), atol=1e-1)
@@ -150,7 +148,7 @@ def test_loss_consistency(self):
 #                 ]
 #             )
 
-#         final_loss = vqt.vqt_qhbm_loss(model_qhbm, model_samples, sub_term_energy_func)
+#         final_loss = vqt.vqt_qhbm_loss(model_qhbm,model_samples,sub_term_energy_func)
 #         final_dm = model_qhbm.density_matrix()
 #         final_fidelity = util.fidelity(final_dm, target_dm)
 #         # TODO(zaqqwerty): tighten these once better sample gradients are ready