diff --git a/.github/test_events/README.md b/.github/test_events/README.md
new file mode 100644
index 00000000..d6b47603
--- /dev/null
+++ b/.github/test_events/README.md
@@ -0,0 +1,11 @@
+# GitHub Test Events
+
+This folder contains mock GitHub webhook events. They can be used as input to [nektos/act](https://github.com/nektos/act) to simulate what will happen for that event. This is useful for testing CI changes locally.
+
+For example, to simulate what will happen in GitHub actions run when a Python pre-release is published, you can run:
+
+```sh
+act release -n -e .github/test_events/prerelease_python.json
+```
+
+These payloads are adapted from GitHub's examples in [Events that trigger workflows](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows).
diff --git a/.github/test_events/python_prerelease.json b/.github/test_events/python_prerelease.json
new file mode 100644
index 00000000..54cf8e81
--- /dev/null
+++ b/.github/test_events/python_prerelease.json
@@ -0,0 +1,78 @@
+{
+ "action": "published",
+ "release": {
+ "url": "https://api.github.com/repos/octocat/Hello-World/releases/1",
+ "html_url": "https://github.com/octocat/Hello-World/releases/v1.0.0",
+ "assets_url": "https://api.github.com/repos/octocat/Hello-World/releases/1/assets",
+ "upload_url": "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}",
+ "tarball_url": "https://api.github.com/repos/octocat/Hello-World/tarball/v1.0.0",
+ "zipball_url": "https://api.github.com/repos/octocat/Hello-World/zipball/v1.0.0",
+ "discussion_url": "https://github.com/octocat/Hello-World/discussions/90",
+ "id": 1,
+ "node_id": "MDc6UmVsZWFzZTE=",
+ "tag_name": "quil-py/v1.0.0",
+ "target_commitish": "master",
+ "name": "v1.0.0",
+ "body": "Description of the release",
+ "draft": false,
+ "prerelease": true,
+ "created_at": "2013-02-27T19:35:32Z",
+ "published_at": "2013-02-27T19:35:32Z",
+ "author": {
+ "login": "octocat",
+ "id": 1,
+ "node_id": "MDQ6VXNlcjE=",
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/octocat",
+ "html_url": "https://github.com/octocat",
+ "followers_url": "https://api.github.com/users/octocat/followers",
+ "following_url": "https://api.github.com/users/octocat/following{/other_user}",
+ "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
+ "organizations_url": "https://api.github.com/users/octocat/orgs",
+ "repos_url": "https://api.github.com/users/octocat/repos",
+ "events_url": "https://api.github.com/users/octocat/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/octocat/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "assets": [
+ {
+ "url": "https://api.github.com/repos/octocat/Hello-World/releases/assets/1",
+ "browser_download_url": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/example.zip",
+ "id": 1,
+ "node_id": "MDEyOlJlbGVhc2VBc3NldDE=",
+ "name": "example.zip",
+ "label": "short description",
+ "state": "uploaded",
+ "content_type": "application/zip",
+ "size": 1024,
+ "download_count": 42,
+ "created_at": "2013-02-27T19:35:32Z",
+ "updated_at": "2013-02-27T19:35:32Z",
+ "uploader": {
+ "login": "octocat",
+ "id": 1,
+ "node_id": "MDQ6VXNlcjE=",
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/octocat",
+ "html_url": "https://github.com/octocat",
+ "followers_url": "https://api.github.com/users/octocat/followers",
+ "following_url": "https://api.github.com/users/octocat/following{/other_user}",
+ "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
+ "organizations_url": "https://api.github.com/users/octocat/orgs",
+ "repos_url": "https://api.github.com/users/octocat/repos",
+ "events_url": "https://api.github.com/users/octocat/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/octocat/received_events",
+ "type": "User",
+ "site_admin": false
+ }
+ }
+ ]
+ }
+}
diff --git a/.github/test_events/python_release.json b/.github/test_events/python_release.json
new file mode 100644
index 00000000..365abd3c
--- /dev/null
+++ b/.github/test_events/python_release.json
@@ -0,0 +1,78 @@
+{
+ "action": "published",
+ "release": {
+ "url": "https://api.github.com/repos/octocat/Hello-World/releases/1",
+ "html_url": "https://github.com/octocat/Hello-World/releases/v1.0.0",
+ "assets_url": "https://api.github.com/repos/octocat/Hello-World/releases/1/assets",
+ "upload_url": "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}",
+ "tarball_url": "https://api.github.com/repos/octocat/Hello-World/tarball/v1.0.0",
+ "zipball_url": "https://api.github.com/repos/octocat/Hello-World/zipball/v1.0.0",
+ "discussion_url": "https://github.com/octocat/Hello-World/discussions/90",
+ "id": 1,
+ "node_id": "MDc6UmVsZWFzZTE=",
+ "tag_name": "quil-py/v1.0.0",
+ "target_commitish": "master",
+ "name": "v1.0.0",
+ "body": "Description of the release",
+ "draft": false,
+ "prerelease": false,
+ "created_at": "2013-02-27T19:35:32Z",
+ "published_at": "2013-02-27T19:35:32Z",
+ "author": {
+ "login": "octocat",
+ "id": 1,
+ "node_id": "MDQ6VXNlcjE=",
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/octocat",
+ "html_url": "https://github.com/octocat",
+ "followers_url": "https://api.github.com/users/octocat/followers",
+ "following_url": "https://api.github.com/users/octocat/following{/other_user}",
+ "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
+ "organizations_url": "https://api.github.com/users/octocat/orgs",
+ "repos_url": "https://api.github.com/users/octocat/repos",
+ "events_url": "https://api.github.com/users/octocat/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/octocat/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "assets": [
+ {
+ "url": "https://api.github.com/repos/octocat/Hello-World/releases/assets/1",
+ "browser_download_url": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/example.zip",
+ "id": 1,
+ "node_id": "MDEyOlJlbGVhc2VBc3NldDE=",
+ "name": "example.zip",
+ "label": "short description",
+ "state": "uploaded",
+ "content_type": "application/zip",
+ "size": 1024,
+ "download_count": 42,
+ "created_at": "2013-02-27T19:35:32Z",
+ "updated_at": "2013-02-27T19:35:32Z",
+ "uploader": {
+ "login": "octocat",
+ "id": 1,
+ "node_id": "MDQ6VXNlcjE=",
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/octocat",
+ "html_url": "https://github.com/octocat",
+ "followers_url": "https://api.github.com/users/octocat/followers",
+ "following_url": "https://api.github.com/users/octocat/following{/other_user}",
+ "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
+ "organizations_url": "https://api.github.com/users/octocat/orgs",
+ "repos_url": "https://api.github.com/users/octocat/repos",
+ "events_url": "https://api.github.com/users/octocat/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/octocat/received_events",
+ "type": "User",
+ "site_admin": false
+ }
+ }
+ ]
+ }
+}
diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml
index 9bde6d6b..f3b76737 100644
--- a/.github/workflows/bench.yml
+++ b/.github/workflows/bench.yml
@@ -16,6 +16,13 @@ jobs:
- stable
steps:
+ # Some of the snapshots have long file paths, so we need to enable long file paths on Windows where the limit is 260 by default
+ - name: Allow Long File Paths
+ if: matrix.os == 'windows-latest'
+ run: |
+ reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f
+ # https://github.com/actions/checkout/issues/1285#issuecomment-2042579471
+ git config --system core.longpaths true
- name: Checkout sources
uses: actions/checkout@v2
with:
@@ -41,7 +48,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: bench
- args: --bench parser -- --warm-up-time=2 --measurement-time=3 --sample-size=500 --color=always
+ args: --bench parser --bench simplification -- --warm-up-time=2 --measurement-time=3 --sample-size=500 --color=always
- name: Archive benchmark results
if: ${{ github.ref == 'refs/heads/main'}}
@@ -49,4 +56,4 @@ jobs:
with:
name: benchmarks-${{ matrix.os }}
path: target/criterion
-
\ No newline at end of file
+
diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml
index 9f667259..effc84d9 100644
--- a/.github/workflows/msrv.yml
+++ b/.github/workflows/msrv.yml
@@ -53,6 +53,23 @@ jobs:
command: test
args: --all-features
+ check-py:
+ name: Check quil-py
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+ steps:
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ override: true
+ - uses: davidB/rust-cargo-make@v1
+ - uses: actions/checkout@v1
+ - uses: snok/install-poetry@v1
+ - name: Run quil-py tests, lints, and formatting checks.
+ run: cargo make --cwd quil-py
+
fmt:
name: Rustfmt
runs-on: ubuntu-latest
@@ -103,7 +120,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
- args: -- -D warnings
+ args: --all-targets --all-features -- -D warnings
deny:
name: Deny
diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml
deleted file mode 100644
index 0a1a0121..00000000
--- a/.github/workflows/prepare-release.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: Prepare Release
-
-on:
- push:
- branches:
- - main
- workflow_dispatch:
- inputs:
- type:
- description: Bump versions and trigger a new release.
- required: true
- default: release
- options:
- - release
- - prerelease
-
-jobs:
- prepare-release:
- runs-on: ubuntu-latest
- env:
- GITHUB_TOKEN: ${{ secrets.PAT }}
- steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0
- token: ${{ secrets.PAT }}
- - name: Install Knope
- uses: knope-dev/action@v1
- with:
- version: 0.7.1 # Test before updating, breaking changes likely: https://github.com/knope-dev/action#install-latest-version
- - run: |
- git config --global user.name "${{ github.triggering_actor }}"
- git config --global user.email "${{ github.triggering_actor}}@users.noreply.github.com"
- - name: Prepare Prerelease
- run: knope prerelease
- if: github.event_name == 'push'
- - name: Prepare Release
- run: knope ${{ inputs.type }}
- if: github.event_name == 'workflow_dispatch'
diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml
new file mode 100644
index 00000000..989f9418
--- /dev/null
+++ b/.github/workflows/publish-docs.yml
@@ -0,0 +1,47 @@
+name: Publish quil-py documentation
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ types:
+ - opened
+ - reopened
+ - synchronize
+ - closed
+
+jobs:
+ publish-docs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+ - name: Install poetry
+ uses: snok/install-poetry@v1
+ - uses: Swatinem/rust-cache@v2
+ - name: Install cargo-make
+ uses: actions-rs/cargo@v1
+ with:
+ command: install
+ args: --debug cargo-make
+ - name: Build quil-py documentation
+ uses: actions-rs/cargo@v1
+ with:
+ command: make
+ args: --cwd quil-py --makefile Makefile.toml docs
+ - name: Deploy preview
+ if: ${{ github.event_name == 'pull_request' }}
+ uses: rossjrw/pr-preview-action@v1
+ with:
+ source-dir: quil-py/build/docs
+ preview-branch: quil-py-docs
+ - name: Deploy docs
+ if: ${{ github.event_name == 'push' }}
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: quil-py/build/docs
+ publish_branch: quil-py-docs
diff --git a/.github/workflows/publish-quil-py.yml b/.github/workflows/publish-quil-py.yml
new file mode 100644
index 00000000..809a7a25
--- /dev/null
+++ b/.github/workflows/publish-quil-py.yml
@@ -0,0 +1,194 @@
+name: Publish quil-py
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+ description: "Manually publish release"
+ inputs:
+ publishWheels:
+ description: "Build and publish wheels to PyPI"
+ type: boolean
+ default: false
+
+jobs:
+ is-python-release:
+ if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'quil-py/v') }}
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo "Release tag starts with quil-py/v, proceeding with release"
+ should-publish-wheels:
+ if: (github.event_name == 'workflow_dispatch' && inputs.publishWheels) || (github.event_name == 'release' && !github.event.release.prerelease)
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo "Publishing wheels"
+
+ macos:
+ runs-on: macos-12
+ needs: [ is-python-release, should-publish-wheels ]
+ strategy:
+ matrix:
+ python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install Rust
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ target: aarch64-apple-darwin
+ profile: minimal
+ default: true
+ - name: Build wheels - universal2
+ # universal2 supports both x86_64 and aarch64
+ uses: messense/maturin-action@v1
+ with:
+ args: -i python --release --target universal2-apple-darwin --manifest-path quil-py/Cargo.toml --out dist
+ - name: Install wheel
+ run: |
+ pip install quil --no-index --find-links dist --force-reinstall
+ - name: Upload wheels
+ uses: actions/upload-artifact@v3
+ with:
+ name: wheels
+ path: dist
+
+ linux:
+ runs-on: ubuntu-22.04
+ needs: [ is-python-release, should-publish-wheels ]
+ env:
+ CXXFLAGS: "-std=c++11"
+ strategy:
+ matrix:
+ python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+ target: [x86_64, aarch64, ppc64le]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install Rust
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ profile: minimal
+ default: true
+ - uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Build wheels
+ uses: messense/maturin-action@v1
+ with:
+ target: ${{ matrix.target }}
+ manylinux: 2014
+ args: -i ${{ matrix.python-version }} --release --manifest-path quil-py/Cargo.toml --out dist
+ - name: Install wheel
+ if: ${{ matrix.target == 'x86_64' }} # pip can only install wheels for it's own architecture
+ run: |
+ pip install quil --no-index --find-links dist --force-reinstall
+ - name: Upload wheels
+ uses: actions/upload-artifact@v3
+ with:
+ name: wheels
+ path: dist
+
+ windows:
+ runs-on: windows-latest
+ needs: [ is-python-release, should-publish-wheels ]
+ strategy:
+ matrix:
+ python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+ target: [x64]
+ steps:
+ # Some of the snapshots have long file paths, so we need to enable long file paths on Windows where the limit is 260 by default
+ - name: Allow Long File Paths
+ run: |
+ reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f
+ # https://github.com/actions/checkout/issues/1285#issuecomment-2042579471
+ git config --system core.longpaths true
+ - uses: actions/checkout@v2
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ profile: minimal
+ default: true
+ - uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ architecture: ${{ matrix.target }}
+ - name: Build wheels
+ uses: messense/maturin-action@v1
+ with:
+ target: ${{ matrix.target }}
+ args: -i python --release --manifest-path quil-py/Cargo.toml --out dist
+ - name: Install built wheel
+ run: |
+ pip install quil --find-links dist --force-reinstall --no-deps --no-index
+ - name: Upload wheels
+ uses: actions/upload-artifact@v2
+ with:
+ name: wheels
+ path: dist
+
+ sdist:
+ runs-on: ubuntu-latest
+ needs: is-python-release
+ env:
+ CXXFLAGS: "-std=c++11"
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install Rust
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ profile: minimal
+ default: true
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+ - name: Build sdist
+ uses: messense/maturin-action@v1
+ with:
+ command: sdist
+ args: --manifest-path quil-py/Cargo.toml --out dist
+ - name: Upload sdist
+ uses: actions/upload-artifact@v3
+ with:
+ name: wheels
+ path: dist
+
+ publish-python-package:
+ name: Release
+ runs-on: ubuntu-latest
+ # `needs` forces this job to wait until all specified jobs
+ # are finished to run. Typically, those jobs would all have
+ # to be successful, but when combined with `if: always()`,
+ # this job is allowed to run after all the needed jobs
+ # finish, regardless of their outcome. In this case, we
+ # still make sure that at least a source distribution
+ # can be published.
+ needs: [ macos, linux, windows, sdist ]
+ if: always() && needs.sdist.result == 'success'
+ permissions:
+ id-token: write
+ steps:
+ - uses: actions/download-artifact@v3
+ - name: Publish to PyPi
+ uses: messense/maturin-action@v1
+ with:
+ command: upload
+ args: --skip-existing wheels/*
+
+ publish-rust-crate:
+ name: Release
+ runs-on: ubuntu-latest
+ needs: publish-python-package
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ token: ${{ secrets.PAT }}
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ override: true
+ - run: cargo publish --manifest-path=quil-py/Cargo.toml --token ${{ secrets.CRATES_IO_TOKEN }}
diff --git a/.github/workflows/publish-quil-rs.yml b/.github/workflows/publish-quil-rs.yml
new file mode 100644
index 00000000..95a6db25
--- /dev/null
+++ b/.github/workflows/publish-quil-rs.yml
@@ -0,0 +1,28 @@
+name: Publish quil-rs
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+ description: "Manually publish release"
+
+jobs:
+ is-quil-rs-release:
+ runs-on: ubuntu-latest
+ if: ${{ github.event_name == 'workflow_dispatch' || startswith(github.event.release.tag_name, 'quil-rs/v') }}
+ steps:
+ - run: echo "release tag starts with quil-rs/v, proceeding with release"
+
+ release:
+ runs-on: ubuntu-latest
+ needs: is-quil-rs-release
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ token: ${{ secrets.PAT }}
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ override: true
+ - run: cargo publish --manifest-path=quil-rs/Cargo.toml --token ${{ secrets.CRATES_IO_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 2b9ce2e7..14cefc78 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,21 +1,39 @@
name: Release
on:
- release:
- types: [published]
-
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+ inputs:
+ type:
+ description: Bump versions and trigger a new release.
+ required: true
+ default: release
+ options:
+ - release
+ - prerelease
+
jobs:
release:
runs-on: ubuntu-latest
+ env:
+ GITHUB_TOKEN: ${{ secrets.PAT }}
steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0
- token: ${{ secrets.PAT }}
- - uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- override: true
- - uses: katyo/publish-crates@v1
- with:
- registry-token: ${{ secrets.CRATES_IO_TOKEN }}
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ token: ${{ secrets.PAT }}
+ - name: Install Knope
+ uses: knope-dev/action@v1
+ with:
+ version: 0.7.1 # Test before updating, breaking changes likely: https://github.com/knope-dev/action#install-latest-version
+ - run: |
+ git config --global user.name "${{ github.triggering_actor }}"
+ git config --global user.email "${{ github.triggering_actor}}@users.noreply.github.com"
+ - name: Prepare Prerelease
+ run: knope release --prerelease-label=rc
+ if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.type == 'prerelease')
+ - name: Prepare Release
+ run: knope release
+ if: github.event_name == 'workflow_dispatch' && inputs.type == 'release'
diff --git a/.gitignore b/.gitignore
index 224fdc61..d91fab29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,22 @@
/target
node_modules
-Cargo.lock
+.venv
+.DS_Store
-# JetBrains Editors
-.idea/
\ No newline at end of file
+# unreviewed insta snapshots
+*.snap.new
+
+# IDEs and editors
+.idea/
+.vscode/
+
+# Python artifacts
+*.so
+__pycache__
+**./.null-ls-cache*
+
+# quil-py documentation
+quil-py/build
+
+# unversioned developer notes
+scratch/
diff --git a/.gitmodules b/.gitmodules
index 4769fdae..c9d91faf 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
-[submodule "benches/quilc"]
- path = benches/quilc
+[submodule "quil-rs/benches/quilc"]
+ path = quil-rs/benches/quilc
url = https://github.com/quil-lang/quilc.git
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 31b91c92..00000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,621 +0,0 @@
-## 0.16.0-rc.1
-
-### Breaking Changes
-
-- empty commit so knope calculates current version
-
-### Fixes
-
-- allow for variable qubit in DEFCAL MEASURE
-- correctly expand delays (#142)
-
-## 0.10.0-rc.2
-
-### Breaking Changes
-
-- empty commit to force version bump
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- RESET frame computation
-- Program.into_simplified
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- allow for variable qubit in DEFCAL MEASURE
-- correctly expand delays (#142)
-- update snapshots
-- Waveforms w/o params need no parens
-- support escaped double quotes and backslashes in strings (#120)
-- make dynamic error Sync as well (#131)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0-rc.1
-
-### Breaking Changes
-
-- empty commit to force version bump
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- RESET frame computation
-- Program.into_simplified
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- allow for variable qubit in DEFCAL MEASURE
-- correctly expand delays (#142)
-- update snapshots
-- Waveforms w/o params need no parens
-- support escaped double quotes and backslashes in strings (#120)
-- make dynamic error Sync as well (#131)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0-rc.0
-
-### Breaking Changes
-
-- empty commit to force version bump
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- RESET frame computation
-- Program.into_simplified
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- allow for variable qubit in DEFCAL MEASURE
-- correctly expand delays (#142)
-- update snapshots
-- Waveforms w/o params need no parens
-- support escaped double quotes and backslashes in strings (#120)
-- make dynamic error Sync as well (#131)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.16.0-rc.0
-
-### Breaking Changes
-
-- empty commit to force version bump
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- RESET frame computation
-- Program.into_simplified
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- correctly expand delays (#142)
-- update snapshots
-- Waveforms w/o params need no parens
-- support escaped double quotes and backslashes in strings (#120)
-- make dynamic error Sync as well (#131)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.15.0
-
-### Breaking Changes
-
-- empty commit to force version bump
-
-## 0.10.0
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- RESET frame computation
-- Program.into_simplified
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- update snapshots
-- Waveforms w/o params need no parens
-- support escaped double quotes and backslashes in strings (#120)
-- make dynamic error Sync as well (#131)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0-rc.2
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- RESET frame computation
-- Program.into_simplified
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- update snapshots
-- Waveforms w/o params need no parens
-- support escaped double quotes and backslashes in strings (#120)
-- make dynamic error Sync as well (#131)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0-rc.1
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- RESET frame computation
-- Program.into_simplified
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- support escaped double quotes and backslashes in strings (#120)
-- make dynamic error Sync as well (#131)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0-rc.0
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- Support Expression arithmetic operations (#126)
-- Program.into_simplified
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- make dynamic error Sync as well (#131)
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.15.0-rc.0
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- make dynamic error Sync as well (#131)
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.14.2
-
-### Features
-
-- Support Expression arithmetic operations (#126)
-
-### Fixes
-
-- make dynamic error Sync as well (#131)
-- support escaped double quotes and backslashes in strings (#120)
-
-## 0.14.2-rc.0
-
-### Features
-
-- Support Expression arithmetic operations (#126)
-
-### Fixes
-
-- make dynamic error Sync as well (#131)
-- support escaped double quotes and backslashes in strings (#120)
-
-## 0.10.0-rc.1
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- Support Expression arithmetic operations (#126)
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- make dynamic error Sync as well (#131)
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0-rc.0
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- make dynamic error Sync as well (#131)
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0-rc.1
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- make dynamic error Sync as well (#131)
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0-rc.0
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- make dynamic error Sync as well (#131)
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.11.0-rc.0
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- support INCLUDE
-- support CONVERT
-- support NOP
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.10.0
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
-
-## 0.15.0-rc.0
-
-### Breaking Changes
-
-- genericize parsing errors and remove error Strings
-- fix all compilation errors from error refactor
-
-### Features
-
-- impl FromStr for MemoryReference
-
-### Fixes
-
-- support escaped double quotes and backslashes in strings (#120)
-- fix performance regression (#113)
-- do not get line/column info for tokens except on error
-- require dynamic error to by Send (#108)
-- bump thiserror version and update import name (#103)
-- identifier parser (#100)
-- test cases with rstest
-- test cases should not violate the spec
-- remove a `dbg!` statement left over from #88
-- use structured error
-- update node version and dependencies for semantic-release (#84)
-- update semantic-release version as per dependabot suggestion (#83)
-- DEFCAL MEASURE serialization
-- test roundtrip of program->string->program
-- linting
-- Instruction used/blocked frames calculation (#74)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..0c3d5da7
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,67 @@
+# Contributing to quil-rs and quil-py
+
+Welcome to the `quil-rs` project, and thanks for contributing!
+
+This guide is to help walk you through contributing in different ways to `quil-rs` and `quil-py`,
+as well as share some general how-tos for development, testing, and maintenance.
+
+## Table of Contents
+
+[Developer Guidelines](#developer-guidelines)
+
+- [Instruction Module](#instruction-module)
+
+[Tips for Maintainers](#tips-for-maintainers)
+
+- [Makefile Tasks](#makefiles-tasks)
+
+## Developer Guidelines
+
+### Instruction Module
+
+The `instruction` module is large, so we follow a few guidelines when adding or changing instructions to help keep
+them organized and consistent in both the `quil-rs` and `quil-py` crates.
+
+All instruction definitions live inside of the `instruction` module. For ease of development,
+instruction types are grouped into submodules so that similar instructions can be modified and viewed together
+rather than having all instructions in one large file. However, to avoid imposing potentially arbritrary
+instruction categories onto the user, the `instruction` module publically re-exports all of its types from
+its root.
+
+This module structure should remain consistent between both `quil-rs` and `quil-py`. For example, the file
+`src/instruction/gate.rs` exists in both `quil-rs` and `quil-py` and contains the same set of instruction
+definitions (for their respective target language, of course).
+
+In short, an instruction should:
+ 1. Be organized in the equivalent `instruction` submodule for both `quil-rs` and `quil-py` crates
+ 2. Only be re-exported publicly from the root of the `Instruction` module
+
+## Tips for Maintainers
+
+### Makefile Tasks
+
+This repo uses [cargo-make](https://github.com/sagiegurari/cargo-make) to define task flows that perform
+common operations. We've extended the default flow with tasks specific to the `quil-rs` and `quil-py`
+crates. You can run the default task with:
+
+```sh
+cargo make
+# or
+makers
+```
+
+It's worth periodically running this command as you develop to make sure there are no unexpected failures.
+
+Check the [`cargo-make documentation`](https://github.com/sagiegurari/cargo-make#predefined-makefiles) for
+more information on the predefined tasks available. The custom flows we've added are described below:
+
+#### `stubtest-flow`
+
+The `quil-py` crate defines `stubtest-flow`. It builds and installs the Python package, then runs
+[stubtest](https://mypy.readthedocs.io/en/stable/stubtest.html) to check that the manually written type hints
+are consistent with what the package exports. If any errors are reported, they should be fixed so users
+of the Python package are given accurate type hints by their tooling.
+
+### `pytest-flow`
+
+The `quil-py` crate also defines `pytest-flow`. It builds and installs the Python package, then runs a test suite against the package using [pytest](https://docs.pytest.org/en/7.2.x/). These tests are used to validate functionality of the `quil` package at the Python level and should always pass.
diff --git a/Cargo.lock b/Cargo.lock
index da024494..ec21256a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "aho-corasick"
-version = "0.7.20"
+version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
@@ -18,21 +18,75 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
-name = "atty"
-version = "0.2.14"
+name = "anstream"
+version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
dependencies = [
- "hermit-abi",
- "libc",
- "winapi",
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
]
[[package]]
-name = "autocfg"
+name = "anstyle"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
+dependencies = [
+ "anstyle",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
+[[package]]
+name = "approx"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
+dependencies = [
+ "num-complex",
+ "num-traits",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "bit-set"
@@ -51,27 +105,27 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
-version = "1.3.2"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "bumpalo"
-version = "3.11.1"
+version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "bytecount"
-version = "0.6.3"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
+checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
[[package]]
-name = "byteorder"
-version = "1.4.3"
+name = "bytemuck"
+version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
[[package]]
name = "cast"
@@ -87,9 +141,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "ciborium"
-version = "0.2.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
"ciborium-io",
"ciborium-ll",
@@ -98,15 +152,15 @@ dependencies = [
[[package]]
name = "ciborium-io"
-version = "0.2.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "ciborium-ll"
-version = "0.2.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
"ciborium-io",
"half",
@@ -114,53 +168,77 @@ dependencies = [
[[package]]
name = "clap"
-version = "3.2.23"
+version = "4.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
+checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
dependencies = [
- "bitflags",
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
+dependencies = [
+ "anstream",
+ "anstyle",
"clap_lex",
- "indexmap",
- "textwrap",
+ "strsim",
]
[[package]]
-name = "clap_lex"
-version = "0.2.4"
+name = "clap_derive"
+version = "4.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
dependencies = [
- "os_str_bytes",
+ "heck 0.5.0",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "syn 2.0.68",
]
+[[package]]
+name = "clap_lex"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
+
[[package]]
name = "console"
-version = "0.15.2"
+version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
+checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
- "terminal_size",
- "winapi",
+ "windows-sys",
]
[[package]]
name = "criterion"
-version = "0.4.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
+checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
- "atty",
"cast",
"ciborium",
"clap",
"criterion-plot",
- "itertools",
- "lazy_static",
+ "is-terminal",
+ "itertools 0.10.5",
"num-traits",
+ "once_cell",
"oorandom",
"plotters",
"rayon",
@@ -179,63 +257,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
- "itertools",
-]
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
-dependencies = [
- "cfg-if",
- "crossbeam-utils",
+ "itertools 0.10.5",
]
[[package]]
name = "crossbeam-deque"
-version = "0.8.2"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
- "cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
-version = "0.9.11"
+version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
- "autocfg",
- "cfg-if",
"crossbeam-utils",
- "memoffset",
- "scopeguard",
]
[[package]]
name = "crossbeam-utils"
-version = "0.8.12"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "deranged"
+version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
- "cfg-if",
+ "powerfmt",
]
[[package]]
name = "dot-writer"
-version = "0.1.2"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1defb949b123415131ecae40ab5dca70e9f39eedda3de2cebb03a8a98fdf5894"
+checksum = "3d1b11bd5e7e98406c6ff39fbc94d6e910a489b978ce7f17c19fce91a1195b7a"
[[package]]
name = "either"
-version = "1.8.0"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
[[package]]
name = "encode_unicode"
@@ -244,14 +319,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
-name = "fastrand"
-version = "1.8.0"
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
- "instant",
+ "libc",
+ "windows-sys",
]
+[[package]]
+name = "fastrand"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
+
[[package]]
name = "fixedbitset"
version = "0.4.2"
@@ -266,9 +354,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "futures"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
@@ -281,9 +369,9 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
"futures-core",
"futures-sink",
@@ -291,15 +379,15 @@ dependencies = [
[[package]]
name = "futures-core"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-executor"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
"futures-core",
"futures-task",
@@ -308,44 +396,44 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
[[package]]
name = "futures-macro"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
- "proc-macro2 1.0.47",
- "quote 1.0.21",
- "syn 1.0.103",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "syn 2.0.68",
]
[[package]]
name = "futures-sink"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-task"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-timer"
-version = "3.0.2"
+version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
[[package]]
name = "futures-util"
-version = "0.3.25"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-channel",
"futures-core",
@@ -361,74 +449,106 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.8"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
[[package]]
name = "half"
-version = "1.8.2"
+version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
+checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+]
[[package]]
name = "hashbrown"
-version = "0.12.3"
+version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "heck"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
-version = "0.1.19"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "indexmap"
-version = "1.9.1"
+version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
- "autocfg",
+ "equivalent",
"hashbrown",
]
+[[package]]
+name = "indoc"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
+
[[package]]
name = "insta"
-version = "1.21.0"
+version = "1.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581d4e3314cae4536e5d22ffd23189d4a374696c5ef733eadafae0ed273fd303"
+checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5"
dependencies = [
"console",
"lazy_static",
"linked-hash-map",
"similar",
- "yaml-rust",
]
[[package]]
-name = "instant"
-version = "0.1.12"
+name = "inventory"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
+
+[[package]]
+name = "is-terminal"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [
- "cfg-if",
+ "hermit-abi",
+ "libc",
+ "windows-sys",
]
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
+
[[package]]
name = "itertools"
version = "0.10.5"
@@ -438,26 +558,35 @@ dependencies = [
"either",
]
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
-version = "1.0.4"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "js-sys"
-version = "0.3.60"
+version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lexical"
@@ -534,9 +663,15 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.137"
+version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+
+[[package]]
+name = "libm"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "linked-hash-map"
@@ -544,26 +679,49 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
[[package]]
name = "log"
-version = "0.4.17"
+version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+
+[[package]]
+name = "matrixmultiply"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
dependencies = [
- "cfg-if",
+ "autocfg",
+ "rawpointer",
]
[[package]]
name = "memchr"
-version = "2.5.0"
+version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memoffset"
-version = "0.6.5"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
@@ -574,11 +732,54 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+[[package]]
+name = "nalgebra"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d506eb7e08d6329505faa8a3a00a5dcc6de9f76e0c77e4b75763ae3c770831ff"
+dependencies = [
+ "approx",
+ "matrixmultiply",
+ "nalgebra-macros",
+ "num-complex",
+ "num-rational",
+ "num-traits",
+ "rand",
+ "rand_distr",
+ "simba",
+ "typenum",
+]
+
+[[package]]
+name = "nalgebra-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218"
+dependencies = [
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ndarray"
+version = "0.15.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32"
+dependencies = [
+ "approx",
+ "matrixmultiply",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "rawpointer",
+]
+
[[package]]
name = "nom"
-version = "7.1.1"
+version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
@@ -586,9 +787,9 @@ dependencies = [
[[package]]
name = "nom_locate"
-version = "4.0.0"
+version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37794436ca3029a3089e0b95d42da1f0b565ad271e4d3bb4bad0c7bb70b10605"
+checksum = "1e3c83c053b0713da60c5b8de47fe8e494fe3ece5267b2f23090a07a053ba8f3"
dependencies = [
"bytecount",
"memchr",
@@ -597,37 +798,68 @@ dependencies = [
[[package]]
name = "num-complex"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
+checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
+ "num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
-version = "0.2.15"
+version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
+ "libm",
]
[[package]]
-name = "num_cpus"
-version = "1.13.1"
+name = "numpy"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
+checksum = "bef41cbb417ea83b30525259e30ccef6af39b31c240bda578889494c5392d331"
dependencies = [
- "hermit-abi",
"libc",
+ "ndarray",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "pyo3",
+ "rustc-hash",
]
[[package]]
name = "once_cell"
-version = "1.17.1"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "oorandom"
@@ -636,16 +868,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
-name = "os_str_bytes"
-version = "6.3.0"
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "petgraph"
-version = "0.6.2"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
+checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset",
"indexmap",
@@ -653,9 +908,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
-version = "0.2.9"
+version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pin-utils"
@@ -665,9 +920,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "plotters"
-version = "0.3.4"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
+checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3"
dependencies = [
"num-traits",
"plotters-backend",
@@ -678,24 +933,36 @@ dependencies = [
[[package]]
name = "plotters-backend"
-version = "0.3.4"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
+checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7"
[[package]]
name = "plotters-svg"
-version = "0.3.3"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
+checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705"
dependencies = [
"plotters-backend",
]
+[[package]]
+name = "portable-atomic"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
[[package]]
name = "ppv-lite86"
-version = "0.2.16"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
@@ -708,31 +975,31 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.47"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "proptest"
-version = "1.0.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"
+checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d"
dependencies = [
"bit-set",
+ "bit-vec",
"bitflags",
- "byteorder",
"lazy_static",
"num-traits",
- "quick-error 2.0.1",
"rand",
"rand_chacha",
"rand_xorshift",
"regex-syntax",
"rusty-fork",
"tempfile",
+ "unarray",
]
[[package]]
@@ -746,6 +1013,72 @@ dependencies = [
"syn 0.15.44",
]
+[[package]]
+name = "pyo3"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233"
+dependencies = [
+ "cfg-if",
+ "indexmap",
+ "indoc",
+ "inventory",
+ "libc",
+ "memoffset",
+ "num-complex",
+ "parking_lot",
+ "portable-atomic",
+ "pyo3-build-config",
+ "pyo3-ffi",
+ "pyo3-macros",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-build-config"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7"
+dependencies = [
+ "once_cell",
+ "target-lexicon",
+]
+
+[[package]]
+name = "pyo3-ffi"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa"
+dependencies = [
+ "libc",
+ "pyo3-build-config",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158"
+dependencies = [
+ "proc-macro2 1.0.86",
+ "pyo3-macros-backend",
+ "quote 1.0.36",
+ "syn 2.0.68",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2 1.0.86",
+ "pyo3-build-config",
+ "quote 1.0.36",
+ "syn 2.0.68",
+]
+
[[package]]
name = "quick-error"
version = "1.2.3"
@@ -753,20 +1086,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
-name = "quick-error"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
+name = "quil-cli"
+version = "0.3.1"
+dependencies = [
+ "anyhow",
+ "clap",
+ "quil-rs",
+]
+
+[[package]]
+name = "quil-py"
+version = "0.10.1"
+dependencies = [
+ "indexmap",
+ "ndarray",
+ "numpy",
+ "pyo3",
+ "pyo3-build-config",
+ "quil-rs",
+ "rigetti-pyo3",
+ "strum",
+]
[[package]]
name = "quil-rs"
-version = "0.16.0-rc.1"
+version = "0.26.1"
dependencies = [
+ "approx",
+ "clap",
"criterion",
"dot-writer",
"indexmap",
"insta",
+ "itertools 0.12.1",
"lexical",
+ "ndarray",
"nom",
"nom_locate",
"num-complex",
@@ -774,9 +1128,12 @@ dependencies = [
"petgraph",
"proptest",
"proptest-derive",
+ "rand",
+ "rasciigraph",
"regex",
"rstest",
"serde",
+ "statrs",
"strum",
"thiserror",
]
@@ -792,11 +1149,11 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
- "proc-macro2 1.0.47",
+ "proc-macro2 1.0.86",
]
[[package]]
@@ -829,6 +1186,16 @@ dependencies = [
"getrandom",
]
+[[package]]
+name = "rand_distr"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
+dependencies = [
+ "num-traits",
+ "rand",
+]
+
[[package]]
name = "rand_xorshift"
version = "0.3.0"
@@ -838,44 +1205,64 @@ dependencies = [
"rand_core",
]
+[[package]]
+name = "rasciigraph"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89a3273d76a0cdbb09ecead2f6007d6d169211f3c9c6dd30cd8a2e8175adcb74"
+
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
[[package]]
name = "rayon"
-version = "1.5.3"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
- "autocfg",
- "crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
-version = "1.9.3"
+version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
- "crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
- "num_cpus",
]
[[package]]
name = "redox_syscall"
-version = "0.2.16"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
-version = "1.7.2"
+version = "1.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
@@ -884,24 +1271,35 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.6.29"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
-name = "remove_dir_all"
-version = "0.5.3"
+name = "relative-path"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
+
+[[package]]
+name = "rigetti-pyo3"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+checksum = "c59068763670399bb3e895a17cc631d9214c3172b64fc74d3ab63dac7371c340"
dependencies = [
- "winapi",
+ "indexmap",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "pyo3",
+ "time",
]
[[package]]
name = "rstest"
-version = "0.15.0"
+version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9c9dc66cc29792b663ffb5269be669f1613664e69ad56441fdb895c2347b930"
+checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199"
dependencies = [
"futures",
"futures-timer",
@@ -911,17 +1309,27 @@ dependencies = [
[[package]]
name = "rstest_macros"
-version = "0.14.0"
+version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5015e68a0685a95ade3eee617ff7101ab6a3fc689203101ca16ebc16f2b89c66"
+checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605"
dependencies = [
"cfg-if",
- "proc-macro2 1.0.47",
- "quote 1.0.21",
+ "glob",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "regex",
+ "relative-path",
"rustc_version",
- "syn 1.0.103",
+ "syn 2.0.68",
+ "unicode-ident",
]
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
[[package]]
name = "rustc_version"
version = "0.4.0"
@@ -931,11 +1339,24 @@ dependencies = [
"semver",
]
+[[package]]
+name = "rustix"
+version = "0.38.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
[[package]]
name = "rustversion"
-version = "1.0.9"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
[[package]]
name = "rusty-fork"
@@ -944,16 +1365,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
dependencies = [
"fnv",
- "quick-error 1.2.3",
+ "quick-error",
"tempfile",
"wait-timeout",
]
[[package]]
name = "ryu"
-version = "1.0.11"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "safe_arch"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a"
+dependencies = [
+ "bytemuck",
+]
[[package]]
name = "same-file"
@@ -966,88 +1396,126 @@ dependencies = [
[[package]]
name = "scopeguard"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
-version = "1.0.14"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "serde"
-version = "1.0.147"
+version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.147"
+version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [
- "proc-macro2 1.0.47",
- "quote 1.0.21",
- "syn 1.0.103",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "syn 2.0.68",
]
[[package]]
name = "serde_json"
-version = "1.0.87"
+version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [
"itoa",
"ryu",
"serde",
]
+[[package]]
+name = "simba"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0b7840f121a46d63066ee7a99fc81dcabbc6105e437cae43528cea199b5a05f"
+dependencies = [
+ "approx",
+ "num-complex",
+ "num-traits",
+ "paste",
+ "wide",
+]
+
[[package]]
name = "similar"
-version = "2.2.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803"
+checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
[[package]]
name = "slab"
-version = "0.4.7"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+[[package]]
+name = "statrs"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b35a062dbadac17a42e0fc64c27f419b25d6fae98572eb43c8814c9e873d7721"
+dependencies = [
+ "approx",
+ "lazy_static",
+ "nalgebra",
+ "num-traits",
+ "rand",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
[[package]]
name = "strum"
-version = "0.24.1"
+version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
-version = "0.24.3"
+version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
- "heck",
- "proc-macro2 1.0.47",
- "quote 1.0.21",
+ "heck 0.5.0",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
"rustversion",
- "syn 1.0.103",
+ "syn 2.0.68",
]
[[package]]
@@ -1063,65 +1531,83 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.103"
+version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
- "proc-macro2 1.0.47",
- "quote 1.0.21",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
"unicode-ident",
]
[[package]]
-name = "tempfile"
-version = "3.3.0"
+name = "syn"
+version = "2.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
+checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
dependencies = [
- "cfg-if",
- "fastrand",
- "libc",
- "redox_syscall",
- "remove_dir_all",
- "winapi",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "unicode-ident",
]
[[package]]
-name = "terminal_size"
-version = "0.1.17"
+name = "target-lexicon"
+version = "0.12.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
-dependencies = [
- "libc",
- "winapi",
-]
+checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
[[package]]
-name = "textwrap"
-version = "0.16.0"
+name = "tempfile"
+version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
+checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "rustix",
+ "windows-sys",
+]
[[package]]
name = "thiserror"
-version = "1.0.37"
+version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.37"
+version = "1.0.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
+dependencies = [
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "syn 2.0.68",
+]
+
+[[package]]
+name = "time"
+version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
- "proc-macro2 1.0.47",
- "quote 1.0.21",
- "syn 1.0.103",
+ "deranged",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
]
+[[package]]
+name = "time-core"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+
[[package]]
name = "tinytemplate"
version = "1.2.1"
@@ -1132,11 +1618,23 @@ dependencies = [
"serde_json",
]
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[package]]
+name = "unarray"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
+
[[package]]
name = "unicode-ident"
-version = "1.0.5"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-xid"
@@ -1144,6 +1642,18 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+[[package]]
+name = "unindent"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
[[package]]
name = "wait-timeout"
version = "0.2.0"
@@ -1155,12 +1665,11 @@ dependencies = [
[[package]]
name = "walkdir"
-version = "2.3.2"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
- "winapi",
"winapi-util",
]
@@ -1172,9 +1681,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.83"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -1182,94 +1691,146 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.83"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
dependencies = [
"bumpalo",
"log",
"once_cell",
- "proc-macro2 1.0.47",
- "quote 1.0.21",
- "syn 1.0.103",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "syn 2.0.68",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.83"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [
- "quote 1.0.21",
+ "quote 1.0.36",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.83"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
- "proc-macro2 1.0.47",
- "quote 1.0.21",
- "syn 1.0.103",
+ "proc-macro2 1.0.86",
+ "quote 1.0.36",
+ "syn 2.0.68",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.83"
+version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "web-sys"
-version = "0.3.60"
+version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
+checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
-name = "winapi"
-version = "0.3.9"
+name = "wide"
+version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+checksum = "8a040b111774ab63a19ef46bbc149398ab372b4ccdcfd719e9814dbd7dfd76c8"
dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
+ "bytemuck",
+ "safe_arch",
]
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
[[package]]
name = "winapi-util"
-version = "0.1.5"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
- "winapi",
+ "windows-sys",
]
[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
+name = "windows-sys"
+version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
[[package]]
-name = "yaml-rust"
-version = "0.4.5"
+name = "windows-targets"
+version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
- "linked-hash-map",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
diff --git a/Cargo.toml b/Cargo.toml
index 4cd3cedf..85969111 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,42 +1,12 @@
-[package]
-name = "quil-rs"
-description = "Rust tooling for Quil (Quantum Instruction Language)"
-version ="0.16.0-rc.1"
-edition = "2021"
-license = "Apache-2.0"
-repository = "https://github.com/rigetti/quil-rust"
-keywords = ["Quil", "Quantum", "Rigetti"]
-categories = ["parser-implementations", "science", "compilers", "emulators"]
-
-[dependencies]
-dot-writer = { version = "0.1.2", optional = true }
-indexmap = "1.6.1"
-lexical = "6.1.1"
-nom = "7.1.1"
-nom_locate = "4.0.0"
-num-complex = "0.4.0"
-once_cell = "1.17.1"
-petgraph = "0.6.2"
-regex = "1.7.2"
-serde = { version = "1.0.125", features = ["derive"] }
-strum = { version = "0.24.1", features = ["derive"] }
-thiserror = "1.0.37"
-
-[dev-dependencies]
-criterion = { version = "0.4.0", features = ["html_reports"] }
-insta = "1.7.1"
-proptest = "1.0.0"
-proptest-derive = "0.3.0"
-rstest = "0.15.0"
-
-[features]
-graphviz-dot = ["dot-writer"]
-latex = []
+[workspace]
+members = ["quil-rs", "quil-py", "quil-cli"]
+resolver = "2"
[profile.release]
lto = true
codegen-units = 1
-[[bench]]
-name = "parser"
-harness = false
+[workspace.dependencies]
+ndarray = { version = "0.15.6", features = ["approx-0_5"] }
+strum = { version = "0.26.0", features = ["derive"] }
+indexmap = "2.2.6"
diff --git a/Makefile.toml b/Makefile.toml
new file mode 100644
index 00000000..4ae4d011
--- /dev/null
+++ b/Makefile.toml
@@ -0,0 +1,3 @@
+[tasks.sync-versions]
+workspace = false
+script = "sh ./scripts/sync_versions.sh"
diff --git a/README.md b/README.md
index f503b71b..b26ace68 100644
--- a/README.md
+++ b/README.md
@@ -10,11 +10,10 @@ It serves three purposes:
It should be considered unstable until the release of v1.0.
-
## Testing
When testing this crate, you should run with the `--all-features` flag to ensure all tests are executed.
```sh
cargo test --all-features
-```
\ No newline at end of file
+```
diff --git a/benches/parser.rs b/benches/parser.rs
deleted file mode 100644
index c966b1ca..00000000
--- a/benches/parser.rs
+++ /dev/null
@@ -1,84 +0,0 @@
-use criterion::{criterion_group, criterion_main, Criterion};
-use std::{fs, path::Path, process::Command, str::FromStr};
-
-fn benchmark_sample_calibration(c: &mut Criterion) {
- let input = fs::read_to_string(concat!(
- env!("CARGO_MANIFEST_DIR"),
- "/benches/sample-calibrations.quil"
- ))
- .expect("benches/sample-calibrations.quil should exist");
-
- let mut group = c.benchmark_group("calibration file");
- group.sample_size(100);
- group.bench_function("Sample calibration file", |b| {
- b.iter(|| {
- let _ = quil_rs::Program::from_str(&input);
- })
- });
- group.finish();
-}
-
-fn benchmark_quil_corpus(c: &mut Criterion) {
- from_corpus().iter().for_each(|cfg| {
- c.bench_function(&cfg.name, |b| {
- b.iter(|| {
- let _ = quil_rs::Program::from_str(&cfg.program);
- })
- });
- })
-}
-
-struct QuilBenchConfig {
- name: String,
- program: String,
-}
-
-fn from_corpus() -> Vec {
- const PATH_SRC: &str = "benches/quilc/tests/good-test-files";
-
- // collect valid quil programs
- let mut programs = vec![];
- let corpus_dir = Path::new(PATH_SRC);
- if !corpus_dir.exists() {
- init_submodules()
- }
-
- let dir = fs::read_dir(corpus_dir).expect("failed to locate quil corpus directory");
-
- dir.filter_map(Result::ok)
- .filter(|entry| {
- entry
- .metadata()
- .expect("failed to read file metadata")
- .is_file()
- })
- .for_each(|entry| {
- let program =
- fs::read_to_string(entry.path()).expect("failed to read quil program file");
- let name = entry
- .file_name()
- .to_str()
- .expect("bad filename")
- .to_string();
-
- // attempt to parse the quil once, ignoring unparsable input (only benchmark parsable code)
- if quil_rs::Program::from_str(&program).is_ok() {
- programs.push(QuilBenchConfig { name, program });
- }
- });
-
- programs
-}
-
-// in the event someone wants to run the benchmarks locally, this will download the corpus of quil used
-fn init_submodules() {
- Command::new("git")
- .args(["submodule", "update", "--init", "--recursive"])
- .spawn()
- .expect("failed to spawn git process")
- .wait_with_output()
- .expect("failed to init submodules, verify `git` is installed");
-}
-
-criterion_group!(benches, benchmark_sample_calibration, benchmark_quil_corpus);
-criterion_main!(benches);
diff --git a/benches/quilc b/benches/quilc
deleted file mode 160000
index a2925c5d..00000000
--- a/benches/quilc
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit a2925c5dd1764534ef8ea4e66b051cc43cecea30
diff --git a/deny.toml b/deny.toml
index e89660a5..ec107f0b 100644
--- a/deny.toml
+++ b/deny.toml
@@ -19,13 +19,13 @@ vulnerability = "deny"
# The lint level for unmaintained crates
unmaintained = "deny"
# The lint level for crates that have been yanked from their source registry
-yanked = "deny"
+yanked = "warn"
# The lint level for crates with security notices.
notice = "deny"
# A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered.
ignore = [
- "RUSTSEC-2023-0018" # remove_dir_all is used by proptest, a dev dependency
+ "RUSTSEC-2024-0320" # yaml-rust is unmaintained, dependency of insta
]
# This section is considered when running `cargo deny check licenses`
@@ -33,7 +33,14 @@ ignore = [
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
unlicensed = "deny"
-allow = ["Apache-2.0", "Apache-2.0 WITH LLVM-exception", "BSD-2-Clause", "BSD-3-Clause", "MIT", "Unicode-DFS-2016"]
+allow = [
+ "Apache-2.0",
+ "Apache-2.0 WITH LLVM-exception",
+ "BSD-2-Clause",
+ "BSD-3-Clause",
+ "MIT",
+ "Unicode-DFS-2016",
+]
# List of explictly disallowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
@@ -71,12 +78,16 @@ multiple-versions = "deny"
wildcards = "deny"
highlight = "all"
skip-tree = [
- { name = "syn", version = "*", depth = 5 }, # Used in both serde_derive and proptest-derive
- { name = "quick-error", version = "*" }, # proptest relies on two versions of this
- { name = "itoa", version = "*" }, # various dependencies rely on two versions of this
- { name = "hermit-abi", version = "*" }, # various dependencies rely on two versions of this
- { name = "memoffset", version = "*" }, # various dependencies rely on two versions of this
- { name = "windows-sys", version = "*" }, # various dependencies rely on two versions of this
+ { name = "syn", version = "*", depth = 5 }, # Used in both serde_derive and proptest-derive
+ { name = "quick-error", version = "*" }, # proptest relies on two versions of this
+ { name = "itoa", version = "*" }, # various dependencies rely on two versions of this
+ { name = "hermit-abi", version = "*" }, # various dependencies rely on two versions of this
+ { name = "memoffset", version = "*" }, # various dependencies rely on two versions of this
+ { name = "windows-sys", version = "*" }, # various dependencies rely on two versions of this
+ { name = "regex-syntax", version = "*" }, # proptest and criterion rely on two versions of this
+ { name = "redox_syscall", version = "*" }, # proptest and pyo3 rely on two versions of this
+ { name = "itertools", version = "*" }, # proptest relies on an older version of itertools than we use
+ { name = "heck", version = "*" }, # conflicting dependency with pyo3 and clap
]
# This section is considered when running `cargo deny check sources`.
@@ -92,4 +103,3 @@ unknown-git = "deny"
# List of URLs for allowed crate registries. Defaults to the crates.io index
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
-
diff --git a/knope.toml b/knope.toml
index 31ec98ee..b36c3693 100644
--- a/knope.toml
+++ b/knope.toml
@@ -1,41 +1,47 @@
-[package]
-versioned_files = ["Cargo.toml"]
-changelog = "CHANGELOG.md"
+[packages.quil-rs]
+versioned_files = ["quil-rs/Cargo.toml"]
+changelog = "quil-rs/CHANGELOG.md"
+scopes = ["rs", "rust", "quil-rs"]
+
+[packages.quil-py]
+versioned_files = ["quil-py/Cargo.toml", "quil-py/pyproject.toml"]
+changelog = "quil-py/CHANGELOG.md"
+scopes = ["py", "python", "quil-py"]
+
+[packages.quil-cli]
+versioned_files = ["quil-cli/Cargo.toml"]
+changelog = "quil-cli/CHANGELOG.md"
+scopes = ["cli", "quil-cli"]
[[workflows]]
-name = "prerelease"
+name = "release"
[[workflows.steps]]
type = "PrepareRelease"
-prerelease_label = "rc"
[[workflows.steps]]
type = "Command"
-command = "cargo update -w && git add Cargo.lock && git commit -m \"chore: prepare pre-release $version [skip ci]\""
-variables = { "$version" = "Version" }
+command = "sh ./scripts/sync_versions.sh"
[[workflows.steps]]
type = "Command"
-command = "git push"
+command = "git add quil-py/Cargo.toml"
[[workflows.steps]]
-type = "Release"
-
-[[workflows]]
-name = "release"
-
-[[workflows.steps]]
-type = "PrepareRelease"
+type = "Command"
+command = "git add quil-cli/Cargo.toml"
[[workflows.steps]]
type = "Command"
-command = "git add Cargo.lock && git commit -m \"chore: prepare release $version [skip ci]\""
-variables = { "$version" = "Version" }
+command = "git commit -m \"chore: prepare release [skip ci]\""
[[workflows.steps]]
type = "Command"
command = "git push"
+[[workflows.steps]]
+type = "Release"
+
[github]
owner = "rigetti"
repo = "quil-rs"
diff --git a/quil-cli/CHANGELOG.md b/quil-cli/CHANGELOG.md
new file mode 100644
index 00000000..0517a714
--- /dev/null
+++ b/quil-cli/CHANGELOG.md
@@ -0,0 +1,383 @@
+## 0.3.1
+
+### Features
+
+- add waveform templates (#369)
+
+### Fixes
+
+- Parsing programs with integers that overflow a u64 will no longer panic; instead, they will raise an error. (#372)
+
+## 0.3.1-rc.1
+
+### Features
+
+- add waveform templates (#369)
+
+### Fixes
+
+- Parsing programs with integers that overflow a u64 will no longer panic; instead, they will raise an error. (#372)
+
+## 0.3.1-rc.0
+
+### Features
+
+- add waveform templates (#369)
+
+## 0.3.0
+
+### Breaking Changes
+
+- reduce number of classical instruction edges in InstructionBlock::graph
+
+## 0.3.0-rc.0
+
+### Breaking Changes
+
+- reduce number of classical instruction edges in InstructionBlock::graph
+
+## 0.2.1
+
+### Features
+
+- Support constructing ControlFlowGraph and BasicBlocks. (#359)
+
+## 0.2.1-rc.0
+
+### Features
+
+- Support constructing ControlFlowGraph and BasicBlocks. (#359)
+
+## 0.2.0
+
+### Breaking Changes
+
+- Program instruction iteration and serialization is deterministic. (#355)
+
+### Fixes
+
+- Program equality is sensitive to the order of calibration instructions. (#357)
+
+## 0.2.0-rc.1
+
+### Breaking Changes
+
+- Program instruction iteration and serialization is deterministic. (#355)
+
+### Fixes
+
+- Program equality is sensitive to the order of calibration instructions. (#357)
+
+## 0.1.1-rc.0
+
+### Fixes
+
+- Program equality is sensitive to the order of calibration instructions. (#357)
+
+## 0.1.0
+
+### Breaking Changes
+
+- CalibrationSet's and Program's will be considered equal if they contain the same set of calibrations, regardless of order. (#352)
+- #334: program scheduling and analysis utilities (#336)
+- Program now has a gate_definitions property that stores all DEFGATEs in a program. These instructions will no longer appear in body_instructions. (#306)
+- Support for Qubit and Target Placeholdres have been added. Converting programs and instructions to a string has been removed and replaced with a fallible to_quil() method. The `Label` struct has been repurposed to support `Label` instructions specifically. The `Target` enum has been added to express `@targets` as part of an instruction. (#266)
+- Decouple expression hashing and equality (#277)
+- allow overriding Instruction getters (#260)
+- This release is identical to 0.18.0. An error in our CI caused a continuity error with our published releases. (#254)
+- When adding two Programs, the resulting Program will have a correct used qubit cache. (#249)
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+- Release quil-py
+- introduce ExecutionDependency::Scheduled (#186)
+- empty commit so knope calculates current version
+- empty commit to force version bump
+- genericize parsing errors and remove error Strings
+- fix all compilation errors from error refactor
+
+### Features
+
+- Add CLI for interacting with quil-rs (#348)
+- Add methods for identifying Quil-T instructions and filtering instructions from `Program`s (#323)
+- Add `Program.wrap_in_loop()` method (#321)
+- Add methods for identifying Quil-T instructions and filtering instructions from Programs
+- Make in-place addition of Program more efficient (#290)
+- Add get_qubits method to Instruction
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+- RESET frame computation
+- Program.into_simplified
+- Support Expression arithmetic operations (#126)
+- support INCLUDE
+- support CONVERT
+- support NOP
+- impl FromStr for MemoryReference
+- update program to use btreemap for deterministic ordering
+
+### Fixes
+
+- Revert "match exactly one qubit for DELAYs without frame specifier" (#342)
+- include separators between DEFCIRCUIT parameters (#338)
+- `is_quil_t()` now correctly returns false for WAIT instructions (#331)
+- The `wrap_in_loop` method now applies the end target to the program (#329)
+- use internal QuotedString wrapper to quote Quil strings correctly (#317)
+- misc instruction memory accesses (#304)
+- match exactly one qubit for DELAYs without frame specifier (#300)
+- trigger release
+- calibration definitions don't contribute to Instrution::get_qubits
+- implement PartialOrd correctly for types implementing Ord (#295)
+- no percent symbol in variable qubit outputs
+- Implement not equal comparisons (#289)
+- Allow whitespace to delimit matrix specifications, better support parsing (#286)
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+- The parser now follows the correct precedence rules for ungrouped infix expressions (#207)
+- The imaginary part of a complex number will now always be formatted as a floating point number. (#205)
+- mark additional instructions as scheduled (#203)
+- parse SWAP-PHASES (#200)
+- allow for variable qubit in DEFCAL MEASURE
+- correctly expand delays (#142)
+- update snapshots
+- Waveforms w/o params need no parens
+- support escaped double quotes and backslashes in strings (#120)
+- make dynamic error Sync as well (#131)
+- fix performance regression (#113)
+- do not get line/column info for tokens except on error
+- require dynamic error to by Send (#108)
+- bump thiserror version and update import name (#103)
+- identifier parser (#100)
+- test cases with rstest
+- test cases should not violate the spec
+- remove a `dbg!` statement left over from #88
+- use structured error
+- update node version and dependencies for semantic-release (#84)
+- update semantic-release version as per dependabot suggestion (#83)
+- DEFCAL MEASURE serialization
+- test roundtrip of program->string->program
+- linting
+- Instruction used/blocked frames calculation (#74)
+- cargo fmt & passing tests
+- PRAGMA instruction `Display` impl (#62)
+- change quilc submodule to use HTTPS
+- move cargo update inline with semantic-release prepare cmd
+- lex keywords from identifiers (#47)
+- DEFWAVEFORM and waveform name parsing (#40)
+- remove unused imports
+- `Program::from_str` and `Expression::from_str` will no longer panic on bad input. (#37)
+- Allow indented comments when parsing. (#24)
+- Unbox calibrations and waveform invocations
+- parse and print real values as double precision
+- support Windows line separators \r\n
+- make program::graph public (#4)
+
+## 0.1.0-rc.0
+
+### Breaking Changes
+
+- CalibrationSet's and Program's will be considered equal if they contain the same set of calibrations, regardless of order. (#352)
+- #334: program scheduling and analysis utilities (#336)
+- Program now has a gate_definitions property that stores all DEFGATEs in a program. These instructions will no longer appear in body_instructions. (#306)
+- Support for Qubit and Target Placeholdres have been added. Converting programs and instructions to a string has been removed and replaced with a fallible to_quil() method. The `Label` struct has been repurposed to support `Label` instructions specifically. The `Target` enum has been added to express `@targets` as part of an instruction. (#266)
+- Decouple expression hashing and equality (#277)
+- allow overriding Instruction getters (#260)
+- This release is identical to 0.18.0. An error in our CI caused a continuity error with our published releases. (#254)
+- When adding two Programs, the resulting Program will have a correct used qubit cache. (#249)
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+- Release quil-py
+- introduce ExecutionDependency::Scheduled (#186)
+- empty commit so knope calculates current version
+- empty commit to force version bump
+- genericize parsing errors and remove error Strings
+- fix all compilation errors from error refactor
+
+### Features
+
+- Add CLI for interacting with quil-rs (#348)
+- Add methods for identifying Quil-T instructions and filtering instructions from `Program`s (#323)
+- Add `Program.wrap_in_loop()` method (#321)
+- Add methods for identifying Quil-T instructions and filtering instructions from Programs
+- Make in-place addition of Program more efficient (#290)
+- Add get_qubits method to Instruction
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+- RESET frame computation
+- Program.into_simplified
+- Support Expression arithmetic operations (#126)
+- support INCLUDE
+- support CONVERT
+- support NOP
+- impl FromStr for MemoryReference
+- update program to use btreemap for deterministic ordering
+
+### Fixes
+
+- Revert "match exactly one qubit for DELAYs without frame specifier" (#342)
+- include separators between DEFCIRCUIT parameters (#338)
+- `is_quil_t()` now correctly returns false for WAIT instructions (#331)
+- The `wrap_in_loop` method now applies the end target to the program (#329)
+- use internal QuotedString wrapper to quote Quil strings correctly (#317)
+- misc instruction memory accesses (#304)
+- match exactly one qubit for DELAYs without frame specifier (#300)
+- trigger release
+- calibration definitions don't contribute to Instrution::get_qubits
+- implement PartialOrd correctly for types implementing Ord (#295)
+- no percent symbol in variable qubit outputs
+- Implement not equal comparisons (#289)
+- Allow whitespace to delimit matrix specifications, better support parsing (#286)
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+- The parser now follows the correct precedence rules for ungrouped infix expressions (#207)
+- The imaginary part of a complex number will now always be formatted as a floating point number. (#205)
+- mark additional instructions as scheduled (#203)
+- parse SWAP-PHASES (#200)
+- allow for variable qubit in DEFCAL MEASURE
+- correctly expand delays (#142)
+- update snapshots
+- Waveforms w/o params need no parens
+- support escaped double quotes and backslashes in strings (#120)
+- make dynamic error Sync as well (#131)
+- fix performance regression (#113)
+- do not get line/column info for tokens except on error
+- require dynamic error to by Send (#108)
+- bump thiserror version and update import name (#103)
+- identifier parser (#100)
+- test cases with rstest
+- test cases should not violate the spec
+- remove a `dbg!` statement left over from #88
+- use structured error
+- update node version and dependencies for semantic-release (#84)
+- update semantic-release version as per dependabot suggestion (#83)
+- DEFCAL MEASURE serialization
+- test roundtrip of program->string->program
+- linting
+- Instruction used/blocked frames calculation (#74)
+- cargo fmt & passing tests
+- PRAGMA instruction `Display` impl (#62)
+- change quilc submodule to use HTTPS
+- move cargo update inline with semantic-release prepare cmd
+- lex keywords from identifiers (#47)
+- DEFWAVEFORM and waveform name parsing (#40)
+- remove unused imports
+- `Program::from_str` and `Expression::from_str` will no longer panic on bad input. (#37)
+- Allow indented comments when parsing. (#24)
+- Unbox calibrations and waveform invocations
+- parse and print real values as double precision
+- support Windows line separators \r\n
+- make program::graph public (#4)
+
+## 0.2.0-rc.0
+
+### Breaking Changes
+
+- #334: program scheduling and analysis utilities (#336)
+- Program now has a gate_definitions property that stores all DEFGATEs in a program. These instructions will no longer appear in body_instructions. (#306)
+- Support for Qubit and Target Placeholdres have been added. Converting programs and instructions to a string has been removed and replaced with a fallible to_quil() method. The `Label` struct has been repurposed to support `Label` instructions specifically. The `Target` enum has been added to express `@targets` as part of an instruction. (#266)
+- Decouple expression hashing and equality (#277)
+- allow overriding Instruction getters (#260)
+- This release is identical to 0.18.0. An error in our CI caused a continuity error with our published releases. (#254)
+- When adding two Programs, the resulting Program will have a correct used qubit cache. (#249)
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+- Release quil-py
+- introduce ExecutionDependency::Scheduled (#186)
+- empty commit so knope calculates current version
+- empty commit to force version bump
+- genericize parsing errors and remove error Strings
+- fix all compilation errors from error refactor
+
+### Features
+
+- Add CLI for interacting with quil-rs (#348)
+- Add methods for identifying Quil-T instructions and filtering instructions from `Program`s (#323)
+- Add `Program.wrap_in_loop()` method (#321)
+- Add methods for identifying Quil-T instructions and filtering instructions from Programs
+- Make in-place addition of Program more efficient (#290)
+- Add get_qubits method to Instruction
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+- RESET frame computation
+- Program.into_simplified
+- Support Expression arithmetic operations (#126)
+- support INCLUDE
+- support CONVERT
+- support NOP
+- impl FromStr for MemoryReference
+- update program to use btreemap for deterministic ordering
+
+### Fixes
+
+- Revert "match exactly one qubit for DELAYs without frame specifier" (#342)
+- include separators between DEFCIRCUIT parameters (#338)
+- `is_quil_t()` now correctly returns false for WAIT instructions (#331)
+- The `wrap_in_loop` method now applies the end target to the program (#329)
+- use internal QuotedString wrapper to quote Quil strings correctly (#317)
+- misc instruction memory accesses (#304)
+- match exactly one qubit for DELAYs without frame specifier (#300)
+- trigger release
+- calibration definitions don't contribute to Instrution::get_qubits
+- implement PartialOrd correctly for types implementing Ord (#295)
+- no percent symbol in variable qubit outputs
+- Implement not equal comparisons (#289)
+- Allow whitespace to delimit matrix specifications, better support parsing (#286)
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+- The parser now follows the correct precedence rules for ungrouped infix expressions (#207)
+- The imaginary part of a complex number will now always be formatted as a floating point number. (#205)
+- mark additional instructions as scheduled (#203)
+- parse SWAP-PHASES (#200)
+- allow for variable qubit in DEFCAL MEASURE
+- correctly expand delays (#142)
+- update snapshots
+- Waveforms w/o params need no parens
+- support escaped double quotes and backslashes in strings (#120)
+- make dynamic error Sync as well (#131)
+- fix performance regression (#113)
+- do not get line/column info for tokens except on error
+- require dynamic error to by Send (#108)
+- bump thiserror version and update import name (#103)
+- identifier parser (#100)
+- test cases with rstest
+- test cases should not violate the spec
+- remove a `dbg!` statement left over from #88
+- use structured error
+- update node version and dependencies for semantic-release (#84)
+- update semantic-release version as per dependabot suggestion (#83)
+- DEFCAL MEASURE serialization
+- test roundtrip of program->string->program
+- linting
+- Instruction used/blocked frames calculation (#74)
+- cargo fmt & passing tests
+- PRAGMA instruction `Display` impl (#62)
+- change quilc submodule to use HTTPS
+- move cargo update inline with semantic-release prepare cmd
+- lex keywords from identifiers (#47)
+- DEFWAVEFORM and waveform name parsing (#40)
+- remove unused imports
+- `Program::from_str` and `Expression::from_str` will no longer panic on bad input. (#37)
+- Allow indented comments when parsing. (#24)
+- Unbox calibrations and waveform invocations
+- parse and print real values as double precision
+- support Windows line separators \r\n
+- make program::graph public (#4)
diff --git a/quil-cli/Cargo.toml b/quil-cli/Cargo.toml
new file mode 100644
index 00000000..a40dcbd0
--- /dev/null
+++ b/quil-cli/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "quil-cli"
+version = "0.3.1"
+edition = "2021"
+license = "Apache-2.0"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+quil-rs = { path = "../quil-rs", version = "0.26.1" }
+clap = {version = "4.5.4", features = ["derive"]}
+anyhow = "1.0.81"
diff --git a/quil-cli/src/main.rs b/quil-cli/src/main.rs
new file mode 100644
index 00000000..99273a19
--- /dev/null
+++ b/quil-cli/src/main.rs
@@ -0,0 +1,60 @@
+use anyhow::Context;
+use clap::{Parser, Subcommand, ValueEnum};
+use quil_rs::{expression::Expression, quil::Quil, Program};
+use std::str::FromStr;
+
+#[derive(Parser, Debug)]
+struct Cli {
+ #[clap(subcommand)]
+ command: Command,
+}
+
+#[derive(Subcommand, Clone, Debug)]
+pub enum Command {
+ /// Parse a Quil program or expression
+ Parse {
+ #[arg(short = 't', long = "type", value_enum, default_value_t)]
+ input_type: InputType,
+ input: String,
+ },
+}
+
+#[derive(ValueEnum, Clone, Debug, Default)]
+pub enum InputType {
+ /// Parse a Quil program (default)
+ #[default]
+ Program,
+ /// Parse a Quil expression
+ Expression,
+}
+
+fn main() -> anyhow::Result<()> {
+ let cli = Cli::parse();
+
+ match cli.command {
+ Command::Parse { input_type, input } => handle_parse(input_type, input)?,
+ };
+
+ Ok(())
+}
+
+fn handle_parse(input_type: InputType, input: String) -> anyhow::Result<()> {
+ let parsed = match input_type {
+ InputType::Program => {
+ Program::from_str(&input)
+ .context("Failed to parse program from input string.")?
+ .to_quil()
+ .context("Parsed Program from valid Quil string, but was unable to convert it back to valid Quil. This is probably a bug in the quil-rs parser.")?
+ }
+ InputType::Expression => {
+ Expression::from_str(&input)
+ .context("Failed to parse expression from input string.")?
+ .to_quil()
+ .context("Parsed Expression from valid Quil expression, but was unable to convert it back to valid Expression. This is probably a bug in the quil-rs parser.")?
+ }
+ };
+
+ println!("{parsed}");
+
+ Ok(())
+}
diff --git a/quil-py/.flake8 b/quil-py/.flake8
new file mode 100644
index 00000000..3f7422a3
--- /dev/null
+++ b/quil-py/.flake8
@@ -0,0 +1,7 @@
+[flake8]
+max-line-length = 120
+# E203, E302 ignored for black compatibility
+extend-ignore = E203, E302
+
+per-file-ignores =
+ **/__init__.pyi:F401,F403 # Disable "unused" warning for top-level exports
diff --git a/quil-py/.stubtest-allowlist b/quil-py/.stubtest-allowlist
new file mode 100644
index 00000000..5c8526d9
--- /dev/null
+++ b/quil-py/.stubtest-allowlist
@@ -0,0 +1 @@
+quil.quil
diff --git a/quil-py/CHANGELOG.md b/quil-py/CHANGELOG.md
new file mode 100644
index 00000000..b660a009
--- /dev/null
+++ b/quil-py/CHANGELOG.md
@@ -0,0 +1,804 @@
+## 0.10.1
+
+### Features
+
+- add waveform templates (#369)
+
+### Fixes
+
+- Parsing programs with integers that overflow a u64 will no longer panic; instead, they will raise an error. (#372)
+
+## 0.10.1-rc.1
+
+### Features
+
+- add waveform templates (#369)
+
+### Fixes
+
+- Parsing programs with integers that overflow a u64 will no longer panic; instead, they will raise an error. (#372)
+
+## 0.10.1-rc.0
+
+### Features
+
+- add waveform templates (#369)
+
+## 0.10.0
+
+### Breaking Changes
+
+- reduce number of classical instruction edges in InstructionBlock::graph
+
+## 0.10.0-rc.0
+
+### Breaking Changes
+
+- reduce number of classical instruction edges in InstructionBlock::graph
+
+## 0.9.1
+
+### Features
+
+- Support constructing ControlFlowGraph and BasicBlocks. (#359)
+
+## 0.9.1-rc.0
+
+### Features
+
+- Support constructing ControlFlowGraph and BasicBlocks. (#359)
+
+## 0.9.0
+
+### Breaking Changes
+
+- Program instruction iteration and serialization is deterministic. (#355)
+
+### Fixes
+
+- Program equality is sensitive to the order of calibration instructions. (#357)
+
+## 0.9.0-rc.0
+
+### Breaking Changes
+
+- Program instruction iteration and serialization is deterministic. (#355)
+
+### Fixes
+
+- Program equality is sensitive to the order of calibration instructions. (#357)
+
+## 0.8.1-rc.0
+
+### Fixes
+
+- Program equality is sensitive to the order of calibration instructions. (#357)
+
+## 0.8.0
+
+### Breaking Changes
+
+- CalibrationSet's and Program's will be considered equal if they contain the same set of calibrations, regardless of order. (#352)
+
+## 0.8.0-rc.0
+
+### Breaking Changes
+
+- CalibrationSet's and Program's will be considered equal if they contain the same set of calibrations, regardless of order. (#352)
+
+## 0.7.1
+
+### Features
+
+- linux ppc64le wheel
+
+## 0.7.1-rc.0
+
+### Features
+
+- linux ppc64le wheel
+
+## 0.7.0
+
+### Breaking Changes
+
+- #334: program scheduling and analysis utilities (#336)
+
+### Fixes
+
+- Revert "match exactly one qubit for DELAYs without frame specifier" (#342)
+
+## 0.7.0-rc.1
+
+### Breaking Changes
+
+- #334: program scheduling and analysis utilities (#336)
+
+### Fixes
+
+- Revert "match exactly one qubit for DELAYs without frame specifier" (#342)
+
+## 0.7.0-rc.0
+
+### Breaking Changes
+
+- #334: program scheduling and analysis utilities (#336)
+
+## 0.6.6
+
+### Fixes
+
+- include separators between DEFCIRCUIT parameters (#338)
+
+## 0.6.6-rc.0
+
+### Fixes
+
+- include separators between DEFCIRCUIT parameters (#338)
+
+## 0.6.5
+
+### Fixes
+
+- `is_quil_t()` now correctly returns false for WAIT instructions (#331)
+
+## 0.6.5-rc.0
+
+### Fixes
+
+- `is_quil_t()` now correctly returns false for WAIT instructions (#331)
+
+## 0.6.4
+
+### Fixes
+
+- The `wrap_in_loop` method now applies the end target to the program (#329)
+
+## 0.6.4-rc.0
+
+### Fixes
+
+- The `wrap_in_loop` method now applies the end target to the program (#329)
+
+## 0.6.3
+
+### Features
+
+- Add methods for identifying Quil-T instructions and filtering instructions from `Program`s (#323)
+- Add `Program.wrap_in_loop()` method (#321)
+- Add methods for identifying Quil-T instructions and filtering instructions from Programs
+
+## 0.6.3-rc.1
+
+### Features
+
+- Add methods for identifying Quil-T instructions and filtering instructions from `Program`s (#323)
+- Add `Program.wrap_in_loop()` method (#321)
+- Add methods for identifying Quil-T instructions and filtering instructions from Programs
+
+## 0.6.3-rc.0
+
+### Features
+
+- Add `Program.wrap_in_loop()` method (#321)
+- Add methods for identifying Quil-T instructions and filtering instructions from Programs
+
+## 0.6.2
+
+### Fixes
+
+- use internal QuotedString wrapper to quote Quil strings correctly (#317)
+
+## 0.6.2-rc.0
+
+### Fixes
+
+- use internal QuotedString wrapper to quote Quil strings correctly (#317)
+
+## 0.6.1
+
+### Features
+
+- Support Python 3.12 (#310)
+
+### Fixes
+
+- misc instruction memory accesses (#304)
+
+## 0.6.1-rc.1
+
+### Features
+
+- Support Python 3.12 (#310)
+
+### Fixes
+
+- misc instruction memory accesses (#304)
+
+## 0.6.1-rc.0
+
+### Fixes
+
+- misc instruction memory accesses (#304)
+
+## 0.6.0
+
+### Breaking Changes
+
+- Program now has a gate_definitions property that stores all DEFGATEs in a program. These instructions will no longer appear in body_instructions. (#306)
+
+## 0.6.0-rc.0
+
+### Breaking Changes
+
+- Program now has a gate_definitions property that stores all DEFGATEs in a program. These instructions will no longer appear in body_instructions. (#306)
+
+## 0.5.8
+
+### Fixes
+
+- match exactly one qubit for DELAYs without frame specifier (#300)
+
+## 0.5.8-rc.0
+
+### Fixes
+
+- match exactly one qubit for DELAYs without frame specifier (#300)
+
+## 0.5.7
+
+### Fixes
+
+- trigger release
+
+## 0.5.7-rc.0
+
+### Fixes
+
+- trigger release
+
+## 0.5.6
+
+### Fixes
+
+- implement PartialOrd correctly for types implementing Ord (#295)
+- no percent symbol in variable qubit outputs
+
+## 0.5.6-rc.1
+
+### Fixes
+
+- implement PartialOrd correctly for types implementing Ord (#295)
+- no percent symbol in variable qubit outputs
+
+## 0.5.6-rc.0
+
+### Fixes
+
+- no percent symbol in variable qubit outputs
+
+## 0.5.5
+
+### Features
+
+- Make in-place addition of Program more efficient (#290)
+
+## 0.5.5-rc.0
+
+### Features
+
+- Make in-place addition of Program more efficient (#290)
+
+## 0.5.4
+
+### Fixes
+
+- Implement not equal comparisons (#289)
+
+## 0.5.4-rc.0
+
+### Fixes
+
+- Implement not equal comparisons (#289)
+
+## 0.5.3
+
+### Fixes
+
+- Allow whitespace to delimit matrix specifications, better support parsing (#286)
+
+## 0.5.3-rc.0
+
+### Fixes
+
+- Allow whitespace to delimit matrix specifications, better support parsing (#286)
+
+## 0.5.2
+
+### Features
+
+- Add get_qubits method to Instruction
+- Instruction classes now implement `__copy__`, and `__deepcopy__`, making them compatible with Python's `copy` module. (#283)
+
+## 0.5.2-rc.1
+
+### Features
+
+- Add get_qubits method to Instruction
+- Instruction classes now implement `__copy__`, and `__deepcopy__`, making them compatible with Python's `copy` module. (#283)
+
+## 0.5.2-rc.0
+
+### Features
+
+- Instruction classes now implement `__copy__`, and `__deepcopy__`, making them compatible with Python's `copy` module. (#283)
+
+## 0.5.1
+
+### Features
+
+- Build & publish wheels for Windows (#280)
+
+## 0.5.1-rc.1
+
+### Features
+
+- Build & publish wheels for Windows (#280)
+
+## 0.5.1-rc.0
+
+### Features
+
+- Build & publish wheels for Windows (#280)
+
+## 0.5.0
+
+### Breaking Changes
+
+- Support for Qubit and Target Placeholdres have been added. Converting programs and instructions to a string has been removed and replaced with a fallible to_quil() method. The `Label` struct has been repurposed to support `Label` instructions specifically. The `Target` enum has been added to express `@targets` as part of an instruction. (#266)
+- Decouple expression hashing and equality (#277)
+
+## 0.5.0-rc.1
+
+### Breaking Changes
+
+- Support for Qubit and Target Placeholdres have been added. Converting programs and instructions to a string has been removed and replaced with a fallible to_quil() method. The `Label` struct has been repurposed to support `Label` instructions specifically. The `Target` enum has been added to express `@targets` as part of an instruction. (#266)
+- Decouple expression hashing and equality (#277)
+
+## 0.5.0-rc.0
+
+### Breaking Changes
+
+- Decouple expression hashing and equality (#277)
+
+## 0.4.0
+
+### Breaking Changes
+
+- allow overriding Instruction getters (#260)
+
+### Features
+
+- Add setters for `Program` calibrations, waveforms, frames, and memory_regions (#264)
+
+## 0.4.0-rc.2
+
+### Breaking Changes
+
+- allow overriding Instruction getters (#260)
+
+### Features
+
+- Add setters for `Program` calibrations, waveforms, frames, and memory_regions (#264)
+
+## 0.4.0-rc.1
+
+### Breaking Changes
+
+- allow overriding Instruction getters (#260)
+
+### Features
+
+- Add setters for `Program` calibrations, waveforms, frames, and memory_regions (#264)
+
+## 0.4.0-rc.0
+
+### Breaking Changes
+
+- allow overriding Instruction getters (#260)
+
+## 0.3.0
+
+### Breaking Changes
+
+- This release is identical to 0.18.0. An error in our CI caused a continuity error with our published releases. (#254)
+
+## 0.3.0-rc.0
+
+### Breaking Changes
+
+- This release is identical to 0.18.0. An error in our CI caused a continuity error with our published releases. (#254)
+
+## 0.2.0
+
+### Breaking Changes
+
+- When adding two Programs, the resulting Program will have a correct used qubit cache. (#249)
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.3.0-rc.1
+
+### Breaking Changes
+
+- When adding two Programs, the resulting Program will have a correct used qubit cache. (#249)
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0
+
+### Breaking Changes
+
+- When adding two Programs, the resulting Program will have a correct used qubit cache. (#249)
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.3.0-rc.0
+
+### Breaking Changes
+
+- When adding two Programs, the resulting Program will have a correct used qubit cache. (#249)
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0
+
+### Breaking Changes
+
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.14
+
+### Breaking Changes
+
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.13
+
+### Breaking Changes
+
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.12
+
+### Breaking Changes
+
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Correct precedence rules are followed when matching measure calibrations. (#243)
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.11
+
+### Breaking Changes
+
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- Expand all analog control instructions (#238)
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.10
+
+### Breaking Changes
+
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.9
+
+### Breaking Changes
+
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.8
+
+### Breaking Changes
+
+- cache used qubits on Program (#234)
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.7
+
+### Breaking Changes
+
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- add clone_without_body_instructions to Program (#236)
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.6
+
+### Breaking Changes
+
+- Program::get_frames_for_instruction return type
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.5
+
+### Breaking Changes
+
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- build and return the unitary of a program (#213)
+- Most instruction types are now hashable.
+
+### Fixes
+
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.4
+
+### Breaking Changes
+
+- more optimizations (#233)
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- Most instruction types are now hashable.
+
+### Fixes
+
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.2.0-rc.3
+
+### Breaking Changes
+
+- optimize clones and collections (#228)
+- Expression parameter strings are now delimited by a comma. `get_expression_parameter_string` and `get_string_parameter_string` have been removed from the instruction module. (#214)
+
+### Features
+
+- Most instruction types are now hashable.
+
+### Fixes
+
+- documentation typo
+- The destination and source are no longer flipped when parsing CONVERT instructions. (#226)
+- BinaryLogic now has it's own to string implementation (#222)
+
+## 0.1.0
+
+This first release of the `quil` package exposes a Python API for most of the `quil-rs` package. This includes a parser, as well as types for instructions, programs, and expressions.
diff --git a/quil-py/Cargo.toml b/quil-py/Cargo.toml
new file mode 100644
index 00000000..c080034e
--- /dev/null
+++ b/quil-py/Cargo.toml
@@ -0,0 +1,34 @@
+[package]
+name = "quil-py"
+description = "Python bindings for quil-rs"
+version = "0.10.1"
+edition = "2021"
+license = "Apache-2.0"
+repository = "https://github.com/rigetti/quil-rs"
+keywords = ["pyquil", "SDK", "Rigetti", "Quil", "Quantum"]
+categories = ["api-bindings", "parsers", "science", "emulators"]
+readme = "./README.md"
+
+[lib]
+# The name of the native library. This is the name which will be used in Python to import the
+# library (i.e. `import quil`). If you change this, you must also change the name of the
+# `#[pymodule]` in `src/lib.rs`.
+name = "quil"
+# "cdylib" is necessary to produce a shared library for Python to import from.
+#
+# Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able
+# to `use quil;` unless the "lib" and "rlib" crate type is also included:
+crate-type = ["cdylib", "rlib"]
+
+[dependencies]
+ndarray.workspace = true
+quil-rs = { path = "../quil-rs", version = "0.26.1" }
+strum.workspace = true
+# pyo3 dependencies should be updated together
+numpy = "0.20.0"
+pyo3 = { version = "0.20.3", features = ["indexmap"] }
+rigetti-pyo3 = {version = "0.3.4", features = ["indexmap"]}
+indexmap.workspace = true
+
+[build-dependencies]
+pyo3-build-config = "0.20.0"
diff --git a/quil-py/Makefile.toml b/quil-py/Makefile.toml
new file mode 100644
index 00000000..a3727ac5
--- /dev/null
+++ b/quil-py/Makefile.toml
@@ -0,0 +1,65 @@
+[env]
+RUST_BACKTRACE = 0
+
+[tasks.poetry-install]
+command = "poetry"
+args = ["install"]
+
+[tasks.install-quil]
+command = "poetry"
+args = ["run", "maturin", "develop"]
+
+[tasks.stubtest]
+dependencies = ["poetry-install"]
+command = "poetry"
+args = ["run", "stubtest", "--allowlist", ".stubtest-allowlist", "quil"]
+
+[tasks.stubtest-flow]
+dependencies = [
+ "poetry-install",
+ "install-quil",
+ "stubtest",
+]
+
+[tasks.format]
+dependencies = ["poetry-install"]
+command = "poetry"
+args = ["run", "ruff", "format"]
+
+[tasks.check-format]
+dependencies = ["poetry-install"]
+command = "poetry"
+args = ["run", "ruff", "format", "--check"]
+
+[tasks.lint]
+dependencies = ["poetry-install"]
+command = "poetry"
+args = ["run", "ruff", "check"]
+
+[tasks.pytest]
+command = "poetry"
+args = ["run", "pytest"]
+
+[tasks.pytest-flow]
+dependencies = [
+ "poetry-install",
+ "install-quil",
+ "pytest",
+]
+
+[tasks.docs]
+dependencies = ["poetry-install", "install-quil"]
+command = "poetry"
+args = ["run", "pdoc", "-o", "build/docs", "quil", "!quil.quil", "--logo", "https://qcs.rigetti.com/static/img/rigetti-logo.svg"]
+
+[tasks.dev-flow]
+dependencies = [
+ "dev-test-flow",
+ "pytest-flow",
+ "stubtest",
+ "lint",
+ "check-format"
+]
+
+[tasks.default]
+alias = "dev-flow"
diff --git a/quil-py/README-py.md b/quil-py/README-py.md
new file mode 100644
index 00000000..b51f462a
--- /dev/null
+++ b/quil-py/README-py.md
@@ -0,0 +1,11 @@
+# Quil
+
+⚠️ In Development
+
+The `quil` package provides tools for constructing, manipulating, parsing, and printing [Quil](https://github.com/quil-lang/quil) programs. Internally, it is powered by [quil-rs](https://github.com/rigetti/quil-rs).
+
+This package is still in early development and breaking changes should be expected between minor versions.
+
+# Documentation
+
+Documentation for the current release of `quil` is published [here](https://rigetti.github.io/quil-rs/quil.html). Every version of `quil` ships [with type stubs](https://github.com/rigetti/quil-rs/tree/main/quil-py/quil) that provide type hints and documentation to Python tooling and editors that support the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) or similar.
diff --git a/quil-py/README.md b/quil-py/README.md
new file mode 100644
index 00000000..2f1c6630
--- /dev/null
+++ b/quil-py/README.md
@@ -0,0 +1,7 @@
+# quil-py
+
+⚠️ In Development
+
+This crate exposes [`pyo3`](https://github.com/PyO3/pyo3) bindings for [`quil-rs`](https://github.com/rigetti/quil-rs) allowing them to be extended or used in other `pyo3` based Python packages.
+
+This package is still in early development and breaking changes should be expected between minor versions.
diff --git a/quil-py/build.rs b/quil-py/build.rs
new file mode 100644
index 00000000..dace4a9b
--- /dev/null
+++ b/quil-py/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+ pyo3_build_config::add_extension_module_link_args();
+}
diff --git a/quil-py/make_docs.py b/quil-py/make_docs.py
new file mode 100644
index 00000000..4c157d1a
--- /dev/null
+++ b/quil-py/make_docs.py
@@ -0,0 +1,14 @@
+import sys
+from pathlib import Path
+
+import pdoc
+
+import quil # noqa - we need to import quil for it to appear in sys.modules
+
+if __name__ == "__main__":
+ print(dir(sys.modules["quil"]))
+ print(dir(sys.modules["quil.validation"]))
+ print([k for k in sys.modules.keys() if "quil" in k])
+ del sys.modules["quil.validation"]
+
+ pdoc.pdoc("quil", "!quil.quil", output_directory=Path("docs"))
diff --git a/quil-py/out/index.html b/quil-py/out/index.html
new file mode 100644
index 00000000..967079b4
--- /dev/null
+++ b/quil-py/out/index.html
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/quil-py/out/quil.html b/quil-py/out/quil.html
new file mode 100644
index 00000000..7ba583d2
--- /dev/null
+++ b/quil-py/out/quil.html
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+ quil API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quil-py/out/quil/quil.html b/quil-py/out/quil/quil.html
new file mode 100644
index 00000000..93ef2bec
--- /dev/null
+++ b/quil-py/out/quil/quil.html
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+ quil.quil API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quil-py/out/search.js b/quil-py/out/search.js
new file mode 100644
index 00000000..9575c96b
--- /dev/null
+++ b/quil-py/out/search.js
@@ -0,0 +1,46 @@
+window.pdocSearch = (function(){
+/** elasticlunr - http://weixsong.github.io * Copyright (C) 2017 Oliver Nightingale * Copyright (C) 2017 Wei Song * MIT Licensed */!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o
\n"}, "quil.quil": {"fullname": "quil.quil", "modulename": "quil.quil", "kind": "module", "doc": "
\n"}}, "docInfo": {"quil": {"qualname": 0, "fullname": 1, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "quil.quil": {"qualname": 0, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}}, "length": 2, "save": true}, "index": {"qualname": {"root": {"docs": {}, "df": 0}}, "fullname": {"root": {"docs": {}, "df": 0, "q": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {"quil": {"tf": 1}, "quil.quil": {"tf": 1.4142135623730951}}, "df": 2}}}}}}, "annotation": {"root": {"docs": {}, "df": 0}}, "default_value": {"root": {"docs": {}, "df": 0}}, "signature": {"root": {"docs": {}, "df": 0}}, "bases": {"root": {"docs": {}, "df": 0}}, "doc": {"root": {"docs": {"quil": {"tf": 1.7320508075688772}, "quil.quil": {"tf": 1.7320508075688772}}, "df": 2}}}, "pipeline": ["trimmer"], "_isPrebuiltIndex": true};
+
+ // mirrored in build-search-index.js (part 1)
+ // Also split on html tags. this is a cheap heuristic, but good enough.
+ elasticlunr.tokenizer.setSeperator(/[\s\-.;&_'"=,()]+|<[^>]*>/);
+
+ let searchIndex;
+ if (docs._isPrebuiltIndex) {
+ console.info("using precompiled search index");
+ searchIndex = elasticlunr.Index.load(docs);
+ } else {
+ console.time("building search index");
+ // mirrored in build-search-index.js (part 2)
+ searchIndex = elasticlunr(function () {
+ this.pipeline.remove(elasticlunr.stemmer);
+ this.pipeline.remove(elasticlunr.stopWordFilter);
+ this.addField("qualname");
+ this.addField("fullname");
+ this.addField("annotation");
+ this.addField("default_value");
+ this.addField("signature");
+ this.addField("bases");
+ this.addField("doc");
+ this.setRef("fullname");
+ });
+ for (let doc of docs) {
+ searchIndex.addDoc(doc);
+ }
+ console.timeEnd("building search index");
+ }
+
+ return (term) => searchIndex.search(term, {
+ fields: {
+ qualname: {boost: 4},
+ fullname: {boost: 2},
+ annotation: {boost: 2},
+ default_value: {boost: 2},
+ signature: {boost: 2},
+ bases: {boost: 2},
+ doc: {boost: 1},
+ },
+ expand: true
+ });
+})();
\ No newline at end of file
diff --git a/quil-py/poetry.lock b/quil-py/poetry.lock
new file mode 100644
index 00000000..dd8c2607
--- /dev/null
+++ b/quil-py/poetry.lock
@@ -0,0 +1,465 @@
+# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
+
+[[package]]
+name = "astunparse"
+version = "1.6.3"
+description = "An AST unparser for Python"
+optional = false
+python-versions = "*"
+files = [
+ {file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"},
+ {file = "astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"},
+]
+
+[package.dependencies]
+six = ">=1.6.1,<2.0"
+wheel = ">=0.23.0,<1.0"
+
+[[package]]
+name = "attrs"
+version = "22.2.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
+ {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
+]
+
+[package.extras]
+cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
+dev = ["attrs[docs,tests]"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
+tests = ["attrs[tests-no-zope]", "zope.interface"]
+tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "colored"
+version = "1.4.4"
+description = "Simple library for color and formatting to terminal"
+optional = false
+python-versions = "*"
+files = [
+ {file = "colored-1.4.4.tar.gz", hash = "sha256:04ff4d4dd514274fe3b99a21bb52fb96f2688c01e93fba7bef37221e7cb56ce0"},
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.1.1"
+description = "Backport of PEP 654 (exception groups)"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
+ {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"},
+]
+
+[package.extras]
+test = ["pytest (>=6)"]
+
+[[package]]
+name = "iniconfig"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
+ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.2"
+description = "A very fast and expressive template engine."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
+ {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
+[[package]]
+name = "markupsafe"
+version = "2.1.3"
+description = "Safely add untrusted strings to HTML/XML markup."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
+ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
+]
+
+[[package]]
+name = "maturin"
+version = "1.2.3"
+description = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "maturin-1.2.3-py3-none-linux_armv6l.whl", hash = "sha256:7b6484d7c94d6d6188ccf4ed8a6167cb8f1e98f13c653bfa715c9ee9eac4be0c"},
+ {file = "maturin-1.2.3-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:b44fb4d1d116d69ce7c713c22b322debd5fc222db09eb1cdfa0e1c1b7f3e2e9c"},
+ {file = "maturin-1.2.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:735375559c8c75bdc910c377f6dcc9197637ee2a312a60e361ef0e08fb31fcb5"},
+ {file = "maturin-1.2.3-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:619f4f7b7e3a842a4f6cbae1d138a71d67aeba460f6217b38f2150ad53bb4dc1"},
+ {file = "maturin-1.2.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:4e1035c102f87aa3e6733d28c2248b7303afa11f93a21f2ac88636e0430b0258"},
+ {file = "maturin-1.2.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:aef8ddb9e775dd3781e6f56e10cc3d26f648735723ab5c47ce938542b9b5bbb6"},
+ {file = "maturin-1.2.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:23c6fdc5750b96fd10d28c125dd795e9b75cd5cd768c8a403dc91dfde641243a"},
+ {file = "maturin-1.2.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:40b4d69f9e5be5eacedd80ae496fae67cfd71d386b5604f7ce2e9ac9d34d0460"},
+ {file = "maturin-1.2.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:826e90533789ff6dd3f3f0541fbe46c3549ec985d19edceff7913f9bdf9c3131"},
+ {file = "maturin-1.2.3-py3-none-win32.whl", hash = "sha256:e414e56896d904c255e80190ac81fa8299b1d7df52f7e2e3f10df33f92784fd8"},
+ {file = "maturin-1.2.3-py3-none-win_amd64.whl", hash = "sha256:1f5516dbe68491bf4bf7e047caf139596a3cd9d4a5ec8bb43034980e3710e550"},
+ {file = "maturin-1.2.3-py3-none-win_arm64.whl", hash = "sha256:7d47e9a0fe56d25de98a2bed7d1c75975516e3a25fa5b552b2ee61fb1add41c0"},
+ {file = "maturin-1.2.3.tar.gz", hash = "sha256:ef3f42af453d64f233b99543c3001bee645019a9c2022c7972210a9cacb5301f"},
+]
+
+[package.dependencies]
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+
+[package.extras]
+patchelf = ["patchelf"]
+zig = ["ziglang (>=0.10.0,<0.11.0)"]
+
+[[package]]
+name = "mypy"
+version = "1.1.1"
+description = "Optional static typing for Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "mypy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39c7119335be05630611ee798cc982623b9e8f0cff04a0b48dfc26100e0b97af"},
+ {file = "mypy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61bf08362e93b6b12fad3eab68c4ea903a077b87c90ac06c11e3d7a09b56b9c1"},
+ {file = "mypy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb19c9f662e41e474e0cff502b7064a7edc6764f5262b6cd91d698163196799"},
+ {file = "mypy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:315ac73cc1cce4771c27d426b7ea558fb4e2836f89cb0296cbe056894e3a1f78"},
+ {file = "mypy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5cb14ff9919b7df3538590fc4d4c49a0f84392237cbf5f7a816b4161c061829e"},
+ {file = "mypy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26cdd6a22b9b40b2fd71881a8a4f34b4d7914c679f154f43385ca878a8297389"},
+ {file = "mypy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b5f81b40d94c785f288948c16e1f2da37203c6006546c5d947aab6f90aefef2"},
+ {file = "mypy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b437be1c02712a605591e1ed1d858aba681757a1e55fe678a15c2244cd68a5"},
+ {file = "mypy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d809f88734f44a0d44959d795b1e6f64b2bbe0ea4d9cc4776aa588bb4229fc1c"},
+ {file = "mypy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:a380c041db500e1410bb5b16b3c1c35e61e773a5c3517926b81dfdab7582be54"},
+ {file = "mypy-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b7c7b708fe9a871a96626d61912e3f4ddd365bf7f39128362bc50cbd74a634d5"},
+ {file = "mypy-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c10fa12df1232c936830839e2e935d090fc9ee315744ac33b8a32216b93707"},
+ {file = "mypy-1.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0a28a76785bf57655a8ea5eb0540a15b0e781c807b5aa798bd463779988fa1d5"},
+ {file = "mypy-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ef6a01e563ec6a4940784c574d33f6ac1943864634517984471642908b30b6f7"},
+ {file = "mypy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d64c28e03ce40d5303450f547e07418c64c241669ab20610f273c9e6290b4b0b"},
+ {file = "mypy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64cc3afb3e9e71a79d06e3ed24bb508a6d66f782aff7e56f628bf35ba2e0ba51"},
+ {file = "mypy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce61663faf7a8e5ec6f456857bfbcec2901fbdb3ad958b778403f63b9e606a1b"},
+ {file = "mypy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b0c373d071593deefbcdd87ec8db91ea13bd8f1328d44947e88beae21e8d5e9"},
+ {file = "mypy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2888ce4fe5aae5a673386fa232473014056967f3904f5abfcf6367b5af1f612a"},
+ {file = "mypy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:19ba15f9627a5723e522d007fe708007bae52b93faab00f95d72f03e1afa9598"},
+ {file = "mypy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:59bbd71e5c58eed2e992ce6523180e03c221dcd92b52f0e792f291d67b15a71c"},
+ {file = "mypy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9401e33814cec6aec8c03a9548e9385e0e228fc1b8b0a37b9ea21038e64cdd8a"},
+ {file = "mypy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b398d8b1f4fba0e3c6463e02f8ad3346f71956b92287af22c9b12c3ec965a9f"},
+ {file = "mypy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:69b35d1dcb5707382810765ed34da9db47e7f95b3528334a3c999b0c90fe523f"},
+ {file = "mypy-1.1.1-py3-none-any.whl", hash = "sha256:4e4e8b362cdf99ba00c2b218036002bdcdf1e0de085cdb296a49df03fb31dfc4"},
+ {file = "mypy-1.1.1.tar.gz", hash = "sha256:ae9ceae0f5b9059f33dbc62dea087e942c0ccab4b7a003719cb70f9b8abfa32f"},
+]
+
+[package.dependencies]
+mypy-extensions = ">=1.0.0"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = ">=3.10"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+install-types = ["pip"]
+python2 = ["typed-ast (>=1.4.0,<2)"]
+reports = ["lxml"]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.0.0"
+description = "Type system extensions for programs checked with the mypy type checker."
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
+ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
+]
+
+[[package]]
+name = "numpy"
+version = "1.24.3"
+description = "Fundamental package for array computing in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"},
+ {file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"},
+ {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"},
+ {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"},
+ {file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"},
+ {file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"},
+ {file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"},
+ {file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"},
+ {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"},
+ {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"},
+ {file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"},
+ {file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"},
+ {file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"},
+ {file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"},
+ {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"},
+ {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"},
+ {file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"},
+ {file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"},
+ {file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"},
+ {file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"},
+ {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"},
+ {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"},
+ {file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"},
+ {file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"},
+ {file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"},
+ {file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"},
+ {file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"},
+ {file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"},
+]
+
+[[package]]
+name = "packaging"
+version = "23.0"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
+ {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
+]
+
+[[package]]
+name = "pdoc"
+version = "14.1.0"
+description = "API Documentation for Python Projects"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pdoc-14.1.0-py3-none-any.whl", hash = "sha256:e8869dffe21296b3bd5545b28e7f07cae0656082aca43f8915323187e541b126"},
+ {file = "pdoc-14.1.0.tar.gz", hash = "sha256:3a0bd921a05c39a82b1505089eb6dc99d857b71b856aa60d1aca4d9086d0e18c"},
+]
+
+[package.dependencies]
+astunparse = {version = "*", markers = "python_version < \"3.9\""}
+Jinja2 = ">=2.11.0"
+MarkupSafe = "*"
+pygments = ">=2.12.0"
+
+[package.extras]
+dev = ["black", "hypothesis", "mypy", "pygments (>=2.14.0)", "pytest", "pytest-cov", "pytest-timeout", "ruff", "tox", "types-pygments"]
+
+[[package]]
+name = "pluggy"
+version = "1.0.0"
+description = "plugin and hook calling mechanisms for python"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
+ {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
+]
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "pygments"
+version = "2.16.1"
+description = "Pygments is a syntax highlighting package written in Python."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"},
+ {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"},
+]
+
+[package.extras]
+plugins = ["importlib-metadata"]
+
+[[package]]
+name = "pytest"
+version = "7.2.2"
+description = "pytest: simple powerful testing with Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"},
+ {file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"},
+]
+
+[package.dependencies]
+attrs = ">=19.2.0"
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=0.12,<2.0"
+tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
+
+[package.extras]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
+
+[[package]]
+name = "ruff"
+version = "0.3.7"
+description = "An extremely fast Python linter and code formatter, written in Rust."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"},
+ {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"},
+ {file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"},
+ {file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"},
+ {file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"},
+ {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"},
+ {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"},
+ {file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"},
+ {file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"},
+ {file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"},
+ {file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"},
+ {file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"},
+ {file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"},
+ {file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"},
+ {file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"},
+ {file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"},
+ {file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"},
+]
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+
+[[package]]
+name = "syrupy"
+version = "3.0.6"
+description = "Pytest Snapshot Test Utility"
+optional = false
+python-versions = ">=3.7,<4"
+files = [
+ {file = "syrupy-3.0.6-py3-none-any.whl", hash = "sha256:9c18e22264026b34239bcc87ab7cc8d893eb17236ea7dae634217ea4f22a848d"},
+ {file = "syrupy-3.0.6.tar.gz", hash = "sha256:583aa5ca691305c27902c3e29a1ce9da50ff9ab5f184c54b1dc124a16e4a6cf4"},
+]
+
+[package.dependencies]
+colored = ">=1.3.92,<2.0.0"
+pytest = ">=5.1.0,<8.0.0"
+
+[[package]]
+name = "tomli"
+version = "2.0.1"
+description = "A lil' TOML parser"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.5.0"
+description = "Backported and Experimental Type Hints for Python 3.7+"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"},
+ {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"},
+]
+
+[[package]]
+name = "wheel"
+version = "0.41.3"
+description = "A built-package format for Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "wheel-0.41.3-py3-none-any.whl", hash = "sha256:488609bc63a29322326e05560731bf7bfea8e48ad646e1f5e40d366607de0942"},
+ {file = "wheel-0.41.3.tar.gz", hash = "sha256:4d4987ce51a49370ea65c0bfd2234e8ce80a12780820d9dc462597a6e60d0841"},
+]
+
+[package.extras]
+test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
+
+[metadata]
+lock-version = "2.0"
+python-versions = "^3.8"
+content-hash = "c4cf08c102dd7ec09c483f00c9dbbabdca03917d1393809aafa65beab8253376"
diff --git a/quil-py/pyproject.toml b/quil-py/pyproject.toml
new file mode 100644
index 00000000..57e26fc4
--- /dev/null
+++ b/quil-py/pyproject.toml
@@ -0,0 +1,123 @@
+[project]
+name = "quil"
+requires-python = ">=3.8"
+description = "A Python package for building and parsing Quil programs."
+documentation = "https://rigetti.github.io/quil-rs/quil.html"
+readme = "README-py.md"
+license = { text = "Apache-2.0" }
+authors = [{ name = "Rigetti Computing", email = "softapps@rigetti.com" }]
+classifiers = [
+ "Development Status :: 3 - Alpha",
+ "License :: OSI Approved :: Apache Software License",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Operating System :: OS Independent",
+]
+
+# PEP 621 specifies the [project] table as the source for project metadata. However, Poetry only supports [tool.poetry]
+# We can remove this table once this issue is resolved: https://github.com/python-poetry/poetry/issues/3332
+[tool.poetry]
+name = "quil"
+version = "0.10.1"
+description = "A Python package for building and parsing Quil programs."
+readme = "README-py.md"
+authors = ["Rigetti Computing "]
+
+[tool.poetry.dependencies]
+python = "^3.8"
+numpy = "^1.21"
+
+[tool.poetry.group.dev.dependencies]
+ruff = "^0.3.7"
+maturin = "^1.2.3"
+mypy = "^1.1.1"
+pytest = "^7.2.2"
+pdoc = "^14.1.0"
+syrupy = "^3.0.6"
+
+[tool.maturin]
+features = ["pyo3/extension-module"]
+bindings = "pyo3"
+compatibility = "linux"
+sdist-include = ["README.md"]
+
+[build-system]
+requires = ["maturin>=1.0.0,<2.0.0"]
+build-backend = "maturin"
+
+[tool.ruff]
+exclude = [
+ ".bzr",
+ ".direnv",
+ ".eggs",
+ ".git",
+ ".git-rewrite",
+ ".hg",
+ ".ipynb_checkpoints",
+ ".mypy_cache",
+ ".nox",
+ ".pants.d",
+ ".pyenv",
+ ".pytest_cache",
+ ".pytype",
+ ".ruff_cache",
+ ".svn",
+ ".tox",
+ ".venv",
+ ".vscode",
+ "__pypackages__",
+ "_build",
+ "buck-out",
+ "build",
+ "dist",
+ "node_modules",
+ "site-packages",
+ "venv",
+]
+line-length = 120
+indent-width = 4
+target-version = "py38"
+
+[tool.ruff.lint]
+select = ["D", "E4", "E7", "E9", "F", "I", "B", "S", "W"]
+ignore = [
+ "E741" # "Ambiguous" variable names like "I" aren't ambiguous in this contex.
+]
+fixable = ["ALL"]
+unfixable = []
+# Allow unused variables when underscore-prefixed.
+dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
+
+[tool.ruff.lint.per-file-ignores]
+"quil/**/*.py" = [
+ "F403", # * imports allowed in extension module glue.
+ "D100", # docstrings belong in type stubs
+ "D104",
+]
+"test/**/*.py" = [
+ "D", # docstrings are not enforced in tests
+ "S101", # asserts are allowed in tests
+ "S301", # we need to test pickling
+]
+"make_docs.py" = [ "D" ]
+
+[tool.ruff.format]
+quote-style = "double"
+indent-style = "space"
+skip-magic-trailing-comma = false
+line-ending = "auto"
+
+[tool.ruff.lint.pydocstyle]
+convention = "google"
+
+[tool.pyright]
+# This diagnostic is raised when a type stub is found without a corresponding source file. This is
+# necessarily the case for a pure Rust pyo3 module, so disabling it.
+reportMissingModuleSource = false
+
+[[tool.mypy.overrides]]
+module = [
+ "quil.quil",
+]
+ignore_missing_imports = true
diff --git a/quil-py/quil.html b/quil-py/quil.html
new file mode 100644
index 00000000..aaa4aa3a
--- /dev/null
+++ b/quil-py/quil.html
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+ quil API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quil-py/quil/__init__.py b/quil-py/quil/__init__.py
new file mode 100644
index 00000000..c04d99fc
--- /dev/null
+++ b/quil-py/quil/__init__.py
@@ -0,0 +1,6 @@
+"""The `quil` package provides tools for constructing, manipulating, parsing, and printing [Quil](https://github.com/quil-lang/quil) programs.
+
+⚠️ This package is still in early development and breaking changes should be expected between minor versions.
+"""
+
+from .quil import *
diff --git a/quil-py/quil/__init__.pyi b/quil-py/quil/__init__.pyi
new file mode 100644
index 00000000..e69de29b
diff --git a/quil-py/quil/expression/__init__.py b/quil-py/quil/expression/__init__.py
new file mode 100644
index 00000000..720522e6
--- /dev/null
+++ b/quil-py/quil/expression/__init__.py
@@ -0,0 +1 @@
+from quil.expression import *
diff --git a/quil-py/quil/expression/__init__.pyi b/quil-py/quil/expression/__init__.pyi
new file mode 100644
index 00000000..9d1da781
--- /dev/null
+++ b/quil-py/quil/expression/__init__.pyi
@@ -0,0 +1,197 @@
+"""The ``expression`` module contains classes for representing Quil expressions."""
+
+from enum import Enum
+from typing import Dict, Optional, Sequence, Union, final
+
+from quil.instructions import MemoryReference
+
+class EvaluationError(ValueError):
+ """Error that may occur while evaluation an ``Expression``."""
+
+class ParseExpressionError(ValueError):
+ """Error that may occur while parsing an ``Expression``."""
+
+@final
+class Expression:
+ """A Quil expression.
+
+ # Variants:
+ - ``address``: An address defined by a `quil.instructions.MemoryReference`.
+ - ``function_call``: A `FunctionCallExpression`.
+ - ``infix``: An `InfixExpression`.
+ - ``number``: A number defined as a `complex`.
+ - ``pi``: The constant ``pi``. No inner data.
+ - ``prefix``: A `PrefixExpression`.
+ - ``variable``: A variable defined as a `str`.
+
+ As seen above, some variants contain inner data that fully specify the expression.
+ For example, the ``number`` variant contains an ``int``. This is in contrast to variants like
+ ``pi`` that have no inner data because they require none to fully specify the expression.
+ This difference is important for determining which methods are available for each variant.
+
+ Methods (for every variant):
+ - ``is_*``: Returns ``True`` if the expression is that variant, ``False`` otherwise.
+
+ If the variant has inner data:
+ - ``as_*``: returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``Expression`` of the given variant from an instance of the inner type.
+
+ If the variant doesn't have inner data (e.g. ``pi``)
+ - ``new_*``: Creates a new ``Expression`` for the variant
+ """
+
+ def inner(
+ self,
+ ) -> Union[
+ MemoryReference,
+ FunctionCallExpression,
+ InfixExpression,
+ int,
+ PrefixExpression,
+ str,
+ ]:
+ """Returns the inner value of the variant. Raises a ``RuntimeError`` if inner data doesn't exist."""
+ ...
+ @staticmethod
+ def parse(input: str) -> Expression:
+ """Parses an ``Expression`` from a string.
+
+ Raises a ``ParseExpressionError`` if the string isn't a valid Quil expression.
+ """
+ def is_address(self) -> bool: ...
+ def is_function_call(self) -> bool: ...
+ def is_infix(self) -> bool: ...
+ def is_number(self) -> bool: ...
+ def is_pi(self) -> bool: ...
+ def is_prefix(self) -> bool: ...
+ def is_variable(self) -> bool: ...
+ @staticmethod
+ def new_pi() -> "Expression": ...
+ @staticmethod
+ def from_address(inner: MemoryReference) -> "Expression": ...
+ @staticmethod
+ def from_function_call(inner: FunctionCallExpression) -> "Expression": ...
+ @staticmethod
+ def from_infix(inner: InfixExpression) -> "Expression": ...
+ @staticmethod
+ def from_number(inner: complex) -> "Expression": ...
+ @staticmethod
+ def from_prefix(inner: PrefixExpression) -> "Expression": ...
+ @staticmethod
+ def from_variable(inner: str) -> "Expression": ...
+ def as_address(self) -> Optional[MemoryReference]: ...
+ def to_address(self) -> MemoryReference: ...
+ def as_function_call(self) -> Optional[FunctionCallExpression]: ...
+ def to_function_call(self) -> FunctionCallExpression: ...
+ def as_infix(self) -> Optional[InfixExpression]: ...
+ def to_infix(self) -> InfixExpression: ...
+ def as_number(self) -> Optional[complex]: ...
+ def to_number(self) -> complex: ...
+ def as_prefix(self) -> Optional[PrefixExpression]: ...
+ def to_prefix(self) -> PrefixExpression: ...
+ def as_variable(self) -> Optional[str]: ...
+ def to_variable(self) -> str: ...
+ def simplify(self):
+ """Simplify the expression as much as possible, in-place."""
+ ...
+ def into_simplified(self) -> "Expression":
+ """Return a simplified copy of the expression."""
+ def evaluate(
+ self,
+ variables: Dict[str, complex],
+ memory_references: Dict[str, Sequence[float]],
+ ) -> complex:
+ """Evaluate an expression, expecting that it may be fully reduced to a single complex number.
+
+ If it cannot be reduced to a complex number, raises an ``EvaluationError``.
+ """
+ ...
+ def substitute_variables(self, variable_values: Dict[str, "Expression"]) -> "Expression":
+ """Returns a copy of the expression where every matching variable in `variable_values` is replaced by the corresponding expression."""
+ ...
+ def to_real(self) -> float:
+ """If this is a number with imaginary part "equal to" zero (of small absolute value), return that number. Otherwise, raises an ``EvaluationError``."""
+ def __add__(self, other: "Expression") -> "Expression": ...
+ def __sub__(self, other: "Expression") -> "Expression": ...
+ def __mul__(self, other: "Expression") -> "Expression": ...
+ def __truediv__(self, other: "Expression") -> "Expression": ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string. Raises an exception if the instruction can't be converted to valid Quil."""
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug
+ format that isn't valid Quil.
+ """
+
+class FunctionCallExpression:
+ """A Quil function call."""
+ @staticmethod
+ def __new__(cls, function: ExpressionFunction, expression: Expression) -> "FunctionCallExpression": ...
+ @property
+ def function(self) -> ExpressionFunction: ...
+ @function.setter
+ def function(self, function: ExpressionFunction): ...
+ @property
+ def expression(self) -> Expression: ...
+ @expression.setter
+ def expression(self, expression: Expression): ...
+
+class InfixExpression:
+ """A Quil infix expression."""
+ @staticmethod
+ def __new__(cls, left: Expression, operator: InfixOperator, right: Expression): ...
+ @property
+ def left(self) -> Expression: ...
+ @left.setter
+ def left(self, expression: Expression): ...
+ @property
+ def operator(self) -> InfixOperator: ...
+ @operator.setter
+ def operator(self, operator: InfixOperator): ...
+ @property
+ def right(self) -> Expression: ...
+ @right.setter
+ def right(self, expression: Expression): ...
+
+class PrefixExpression:
+ """A Quil prefix expression."""
+ @staticmethod
+ def __new__(cls, operator: PrefixOperator, expression: Expression): ...
+ @property
+ def operator(self) -> PrefixOperator: ...
+ @operator.setter
+ def operator(self, operator: PrefixOperator): ...
+ @property
+ def expression(self) -> Expression: ...
+ @expression.setter
+ def expression(self, expression: Expression): ...
+
+@final
+class ExpressionFunction(Enum):
+ """An enum representing a Quil function that can be applied to an expression."""
+
+ Cis = "CIS"
+ Cosine = "COSINE"
+ Exponent = "EXPONENT"
+ Sine = "SINE"
+ SquareRoot = "SQUAREROOT"
+
+@final
+class PrefixOperator(Enum):
+ """An enum that represents the operators supported on a prefix expression."""
+
+ Plus = "PLUS"
+ Minus = "MINUS"
+
+@final
+class InfixOperator(Enum):
+ """An enum that represents the operators supported on an infix expression."""
+
+ Caret = "CARET"
+ Plus = "PLUS"
+ Minus = "MINUS"
+ Slash = "SLASH"
+ Star = "STAR"
diff --git a/quil-py/quil/instructions/__init__.py b/quil-py/quil/instructions/__init__.py
new file mode 100644
index 00000000..7062b812
--- /dev/null
+++ b/quil-py/quil/instructions/__init__.py
@@ -0,0 +1,3 @@
+"""The `quil.instructions` module contains classes for representing Quil instructions."""
+
+from quil.instructions import *
diff --git a/quil-py/quil/instructions/__init__.pyi b/quil-py/quil/instructions/__init__.pyi
new file mode 100644
index 00000000..6997ca8b
--- /dev/null
+++ b/quil-py/quil/instructions/__init__.pyi
@@ -0,0 +1,2304 @@
+from enum import Enum
+from typing import Dict, List, Optional, Sequence, Tuple, Union, final
+
+import numpy as np
+from numpy.typing import NDArray
+from typing_extensions import Self
+
+from quil.expression import Expression
+
+@final
+class Instruction:
+ """A Quil instruction. Each variant corresponds to a possible type of Quil instruction.
+
+ # Variants:
+ - ``arithmetic``: An arithmetic expression defined by an ``Arithmetic``.
+ - ``binary_logic``: A binary expression defined by a ``BinaryLogic``.
+ - ``calibration_definition``: Corresponds to a `DEFCAL` instruction (not `DEFCAL MEASURE`)
+ - defined by a ``Calibration``.
+ - ``capture``: Corresponds to a `CAPTURE` instruction
+ - ``calibration``: Corresponds to a `DEFCAL` instruction.
+ - ``circuit_definition``: Corresponds to a `DEFCIRCUIT` instruction and its body,
+ - defined by a ``CircuitDefinition``.
+ - ``convert``: Corresponds to a `CONVERT` instruction.
+ - ``comparison``: Corresponds to a comparison of two `MemoryReference`s
+ - ``declaration``: Corresponds to a `DECLARE` statement defined by a ``Declaration``.
+ - ``delay``: Corresponds to a `DELAY` instruction.
+ - ``exchange``: Corresponds to an `EXCHANGE` instruction.
+ - ``fence``: Corresponds to a `FENCE` instruction.
+ - ``frame_definition``: Corresponds to a `DEFFRAME` statement, defined by a ``FrameDefinition``.
+ - ``gate``: A Quil quantum gate instruction defined by a ``Gate``.
+ - ``gate_definition``: A quantum gate definition defined by a ``GateDefinition``.
+ - ``halt``: Corresponds to the `HALT` instruction. No inner data.
+ - ``include``: Corresponds to an `INCLUDE` directive.
+ - ``jump``: Corresponds to a `JUMP` instruction
+ - ``jump_when``: Corresponds to a `JUMP-WHEN` instruction
+ - ``jump_unless``: Corresponds to a `JUMP-UNLESS` instruction
+ - ``label``: Corresponds to a `LABEL`
+ - ``load``: Corresponds to a `LOAD` instruction.
+ - ``measure_calibration_definition``: Corresponds to a `DEFCAL MEASURE` instruction. Defined by a ``MeasureCalibrationDefinition``.
+ - ``measurement``: Corresponds to a `MEASURE` instruction.
+ - ``move``: Corresponds to a `MOVE` instruction.
+ - ``nop``: Corresponds to the `NOP` instruction. No inner data.
+ - ``pragma``: Corresponds to a `PRAGMA` instruction.
+ - ``pulse``: Corresponds to a `PULSE` instruction.
+ - ``raw_capture``: Corresponds to a `RAW-CAPTURE` instruction.
+ - ``reset``: Corresponds to a `RESET` instruction.
+ - ``set_frequency``: Corresponds to a `SET-FREQUENCY` instruction.
+ - ``set_phase``: Corresponds to a `SET-PHASE` instruction.
+ - ``set_scale``: Corresponds to a `SET-SCALE` instruction.
+ - ``shift_frequency``: Corresponds to a `SHIFT-FREQUENCY` instruction.
+ - ``shift_phase``: Corresponds to a `SHIFT-PHASE` instruction.
+ - ``store``: Corresponds to a `STORE` instruction.
+ - ``swap_phases``: Corresponds to a `SWAP-PHASES` instruction.
+ - ``unary_logic``: Corresponds to a unary operation on a `MemoryReference`.
+ - ``waveform_definition``: A waveform defined by a ``WaveformDefinition``.
+ - ``wait``: Corresponds to a `WAIT` instruction. No inner data.
+
+ As seen above, some variants contain inner data that fully specify the instruction.
+ For example, the ``gate`` variant contains a ``Gate``. This is in contrast to variants like
+ ``halt`` that have no inner data because they require none to fully specify an instruction.
+ This difference is important for determining which methods are available for each variant.
+
+ Methods (for each variant):
+ - ``is_*``: Returns ``True`` if the instruction is that variant, ``False`` otherwise.
+
+ If the variant has inner data (e.g. ``gate``):
+ - ``as_*``: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``Instruction`` of the given variant from an instance of the inner type.
+
+ If the variant doesn't have inner data (e.g. ``halt``)
+ - ``new_*``: Creates a new ``Instruction`` for the variant.
+ """
+
+ def __new__(
+ cls,
+ instruction: Union[
+ Arithmetic,
+ Calibration,
+ Capture,
+ BinaryLogic,
+ CircuitDefinition,
+ Convert,
+ Comparison,
+ Declaration,
+ Delay,
+ Exchange,
+ Fence,
+ FrameDefinition,
+ Gate,
+ GateDefinition,
+ Include,
+ Jump,
+ JumpWhen,
+ JumpUnless,
+ Label,
+ Load,
+ MeasureCalibrationDefinition,
+ Measurement,
+ Move,
+ Pragma,
+ Pulse,
+ RawCapture,
+ Reset,
+ SetFrequency,
+ SetPhase,
+ SetScale,
+ ShiftFrequency,
+ ShiftPhase,
+ Store,
+ SwapPhases,
+ UnaryLogic,
+ WaveformDefinition,
+ ],
+ ) -> Self:
+ """Returns a new ``Instruction`` from the given inner data."""
+ def is_quil_t(self) -> bool:
+ """Returns ``True`` if the instruction is a Quil-T instruction, ``False`` otherwise."""
+ ...
+ def inner(
+ self,
+ ) -> Union[
+ Arithmetic,
+ Calibration,
+ Capture,
+ BinaryLogic,
+ CircuitDefinition,
+ Convert,
+ Comparison,
+ Declaration,
+ Delay,
+ Exchange,
+ Fence,
+ FrameDefinition,
+ Gate,
+ GateDefinition,
+ Include,
+ Jump,
+ JumpWhen,
+ JumpUnless,
+ Label,
+ Load,
+ MeasureCalibrationDefinition,
+ Measurement,
+ Move,
+ Pragma,
+ Pulse,
+ RawCapture,
+ Reset,
+ SetFrequency,
+ SetPhase,
+ SetScale,
+ ShiftFrequency,
+ ShiftPhase,
+ Store,
+ SwapPhases,
+ UnaryLogic,
+ WaveformDefinition,
+ ]:
+ """Returns the inner value of the variant. Raises a ``RuntimeError`` if inner data doesn't exist."""
+ ...
+ def is_arithmetic(self) -> bool: ...
+ def is_binary_logic(self) -> bool: ...
+ def is_calibration_definition(self) -> bool: ...
+ def is_capture(self) -> bool: ...
+ def is_circuit_definition(self) -> bool: ...
+ def is_convert(self) -> bool: ...
+ def is_comparison(self) -> bool: ...
+ def is_declaration(self) -> bool: ...
+ def is_delay(self) -> bool: ...
+ def is_exchange(self) -> bool: ...
+ def is_fence(self) -> bool: ...
+ def is_frame_definition(self) -> bool: ...
+ def is_gate(self) -> bool: ...
+ def is_gate_definition(self) -> bool: ...
+ def is_halt(self) -> bool: ...
+ def is_include(self) -> bool: ...
+ def is_jump(self) -> bool: ...
+ def is_jump_when(self) -> bool: ...
+ def is_jump_unless(self) -> bool: ...
+ def is_label(self) -> bool: ...
+ def is_load(self) -> bool: ...
+ def is_measure_calibration_definition(self) -> bool: ...
+ def is_measurement(self) -> bool: ...
+ def is_move(self) -> bool: ...
+ def is_nop(self) -> bool: ...
+ def is_pragma(self) -> bool: ...
+ def is_pulse(self) -> bool: ...
+ def is_raw_capture(self) -> bool: ...
+ def is_reset(self) -> bool: ...
+ def is_set_frequency(self) -> bool: ...
+ def is_set_phase(self) -> bool: ...
+ def is_set_scale(self) -> bool: ...
+ def is_shift_frequency(self) -> bool: ...
+ def is_shift_phase(self) -> bool: ...
+ def is_unary_logic(self) -> bool: ...
+ def is_store(self) -> bool: ...
+ def is_swap_phases(self) -> bool: ...
+ def is_waveform_definition(self) -> bool: ...
+ def is_wait(self) -> bool: ...
+ @staticmethod
+ def new_halt() -> Instruction: ...
+ @staticmethod
+ def new_nop() -> Instruction: ...
+ @staticmethod
+ def new_wait() -> Instruction: ...
+ @staticmethod
+ def from_arithmetic(inner: Arithmetic) -> Instruction: ...
+ @staticmethod
+ def from_binary_logic(inner: BinaryLogic) -> Instruction: ...
+ @staticmethod
+ def from_calibration_definition(inner: Calibration) -> Instruction: ...
+ @staticmethod
+ def from_capture(inner: Capture) -> Instruction: ...
+ @staticmethod
+ def from_circuit_definition(
+ inner: CircuitDefinition,
+ ) -> Instruction: ...
+ @staticmethod
+ def from_convert(inner: Convert) -> Instruction: ...
+ @staticmethod
+ def from_comparison(inner: Comparison) -> Instruction: ...
+ @staticmethod
+ def from_declaration(inner: Declaration) -> Instruction: ...
+ @staticmethod
+ def from_delay(inner: Delay) -> Instruction: ...
+ @staticmethod
+ def from_exchange(inner: Exchange) -> Instruction: ...
+ @staticmethod
+ def from_fence(inner: Fence) -> Instruction: ...
+ @staticmethod
+ def from_frame_definition(inner: FrameDefinition) -> Instruction: ...
+ @staticmethod
+ def from_gate(inner: Gate) -> Instruction: ...
+ @staticmethod
+ def from_gate_definition(inner: GateDefinition) -> Instruction: ...
+ @staticmethod
+ def from_include(inner: Include) -> Instruction: ...
+ @staticmethod
+ def from_jump(inner: Jump) -> Instruction: ...
+ @staticmethod
+ def from_jump_when(inner: JumpWhen) -> Instruction: ...
+ @staticmethod
+ def from_jump_unless(inner: JumpUnless) -> Instruction: ...
+ @staticmethod
+ def from_label(inner: Label) -> Instruction: ...
+ @staticmethod
+ def from_load(inner: Load) -> Instruction: ...
+ @staticmethod
+ def from_measure_calibration_definition(
+ inner: MeasureCalibrationDefinition,
+ ) -> Instruction: ...
+ @staticmethod
+ def from_measurement(
+ inner: Measurement,
+ ) -> Instruction: ...
+ @staticmethod
+ def from_move(inner: Move) -> Instruction: ...
+ @staticmethod
+ def from_pragma(inner: Pragma) -> Instruction: ...
+ @staticmethod
+ def from_pulse(inner: Pulse) -> Instruction: ...
+ @staticmethod
+ def from_raw_capture(inner: RawCapture) -> Instruction: ...
+ @staticmethod
+ def from_set_frequency(inner: SetFrequency) -> Instruction: ...
+ @staticmethod
+ def from_set_phase(inner: SetPhase) -> Instruction: ...
+ @staticmethod
+ def from_set_scale(inner: SetScale) -> Instruction: ...
+ @staticmethod
+ def from_shift_frequency(inner: ShiftFrequency) -> Instruction: ...
+ @staticmethod
+ def from_shift_phase(inner: ShiftPhase) -> Instruction: ...
+ @staticmethod
+ def from_unary_logic(inner: UnaryLogic) -> Instruction: ...
+ @staticmethod
+ def from_store(inner: Store) -> Instruction: ...
+ @staticmethod
+ def from_swap_phases(inner: SwapPhases) -> Instruction: ...
+ @staticmethod
+ def from_reset(inner: Reset) -> Instruction: ...
+ @staticmethod
+ def from_waveform_definition(
+ inner: WaveformDefinition,
+ ) -> Instruction: ...
+ def as_arithmetic(self) -> Optional[Arithmetic]: ...
+ def to_arithmetic(self) -> Arithmetic: ...
+ def as_binary_logic(self) -> Optional[BinaryLogic]: ...
+ def to_binary_logic(self) -> BinaryLogic: ...
+ def as_convert(self) -> Optional[Convert]: ...
+ def to_convert(self) -> Convert: ...
+ def as_comparison(self) -> Optional[Comparison]: ...
+ def to_comparison(self) -> Comparison: ...
+ def as_circuit_definition(self) -> Optional[CircuitDefinition]: ...
+ def to_circuit_definition(self) -> CircuitDefinition: ...
+ def as_calibration_definition(self) -> Optional[Calibration]: ...
+ def to_calibration_definition(self) -> Calibration: ...
+ def as_capture(self) -> Optional[Capture]: ...
+ def to_capture(self) -> Capture: ...
+ def as_declaration(self) -> Optional[Declaration]: ...
+ def to_declaration(self) -> Declaration: ...
+ def as_delay(self) -> Optional[Delay]: ...
+ def to_delay(self) -> Delay: ...
+ def as_exchange(self) -> Optional[Exchange]: ...
+ def to_exchange(self) -> Exchange: ...
+ def as_fence(self) -> Optional[Fence]: ...
+ def to_fence(self) -> Fence: ...
+ def as_gate(self) -> Optional[Gate]: ...
+ def to_gate(self) -> Gate: ...
+ def as_gate_definition(self) -> Optional[GateDefinition]: ...
+ def to_gate_definition(self) -> GateDefinition: ...
+ def as_include(self) -> Optional[Include]: ...
+ def to_include(self) -> Include: ...
+ def as_jump(self) -> Optional[Jump]: ...
+ def to_jump(self) -> Jump: ...
+ def as_jump_when(self) -> Optional[JumpWhen]: ...
+ def to_jump_when(self) -> JumpWhen: ...
+ def as_jump_unless(self) -> Optional[JumpUnless]: ...
+ def to_jump_unless(self) -> JumpUnless: ...
+ def as_label(self) -> Optional[Label]: ...
+ def to_label(self) -> Label: ...
+ def as_load(self) -> Optional[Load]: ...
+ def to_load(self) -> Load: ...
+ def as_frame_definition(self) -> Optional[FrameDefinition]: ...
+ def to_frame_definition(self) -> FrameDefinition: ...
+ def as_measure_calibration_definition(
+ self,
+ ) -> Optional[MeasureCalibrationDefinition]: ...
+ def to_measure_calibration_definition(self) -> MeasureCalibrationDefinition: ...
+ def as_measurement(
+ self,
+ ) -> Optional[Measurement]: ...
+ def to_measurement(self) -> Measurement: ...
+ def as_move(self) -> Optional[Move]: ...
+ def to_move(self) -> Move: ...
+ def as_pragma(self) -> Optional[Pragma]: ...
+ def to_pragma(self) -> Pragma: ...
+ def as_pulse(self) -> Optional[Pulse]: ...
+ def to_pulse(self) -> Pulse: ...
+ def as_raw_capture(self) -> Optional[RawCapture]: ...
+ def to_raw_capture(self) -> RawCapture: ...
+ def as_reset(self) -> Optional[Reset]: ...
+ def to_reset(self) -> Reset: ...
+ def as_set_frequency(self) -> Optional[SetFrequency]: ...
+ def to_set_frequency(self) -> SetFrequency: ...
+ def as_set_phase(self) -> Optional[SetPhase]: ...
+ def to_set_phase(self) -> SetPhase: ...
+ def as_set_scale(self) -> Optional[SetScale]: ...
+ def to_set_scale(self) -> SetScale: ...
+ def as_shift_frequency(self) -> Optional[ShiftFrequency]: ...
+ def to_shift_frequency(self) -> ShiftFrequency: ...
+ def as_shift_phase(self) -> Optional[ShiftPhase]: ...
+ def to_shift_phase(self) -> ShiftPhase: ...
+ def as_unary_logic(self) -> Optional[UnaryLogic]: ...
+ def to_unary_logic(self) -> UnaryLogic: ...
+ def as_store(self) -> Optional[Store]: ...
+ def to_store(self) -> Store: ...
+ def as_swap_phases(self) -> Optional[SwapPhases]: ...
+ def to_swap_phases(self) -> SwapPhases: ...
+ def as_waveform_definition(self) -> Optional[WaveformDefinition]: ...
+ def to_waveform_definition(self) -> WaveformDefinition: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string. Raises an exception if the instruction can't be converted to valid Quil."""
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+@final
+class ArithmeticOperand:
+ """A Quil arithmetic operand.
+
+ # Variants:
+ - ``literal_integer``: An integer literal.
+ - ``literal_real``: A real numbered literal.
+ - ``memory_reference``: A Quil ``MemoryReference``.
+
+ Methods (for each variant):
+ - ``is_*``: Returns ``True`` if the operand is that variant, ``False`` otherwise.
+ - ``as_*``: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``ArithmeticOperand`` of the given variant from an instance of the inner type.
+ """
+
+ def inner(self) -> Union[int, float, MemoryReference]:
+ """Returns the inner value of the variant. Raises a ``RuntimeError`` if inner data doesn't exist."""
+ ...
+ def is_literal_integer(self) -> bool: ...
+ def is_literal_real(self) -> bool: ...
+ def is_memory_reference(self) -> bool: ...
+ def as_literal_integer(self) -> Optional[int]: ...
+ def as_literal_real(self) -> Optional[float]: ...
+ def as_memory_reference(self) -> Optional[MemoryReference]: ...
+ def to_literal_integer(self) -> int: ...
+ def to_literal_real(self) -> float: ...
+ def to_memory_reference(self) -> MemoryReference: ...
+ @staticmethod
+ def from_literal_integer(inner: int) -> ArithmeticOperand: ...
+ @staticmethod
+ def from_literal_real(inner: float) -> ArithmeticOperand: ...
+ @staticmethod
+ def from_memory_reference(
+ inner: MemoryReference,
+ ) -> ArithmeticOperand: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+@final
+class ArithmeticOperator(Enum):
+ Add = "Add"
+ Subtract = "Subtract"
+ Divide = "Divide"
+ Multiply = "Multiply"
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class Arithmetic:
+ def __new__(
+ cls,
+ operator: ArithmeticOperator,
+ destination: ArithmeticOperand,
+ source: ArithmeticOperand,
+ ) -> Self: ...
+ @property
+ def operator(self) -> ArithmeticOperator: ...
+ @operator.setter
+ def operator(self, operator: ArithmeticOperator) -> None: ...
+ @property
+ def destination(self) -> ArithmeticOperand: ...
+ @destination.setter
+ def destination(self, operand: ArithmeticOperand) -> None: ...
+ @property
+ def source(self) -> ArithmeticOperand: ...
+ @source.setter
+ def source(self, operand: ArithmeticOperand) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original. Should be used by passing
+ an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+@final
+class BinaryOperand:
+ """A Quil binary operand.
+
+ # Variants:
+ - ``literal_integer``: An integer literal.
+ - ``memory_reference``: A Quil ``MemoryReference``.
+
+ Methods (for each variant):
+ - ``is_*``: Returns ``True`` if the operand is that variant, ``False`` otherwise.
+ - ``as_*``: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``BinaryOperand`` of the given variant from an instance of the inner type.
+ """
+
+ def inner(self) -> Union[int, MemoryReference]:
+ """Returns the inner value of the variant. Raises a ``RuntimeError`` if inner data doesn't exist."""
+ ...
+ def is_literal_integer(self) -> bool: ...
+ def is_memory_reference(self) -> bool: ...
+ def as_literal_integer(self) -> Optional[int]: ...
+ def as_memory_reference(self) -> Optional[MemoryReference]: ...
+ def to_literal_integer(self) -> int: ...
+ def to_memory_reference(self) -> MemoryReference: ...
+ @staticmethod
+ def from_literal_integer(inner: int) -> BinaryOperand: ...
+ @staticmethod
+ def from_memory_reference(
+ inner: MemoryReference,
+ ) -> BinaryOperand: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+@final
+class BinaryOperator(Enum):
+ And = "AND"
+ Ior = "IOR"
+ Xor = "XOR"
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class BinaryOperands:
+ def __new__(
+ cls,
+ memory_reference: MemoryReference,
+ operand: BinaryOperand,
+ ) -> Self: ...
+ @property
+ def memory_reference(self) -> MemoryReference: ...
+ @memory_reference.setter
+ def memory_reference(self, memory_reference: MemoryReference) -> None: ...
+ @property
+ def operand(self) -> BinaryOperand: ...
+ @operand.setter
+ def operand(self, operand: BinaryOperand) -> None: ...
+
+class BinaryLogic:
+ def __new__(
+ cls,
+ operator: BinaryOperator,
+ operands: BinaryOperands,
+ ) -> Self: ...
+ @property
+ def operator(self) -> BinaryOperator: ...
+ @operator.setter
+ def operator(self, operator: BinaryOperator) -> None: ...
+ @property
+ def operands(self) -> BinaryOperands: ...
+ @operands.setter
+ def operands(self, operands: BinaryOperands) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Convert:
+ def __new__(cls, destination: MemoryReference, source: MemoryReference) -> Self: ...
+ @property
+ def destination(self) -> MemoryReference: ...
+ @destination.setter
+ def destination(self, destination: MemoryReference) -> None: ...
+ @property
+ def source(self) -> MemoryReference: ...
+ @source.setter
+ def source(self, source: MemoryReference) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Move:
+ def __new__(cls, destination: MemoryReference, source: ArithmeticOperand) -> Self: ...
+ @property
+ def destination(self) -> MemoryReference: ...
+ @destination.setter
+ def destination(self, destination: MemoryReference) -> None: ...
+ @property
+ def source(self) -> ArithmeticOperand: ...
+ @source.setter
+ def source(self, source: ArithmeticOperand) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Exchange:
+ def __new__(cls, left: MemoryReference, right: MemoryReference) -> Self: ...
+ @property
+ def left(self) -> MemoryReference: ...
+ @left.setter
+ def left(self, left: MemoryReference) -> None: ...
+ @property
+ def right(self) -> MemoryReference: ...
+ @right.setter
+ def right(self, right: MemoryReference) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+@final
+class ComparisonOperand:
+ """A Quil binary operand.
+
+ # Variants:
+ - ``literal_integer``: An integer literal.
+ - ``literal_real``: A floating point literal.
+ - ``memory_reference``: A Quil ``MemoryReference``.
+
+ Methods (for each variant):
+ - ``is_*``: Returns ``True`` if the operand is that variant, ``False`` otherwise.
+ - ``as_*``: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``BinaryOperand`` of the given variant from an instance of the inner type.
+ """
+
+ def inner(self) -> Union[int, float, MemoryReference]:
+ """Returns the inner value of the variant."""
+ ...
+ def is_literal_integer(self) -> bool: ...
+ def is_literal_real(self) -> bool: ...
+ def is_memory_reference(self) -> bool: ...
+ def as_literal_integer(self) -> Optional[int]: ...
+ def as_literal_real(self) -> Optional[float]: ...
+ def as_memory_reference(self) -> Optional[MemoryReference]: ...
+ def to_literal_integer(self) -> int: ...
+ def to_literal_real(self) -> float: ...
+ def to_memory_reference(self) -> MemoryReference: ...
+ @staticmethod
+ def from_literal_integer(inner: int) -> ComparisonOperand: ...
+ @staticmethod
+ def from_literal_real(inner: float) -> ComparisonOperand: ...
+ @staticmethod
+ def from_memory_reference(
+ inner: MemoryReference,
+ ) -> ComparisonOperand: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+@final
+class ComparisonOperator(Enum):
+ Equal = "EQUAL"
+ GreaterThanOrEqual = "GREATERTHANOREQUAL"
+ GreaterThan = "GREATERTHAN"
+ LessThanOrEqual = "GREATERTHANOREQUAL"
+ LessThan = "LESSTHAN"
+
+class Comparison:
+ def __new__(
+ cls,
+ operator: ComparisonOperator,
+ operands: Tuple[MemoryReference, MemoryReference, ComparisonOperand],
+ ) -> Self: ...
+ @property
+ def operator(self) -> ComparisonOperator: ...
+ @operator.setter
+ def operator(self, operator: ComparisonOperator) -> None: ...
+ @property
+ def operands(
+ self,
+ ) -> Tuple[MemoryReference, MemoryReference, ComparisonOperand]: ...
+ @operands.setter
+ def operands(self, operands: Tuple[MemoryReference, MemoryReference, ComparisonOperand]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+@final
+class UnaryOperator(Enum):
+ Neg = "NEG"
+ Not = "NOT"
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class UnaryLogic:
+ def __new__(cls, operator: UnaryOperator, operand: MemoryReference) -> Self: ...
+ @property
+ def operator(self) -> UnaryOperator: ...
+ @operator.setter
+ def operator(self, operator: UnaryOperator) -> None: ...
+ @property
+ def operand(self) -> MemoryReference: ...
+ @operand.setter
+ def operand(self, operand: MemoryReference) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Calibration:
+ def __new__(
+ cls,
+ name: str,
+ parameters: Sequence[Expression],
+ qubits: Sequence[Qubit],
+ instructions: Sequence[Instruction],
+ modifiers: Sequence[GateModifier],
+ ) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def parameters(self) -> List[Expression]: ...
+ @parameters.setter
+ def parameters(self, parameters: Sequence[Expression]) -> None: ...
+ @property
+ def qubits(self) -> List[Qubit]: ...
+ @qubits.setter
+ def qubits(self, qubits: Sequence[Qubit]) -> None: ...
+ @property
+ def instructions(self) -> List[Instruction]: ...
+ @instructions.setter
+ def instructions(self, instructions: Sequence[Instruction]) -> None: ...
+ @property
+ def modifiers(self) -> List[GateModifier]: ...
+ @modifiers.setter
+ def modifiers(self, modifiers: Sequence[GateModifier]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class MeasureCalibrationDefinition:
+ def __new__(
+ cls,
+ qubit: Optional[Qubit],
+ parameter: str,
+ instructions: Sequence[Instruction],
+ ) -> Self: ...
+ @property
+ def qubit(self) -> Optional[Qubit]: ...
+ @qubit.setter
+ def qubit(self, qubit: Optional[Qubit]) -> None: ...
+ @property
+ def parameter(self) -> str: ...
+ @parameter.setter
+ def parameter(self, parameter: str) -> None: ...
+ @property
+ def instructions(self) -> List[Instruction]: ...
+ @instructions.setter
+ def instructions(self, instructions: Sequence[Instruction]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class CircuitDefinition:
+ def __new__(
+ cls,
+ name: str,
+ parameters: Sequence[str],
+ qubit_variables: Sequence[str],
+ instructions: Sequence[Instruction],
+ ) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def parameters(self) -> List[str]: ...
+ @parameters.setter
+ def parameters(self, parameters: Sequence[str]) -> None: ...
+ @property
+ def qubit_variables(self) -> List[str]: ...
+ @qubit_variables.setter
+ def qubit_variables(self, qubit_variables: Sequence[str]) -> None: ...
+ @property
+ def instructions(self) -> List[Instruction]: ...
+ @instructions.setter
+ def instructions(self, instructions: Sequence[Instruction]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Offset:
+ def __new__(
+ cls,
+ offset: int,
+ data_type: ScalarType,
+ ) -> Self: ...
+ @property
+ def offset(self) -> int: ...
+ @offset.setter
+ def offset(self, offset: int) -> None: ...
+ @property
+ def data_type(self) -> ScalarType: ...
+ @data_type.setter
+ def data_type(self, data_type: ScalarType) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class Sharing:
+ def __new__(
+ cls,
+ name: str,
+ offsets: Sequence[Offset],
+ ) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def offsets(self) -> List[Offset]: ...
+ @offsets.setter
+ def offsets(self, offsets: Sequence[Offset]) -> None: ...
+
+class Declaration:
+ def __new__(cls, name: str, size: Vector, sharing: Optional[Sharing]) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def size(self) -> Vector: ...
+ @size.setter
+ def size(self, vector: Vector) -> None: ...
+ @property
+ def sharing(self) -> Optional[Sharing]: ...
+ @sharing.setter
+ def sharing(self, sharing: Optional[Sharing]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Vector:
+ def __new__(cls, data_type: ScalarType, length: int) -> Self: ...
+ @property
+ def data_type(self) -> ScalarType: ...
+ @data_type.setter
+ def data_type(self, data_type: ScalarType) -> None: ...
+ @property
+ def length(self) -> int: ...
+ @length.setter
+ def length(self, data_type: int) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+@final
+class ScalarType(Enum):
+ Bit = "BIT"
+ Integer = "INTEGER"
+ Octet = "OCTET"
+ Real = "REAL"
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+@final
+class AttributeValue:
+ """A frame attribute value.
+
+ # Variants:
+ - ``string``: A string attribute containing a ``str``.
+ - ``expression``: An expression attribute containing an ``Expression``.
+
+ Methods (for each variant):
+ - ``is_*``: Returns ``True`` if the ``AttributeValue`` is that variant, ``False`` otherwise.
+ - ``as_*``: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``AttributeValue`` of the given variant from an instance of the inner type.
+ """
+
+ def inner(self) -> Union[str, Expression]:
+ """Returns the inner value of the variant. Raises a ``RuntimeError`` if inner data doesn't exist."""
+ ...
+ def is_string(self) -> bool: ...
+ def is_expression(self) -> bool: ...
+ @staticmethod
+ def from_string(inner: str) -> AttributeValue: ...
+ @staticmethod
+ def from_expression(inner: Expression) -> AttributeValue: ...
+ def as_string(self) -> Optional[str]: ...
+ def to_string(self) -> str: ...
+ def as_expression(self) -> Optional[Expression]: ...
+ def to_expression(self) -> Expression: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class FrameDefinition:
+ def __new__(
+ cls,
+ identifier: FrameIdentifier,
+ attributes: Dict[str, AttributeValue],
+ ) -> Self: ...
+ @property
+ def identifier(self) -> FrameIdentifier: ...
+ @identifier.setter
+ def identifier(self, identifier: FrameIdentifier) -> None: ...
+ @property
+ def attributes(self) -> Dict[str, AttributeValue]: ...
+ @attributes.setter
+ def attributes(self, identifier: Dict[str, AttributeValue]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class FrameIdentifier:
+ def __new__(cls, name: str, qubits: Sequence[Qubit]) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def qubits(self) -> List[Qubit]: ...
+ @qubits.setter
+ def qubits(self, qubits: Sequence[Qubit]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class Capture:
+ def __new__(
+ cls,
+ blocking: bool,
+ frame: FrameIdentifier,
+ memory_reference: MemoryReference,
+ waveform: WaveformInvocation,
+ ) -> Self: ...
+ @property
+ def blocking(self) -> bool: ...
+ @blocking.setter
+ def blocking(self, blocking: bool) -> None: ...
+ @property
+ def frame(self) -> FrameIdentifier: ...
+ @frame.setter
+ def frame(self, frame: FrameIdentifier) -> None: ...
+ @property
+ def memory_reference(self) -> MemoryReference: ...
+ @memory_reference.setter
+ def memory_reference(self, memory_reference: MemoryReference) -> None: ...
+ @property
+ def waveform(self) -> WaveformInvocation: ...
+ @waveform.setter
+ def waveform(self, waveform: WaveformInvocation) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Pulse:
+ def __new__(
+ cls,
+ blocking: bool,
+ frame: FrameIdentifier,
+ waveform: WaveformInvocation,
+ ) -> Self: ...
+ @property
+ def blocking(self) -> bool: ...
+ @blocking.setter
+ def blocking(self, blocking: bool) -> None: ...
+ @property
+ def frame(self) -> FrameIdentifier: ...
+ @frame.setter
+ def frame(self, frame: FrameIdentifier) -> None: ...
+ @property
+ def waveform(self) -> WaveformInvocation: ...
+ @waveform.setter
+ def waveform(self, waveform: WaveformInvocation) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class RawCapture:
+ def __new__(
+ cls,
+ blocking: bool,
+ frame: FrameIdentifier,
+ duration: Expression,
+ memory_reference: MemoryReference,
+ ) -> Self: ...
+ @property
+ def blocking(self) -> bool: ...
+ @blocking.setter
+ def blocking(self, blocking: bool) -> None: ...
+ @property
+ def frame(self) -> FrameIdentifier: ...
+ @frame.setter
+ def frame(self, frame: FrameIdentifier) -> None: ...
+ @property
+ def duration(self) -> Expression: ...
+ @duration.setter
+ def duration(self, duration: Expression) -> None: ...
+ @property
+ def memory_reference(self) -> MemoryReference: ...
+ @memory_reference.setter
+ def memory_reference(self, memory_reference: MemoryReference) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class SetFrequency:
+ def __new__(cls, frame: FrameIdentifier, frequency: Expression) -> Self: ...
+ @property
+ def frame(self) -> FrameIdentifier: ...
+ @frame.setter
+ def frame(self, frame: FrameIdentifier) -> None: ...
+ @property
+ def frequency(self) -> Expression: ...
+ @frequency.setter
+ def frequency(self, frequency: Expression) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class SetPhase:
+ def __new__(cls, frame: FrameIdentifier, phase: Expression) -> Self: ...
+ @property
+ def frame(self) -> FrameIdentifier: ...
+ @frame.setter
+ def frame(self, frame: FrameIdentifier) -> None: ...
+ @property
+ def phase(self) -> Expression: ...
+ @phase.setter
+ def phase(self, phase: Expression) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class SetScale:
+ def __new__(cls, frame: FrameIdentifier, phase: Expression) -> Self: ...
+ @property
+ def frame(self) -> FrameIdentifier: ...
+ @frame.setter
+ def frame(self, frame: FrameIdentifier) -> None: ...
+ @property
+ def scale(self) -> Expression: ...
+ @scale.setter
+ def scale(self, scale: Expression) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class ShiftFrequency:
+ def __new__(cls, frame: FrameIdentifier, frequency: Expression) -> Self: ...
+ @property
+ def frame(self) -> FrameIdentifier: ...
+ @frame.setter
+ def frame(self, frame: FrameIdentifier) -> None: ...
+ @property
+ def frequency(self) -> Expression: ...
+ @frequency.setter
+ def frequency(self, frequency: Expression) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class ShiftPhase:
+ def __new__(cls, frame: FrameIdentifier, phase: Expression) -> Self: ...
+ @property
+ def frame(self) -> FrameIdentifier: ...
+ @frame.setter
+ def frame(self, frame: FrameIdentifier) -> None: ...
+ @property
+ def phase(self) -> Expression: ...
+ @phase.setter
+ def phase(self, phase: Expression) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class SwapPhases:
+ def __new__(cls, frame_1: FrameIdentifier, frame_2: FrameIdentifier) -> Self: ...
+ @property
+ def frame_1(self) -> FrameIdentifier: ...
+ @frame_1.setter
+ def frame_1(self, frame_1: FrameIdentifier) -> None: ...
+ @property
+ def frame_2(self) -> FrameIdentifier: ...
+ @frame_2.setter
+ def frame_2(self, frame_2: FrameIdentifier) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class GateError(ValueError):
+ """An error that may occur when performing operations on a ``Gate``."""
+
+ ...
+
+@final
+class GateModifier(Enum):
+ Controlled = "CONTROLLED"
+ Dagger = "DAGGER"
+ Forked = "FORKED"
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class Gate:
+ def __new__(
+ cls,
+ name: str,
+ parameters: Sequence[Expression],
+ qubits: Sequence[Qubit],
+ modifiers: Sequence[GateModifier],
+ ) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def parameters(self) -> List[Expression]: ...
+ @parameters.setter
+ def parameters(self, parameters: Sequence[Expression]) -> None: ...
+ @property
+ def qubits(self) -> List[Qubit]: ...
+ @qubits.setter
+ def qubits(self, qubits: Sequence[Qubit]) -> None: ...
+ @property
+ def modifiers(self) -> List[GateModifier]: ...
+ @modifiers.setter
+ def modifiers(self, modifiers: Sequence[GateModifier]) -> None: ...
+ def dagger(self) -> Self:
+ """Returns a copy of the gate with the ``DAGGER`` modifier added to it."""
+ ...
+ def controlled(self, control_qubit: Qubit) -> Self:
+ """Returns a copy of the gate with the ``CONTROLLED`` modifier added to it."""
+ def forked(self, fork_qubit: Qubit, alt_params: Sequence[Expression]) -> Self:
+ """Returns a copy of the gate with the ``FORKED`` modifier added to it.
+
+ Raises a ``GateError`` if the number of provided alternate parameters don't
+ equal the number of existing parameters.
+ """
+ ...
+ def to_unitary_mut(self, n_qubits: int) -> NDArray[np.complex_]:
+ """Lift a Gate to the full `n_qubits`-qubit Hilbert space.
+
+ Returns a ``GateError` if any of the parameters of this gate are
+ non-constant, if any of the qubits are variable, if the name of this
+ gate is unknown, or if there are an unexpected number of parameters.
+ """
+ ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+@final
+class PauliGate(Enum):
+ I = "I"
+ X = "X"
+ Y = "Y"
+ Z = "Z"
+ @staticmethod
+ def parse(input: str) -> PauliGate:
+ """Parses a ``PauliGate`` from a string. Raises a ``ParseEnumError`` if the string isn't a valid Pauli word."""
+ ...
+
+class PauliTerm:
+ def __new__(
+ cls,
+ arguments: Sequence[Tuple[PauliGate, str]],
+ expression: Expression,
+ ) -> Self: ...
+ @property
+ def arguments(self) -> List[Tuple[PauliGate, str]]: ...
+ @arguments.setter
+ def arguments(self, word: Sequence[Tuple[PauliGate, str]]) -> None: ...
+ @property
+ def expression(self) -> Expression: ...
+ @expression.setter
+ def expression(self, expression: Expression) -> None: ...
+
+class PauliSum:
+ def __new__(cls, arguments: Sequence[str], terms: Sequence[PauliTerm]) -> Self: ...
+ @property
+ def arguments(self) -> List[str]: ...
+ @arguments.setter
+ def arguments(self, arguments: Sequence[str]) -> None: ...
+ @property
+ def terms(self) -> List[PauliTerm]: ...
+ @terms.setter
+ def terms(self, terms: Sequence[PauliTerm]) -> None: ...
+
+@final
+class GateSpecification:
+ """A specification for a gate definition.
+
+ # Variants:
+ - ``matrix``: A gate specified by a matrix of ``Expression``s representing a unitary operation.
+ - ``permutation``: A gate specified by a vector of integers that defines a permutation.
+
+ Methods (for each variant):
+ - is_*: Returns ``True`` if the inner type is of that variant.
+ - as_*: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - to_*: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - from_*: Creates a new ``GateSpecification`` using an instance of the inner type for the variant.
+ """
+
+ def inner(self) -> Union[List[List[Expression]], List[int], PauliSum]:
+ """Returns the inner value of the variant. Raises a ``RuntimeError`` if inner data doesn't exist."""
+ ...
+ def is_matrix(self) -> bool: ...
+ def is_permutation(self) -> bool: ...
+ def is_pauli_sum(self) -> bool: ...
+ def as_matrix(self) -> Optional[List[List[Expression]]]: ...
+ def to_matrix(self) -> List[List[Expression]]: ...
+ def as_permutation(self) -> Optional[List[int]]: ...
+ def to_permutation(self) -> List[int]: ...
+ def as_pauli_sum(self) -> Optional[PauliSum]: ...
+ def to_pauli_sum(self) -> PauliSum: ...
+ @staticmethod
+ def from_matrix(inner: Sequence[Sequence[Expression]]) -> GateSpecification: ...
+ @staticmethod
+ def from_permutation(inner: Sequence[int]) -> GateSpecification: ...
+ @staticmethod
+ def from_pauli_sum(inner: PauliSum) -> GateSpecification: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class GateDefinition:
+ def __new__(
+ cls,
+ name: str,
+ parameters: Sequence[str],
+ specification: GateSpecification,
+ ) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def parameters(self) -> List[str]: ...
+ @parameters.setter
+ def parameters(self, parameters: Sequence[str]) -> None: ...
+ @property
+ def specification(self) -> GateSpecification: ...
+ @specification.setter
+ def specification(self, specification: GateSpecification) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+@final
+class Qubit:
+ """A Qubit.
+
+ # Variants:
+ - ``fixed``: A qubit represented as a fixed integer index.
+ - ``variable``: A qubit represented by a name.
+
+ Methods (for each variant):
+ - ``is_*``: Returns ``True`` if the inner type is of that variant.
+ - ``as_*``: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``Qubit`` using an instance of the inner type for the variant.
+ """
+
+ def inner(self) -> Union[int, str]:
+ """Returns the inner value of the variant. Raises a ``RuntimeError`` if inner data doesn't exist."""
+ ...
+ def is_fixed(self) -> bool: ...
+ def is_variable(self) -> bool: ...
+ def is_placeholder(self) -> bool: ...
+ def as_fixed(self) -> Optional[int]: ...
+ def to_fixed(self) -> int: ...
+ def as_variable(self) -> Optional[str]: ...
+ def to_variable(self) -> str: ...
+ def as_placeholder(self) -> Optional[QubitPlaceholder]: ...
+ def to_placeholder(self) -> QubitPlaceholder: ...
+ @staticmethod
+ def from_fixed(inner: int) -> Qubit: ...
+ @staticmethod
+ def from_variable(inner: str) -> Qubit: ...
+ @staticmethod
+ def from_placeholder(inner: QubitPlaceholder) -> Qubit: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class QubitPlaceholder:
+ """A qubit that can be used as a placeholder.
+
+ Placeholders must be resolved before converting a program to valid Quil. See ``quil.program.Program#resolve_placeholders``.
+ """
+
+ def __new__(cls) -> Self: ...
+ def __lt__(self, other: QubitPlaceholder) -> bool: ...
+
+class Reset:
+ def __new__(cls, qubit: Optional[Qubit]) -> Self: ...
+ @property
+ def qubit(self) -> Optional[Qubit]: ...
+ @qubit.setter
+ def qubit(self, qubit: Optional[Qubit]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Delay:
+ def __new__(cls, duration: Expression, frame_names: Sequence[str], qubits: Sequence[Qubit]) -> Self: ...
+ @property
+ def duration(self) -> Expression: ...
+ @duration.setter
+ def duration(self, duration: Expression) -> None: ...
+ @property
+ def frame_names(self) -> List[str]: ...
+ @frame_names.setter
+ def frame_names(self, frame_names: Sequence[str]) -> None: ...
+ @property
+ def qubits(self) -> List[Qubit]: ...
+ @qubits.setter
+ def qubits(self, qubits: Sequence[Qubit]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Fence:
+ def __new__(cls, qubits: Sequence[Qubit]) -> Self: ...
+ @property
+ def qubits(self) -> List[Qubit]: ...
+ @qubits.setter
+ def qubits(self, qubits: Sequence[Qubit]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+@final
+class PragmaArgument:
+ """A PRAGMA argument.
+
+ Variants:
+ - ``identifier``: A Pragma argument defined by a Quil identifier
+ - ``integer``: A Pragma argument defined by an integer
+
+ Methods (for each variant):
+ - ``is_*``: Returns ``True`` if the inner type is of that variant.
+ - ``as_*``: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``PragmaArgument`` using an instance of the inner type for the variant.
+ """
+
+ def inner(self) -> Union[str, int]:
+ """Returns the inner value of the variant. Raises a ``RuntimeError`` if inner data doesn't exist."""
+ ...
+ def is_identifier(self) -> bool: ...
+ def is_integer(self) -> bool: ...
+ def as_identifier(self) -> Optional[str]: ...
+ def as_integer(self) -> Optional[int]: ...
+ def to_identifier(self) -> str: ...
+ def to_integer(self) -> int: ...
+ @staticmethod
+ def from_identifier(inner: str) -> PragmaArgument: ...
+ @staticmethod
+ def from_integer(inner: int) -> PragmaArgument: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class Include:
+ def __new__(cls, filename: str) -> Self: ...
+ @property
+ def filename(self) -> str: ...
+ @filename.setter
+ def filename(self, filename: str) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Pragma:
+ def __new__(cls, name: str, arguments: Sequence[PragmaArgument], data: Optional[str]) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def arguments(self) -> List[PragmaArgument]: ...
+ @arguments.setter
+ def arguments(self, arguments: Sequence[PragmaArgument]) -> None: ...
+ @property
+ def data(self) -> Optional[str]: ...
+ @data.setter
+ def data(self, data: Optional[str]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Measurement:
+ def __new__(cls, qubit: Qubit, target: Optional[MemoryReference]) -> Self: ...
+ @property
+ def qubit(self) -> Qubit: ...
+ @qubit.setter
+ def qubit(self, qubit: Qubit) -> None: ...
+ @property
+ def target(self) -> Optional[MemoryReference]: ...
+ @target.setter
+ def target(self, target: Optional[MemoryReference]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class ParseMemoryReferenceError(ValueError):
+ """Errors that may occur while parsing a ``MemoryReference``."""
+
+class MemoryReference:
+ def __new__(cls, name: str, index: int) -> Self: ...
+ @staticmethod
+ def parse(input: str) -> MemoryReference:
+ """Parses a ``MemoryReference`` from a string.
+
+ Raises a ``ParseMemoryReference`` error if the string isn't a valid Quil memory reference.
+ """
+ ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def index(self) -> int: ...
+ @index.setter
+ def index(self, index: int) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class Load:
+ def __new__(cls, destination: MemoryReference, source: str, offset: MemoryReference) -> Self: ...
+ @property
+ def destination(self) -> MemoryReference: ...
+ @destination.setter
+ def destination(self, destination: MemoryReference) -> None: ...
+ @property
+ def source(self) -> str: ...
+ @source.setter
+ def source(self, source: str) -> None: ...
+ @property
+ def offset(self) -> MemoryReference: ...
+ @offset.setter
+ def offset(self, offset: MemoryReference) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Store:
+ def __new__(cls, destination: str, offset: MemoryReference, source: ArithmeticOperand) -> Self: ...
+ @property
+ def destination(self) -> str: ...
+ @destination.setter
+ def destination(self, destination: str) -> None: ...
+ @property
+ def offset(self) -> MemoryReference: ...
+ @offset.setter
+ def offset(self, offset: MemoryReference) -> None: ...
+ @property
+ def source(self) -> ArithmeticOperand: ...
+ @source.setter
+ def source(self, source: ArithmeticOperand) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class Waveform:
+ def __new__(cls, matrix: Sequence[Expression], parameters: Sequence[str]) -> Self: ...
+ @property
+ def matrix(self) -> List[Expression]: ...
+ @matrix.setter
+ def matrix(self, matrix: Sequence[Expression]) -> None: ...
+ @property
+ def parameters(self) -> List[str]: ...
+ @parameters.setter
+ def parameters(self, parameters: Sequence[str]) -> None: ...
+
+class WaveformDefinition:
+ def __new__(cls, name: str, definition: Waveform) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def definition(self) -> Waveform: ...
+ @definition.setter
+ def definition(self, definition: Waveform) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class WaveformInvocation:
+ def __new__(cls, name: str, parameters: Dict[str, Expression]) -> Self: ...
+ @property
+ def name(self) -> str: ...
+ @name.setter
+ def name(self, name: str) -> None: ...
+ @property
+ def parameters(self) -> Dict[str, Expression]: ...
+ @parameters.setter
+ def parameters(self, parameters: Dict[str, Expression]) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class Label:
+ def __new__(cls, target: Target) -> Self: ...
+ @property
+ def target(self) -> Target: ...
+ @target.setter
+ def target(self, target: Target) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+@final
+class Target:
+ """Represents a Quil target.
+
+ # Variants:
+ - ``fixed``: A fixed target defined by a Quil identifier
+ - ``placeholder``: A placeholder target that can be assigned a new name at a later time.
+
+ Methods (for each variant):
+ - ``is_*``: Returns ``True`` if the inner type is of that variant.
+ - ``as_*``: Returns the inner data if it is the given variant, ``None`` otherwise.
+ - ``to_*``: Returns the inner data if it is the given variant, raises ``ValueError`` otherwise.
+ - ``from_*``: Creates a new ``PragmaArgument`` using an instance of the inner type for the variant.
+ """
+
+ def __new__(cls, inner: Union[str, TargetPlaceholder]) -> Target: ...
+ @staticmethod
+ def from_fixed(inner: str) -> Target: ...
+ @staticmethod
+ def from_placeholder(inner: TargetPlaceholder) -> Target: ...
+ def is_fixed(self) -> bool: ...
+ def is_placeholder(self) -> bool: ...
+ def as_fixed(self) -> Optional[str]: ...
+ def as_placeholder(self) -> Optional[TargetPlaceholder]: ...
+ def to_fixed(self) -> str: ...
+ def to_placeholder(self) -> TargetPlaceholder: ...
+ def inner(self) -> Union[str, TargetPlaceholder]: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+
+class TargetPlaceholder:
+ """A placeholder target that must be assigned a fixed name before creating a program with valid quil.
+
+ See ``quil.program.Program#resolve_placeholders`` for more information.
+ """
+
+ def __new__(cls, base_target: str) -> Self: ...
+ @property
+ def base_label(self) -> str: ...
+
+class Jump:
+ def __new__(cls, target: Target) -> Self: ...
+ @property
+ def target(self) -> Target: ...
+ @target.setter
+ def target(self, target: Target) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class JumpWhen:
+ def __new__(cls, target: Target, condition: MemoryReference) -> Self: ...
+ @property
+ def target(self) -> Target: ...
+ @target.setter
+ def target(self, target: Target) -> None: ...
+ @property
+ def condition(self) -> MemoryReference: ...
+ @condition.setter
+ def condition(self, condition: MemoryReference) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
+
+class JumpUnless:
+ def __new__(cls, target: Target, condition: MemoryReference) -> Self: ...
+ @property
+ def target(self) -> Target: ...
+ @target.setter
+ def target(self, target: Target) -> None: ...
+ @property
+ def condition(self) -> MemoryReference: ...
+ @condition.setter
+ def condition(self, condition: MemoryReference) -> None: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def __deepcopy__(self, _: Dict) -> Self:
+ """Creates and returns a deep copy of the class.
+
+ If the instruction contains any ``QubitPlaceholder`` or ``TargetPlaceholder``, then they will be replaced with
+ new placeholders so resolving them in the copy will not resolve them in the original.
+ Should be used by passing an instance of the class to ``copy.deepcopy``
+ """
+ def __copy__(self) -> Self:
+ """Returns a shallow copy of the class."""
diff --git a/quil-py/quil/program/__init__.py b/quil-py/quil/program/__init__.py
new file mode 100644
index 00000000..bbf0cda4
--- /dev/null
+++ b/quil-py/quil/program/__init__.py
@@ -0,0 +1,3 @@
+"""The `quil.program` module contains classes for constructing and representing a Quil program."""
+
+from quil.program import *
diff --git a/quil-py/quil/program/__init__.pyi b/quil-py/quil/program/__init__.pyi
new file mode 100644
index 00000000..5478a841
--- /dev/null
+++ b/quil-py/quil/program/__init__.pyi
@@ -0,0 +1,414 @@
+from typing import Callable, Dict, FrozenSet, List, Optional, Sequence, Set, final
+
+import numpy as np
+from numpy.typing import NDArray
+from typing_extensions import Self
+
+from quil.instructions import (
+ AttributeValue,
+ Calibration,
+ Declaration,
+ FrameIdentifier,
+ Gate,
+ GateDefinition,
+ Instruction,
+ MeasureCalibrationDefinition,
+ Measurement,
+ MemoryReference,
+ Qubit,
+ QubitPlaceholder,
+ Sharing,
+ Target,
+ TargetPlaceholder,
+ Vector,
+ Waveform,
+)
+
+@final
+class Program:
+ @staticmethod
+ def __new__(cls) -> "Program": ...
+ @property
+ def body_instructions(self) -> List[Instruction]: ...
+ @property
+ def calibrations(self) -> CalibrationSet: ...
+ @calibrations.setter
+ def calibrations(self, calibration_set: CalibrationSet): ...
+ @property
+ def waveforms(self) -> Dict[str, Waveform]: ...
+ @waveforms.setter
+ def waveforms(self, waveforms: Dict[str, Waveform]): ...
+ @property
+ def gate_definitions(self) -> Dict[str, GateDefinition]: ...
+ @gate_definitions.setter
+ def gate_definitions(self, gate_definitions: Dict[str, GateDefinition]): ...
+ @property
+ def frames(self) -> FrameSet: ...
+ @frames.setter
+ def frames(self, frames: FrameSet): ...
+ @property
+ def memory_regions(self) -> Dict[str, MemoryRegion]: ...
+ @memory_regions.setter
+ def memory_regions(self, memory_regions: Dict[str, MemoryRegion]): ...
+ @property
+ def declarations(self) -> Dict[str, Declaration]: ...
+ def dagger(self) -> "Program":
+ """Creates a new conjugate transpose of the ``Program`` by reversing the order of gate instructions and applying the DAGGER modifier to each.
+
+ Raises a ``GateError`` if any of the instructions in the program are not a ``Gate`
+ """
+ ...
+ def expand_calibrations(self) -> "Program":
+ """Expand any instructions in the program which have a matching calibration, leaving the others unchanged.
+
+ Recurses though each instruction while ensuring there is no cycle in the expansion graph (i.e. no calibration
+ expands directly or indirectly into itself)
+ """
+ ...
+ def into_simplified(self) -> "Program":
+ """Simplify this program into a new `Program` which contains only instructions and definitions which are executed; effectively, perform dead code removal.
+
+ Removes:
+ - All calibrations, following calibration expansion
+ - Frame definitions which are not used by any instruction such as `PULSE` or `CAPTURE`
+ - Waveform definitions which are not used by any instruction
+
+ When a valid program is simplified, it remains valid.
+ """
+ ...
+ def get_used_qubits(self) -> Set[Qubit]:
+ """Returns a set consisting of every Qubit that is used in the program."""
+ ...
+ def add_instruction(self, instruction: Instruction):
+ """Add an instruction to the end of the program."""
+ ...
+ def add_instructions(self, instructions: Sequence[Instruction]):
+ """Add a list of instructions to the end of the program."""
+ ...
+ @staticmethod
+ def parse(input: str) -> "Program":
+ """Parses the given Quil string and returns a new ``Program``.
+
+ Raises a ``ProgramError`` if the given string isn't valid Quil.
+ """
+ def to_instructions(self) -> Sequence[Instruction]: ...
+ def to_unitary(self, n_qubits: int) -> NDArray[np.complex_]: ...
+ def copy(self) -> "Program":
+ """Creates a clone of this ``Program``."""
+ ...
+ def clone_without_body_instructions(self) -> "Program":
+ """Creates a clone of this ``Program`` with an empty body instructions list."""
+ def __add__(self, rhs: Program) -> Program: ...
+ def to_quil(self) -> str:
+ """Attempt to convert the instruction to a valid Quil string.
+
+ Raises an exception if the instruction can't be converted to valid Quil.
+ """
+ ...
+ def to_quil_or_debug(self) -> str:
+ """Convert the instruction to a Quil string.
+
+ If any part of the instruction can't be converted to valid Quil, it will be printed in a human-readable debug format.
+ """
+ def filter_instructions(self, predicate: Callable[[Instruction], bool]) -> "Program":
+ """Return a new ``Program`` containing only the instructions for which ``predicate`` returns ``True``."""
+ ...
+ def wrap_in_loop(
+ self, loop_count_reference: MemoryReference, start_target: Target, end_target: Target, iterations: int
+ ) -> "Program":
+ """Return a copy of the `Program` wrapped in a loop that repeats ``iterations`` times.
+
+ The loop is constructed by wrapping the body of the program in classical Quil instructions.
+ The given ``loop_count_reference`` must refer to an INTEGER memory region. The value at the
+ reference given will be set to ``iterations`` and decremented in the loop. The loop will
+ terminate when the reference reaches 0. For this reason your program should not itself
+ modify the value at the reference unless you intend to modify the remaining number of
+ iterations (i.e. to break the loop).
+
+ The given ``start_target`` and ``end_target`` will be used as the entry and exit points for
+ the loop, respectively. You should provide unique `quil.instructions.Target`s that won't be
+ used elsewhere in the program.
+
+ If `iterations` is 0, then a copy of the program is returned without any changes. Raises a
+ `TypeError` if `iterations` is negative.
+ """
+ ...
+ def resolve_placeholders(self) -> None:
+ """Resolve ``TargetPlaceholder``s and ``QubitPlaceholder``s within the program using default resolvers.
+
+ The default resolver will be used to generate a unique value for that placeholder within the scope of
+ the program using an auto-incrementing value (for qubit) or suffix (for target)
+ while ensuring that unique value is not already in use within the program.
+ """
+ ...
+ def resolve_placeholders_with_custom_resolvers(
+ self,
+ *,
+ target_resolver: Optional[Callable[[TargetPlaceholder], Optional[str]]] = None,
+ qubit_resolver: Optional[Callable[[QubitPlaceholder], Optional[int]]] = None,
+ ):
+ """Resolve ``TargetPlaceholder``s and ``QubitPlaceholder``s within the program.
+
+ The resolved values will remain unique to that placeholder within the scope of the program.
+
+ If you provide ``target_resolver`` and/or ``qubit_resolver``, those will be used to resolve those values respectively.
+ If your resolver returns `None` for a particular placeholder, it will not be replaced but will be left as a placeholder.
+
+ If you do not provide a resolver for a placeholder, a default resolver will be used which will generate a unique value
+ for that placeholder within the scope of the program using an auto-incrementing value (for qubit) or suffix (for target)
+ while ensuring that unique value is not already in use within the program.
+ """
+ ...
+ def control_flow_graph(self) -> "ControlFlowGraph":
+ """Return the `control flow graph`_ of the program.
+
+ .. _control flow graph: https://en.wikipedia.org/wiki/Control-flow_graph
+ """
+
+class BasicBlock:
+ def __new__(cls, instance: "BasicBlock") -> Self:
+ """Create a new instance of a `BasicBlock` (or a subclass) using an existing instance."""
+
+ def as_schedule_seconds(self, program: Program) -> ScheduleSeconds:
+ """Return the ``ScheduleSeconds`` representing the timing of the instructions within the block.
+
+ * Expanding each instruction within the block using the program's calibration definitions
+ * Resolving the `ScheduleSeconds` of the expanded instructions
+ * Mapping calibrated instructions back to the original instructions within this block, such that the
+ block's instruction is represented as a timespan encompassing all of its expanded instructions
+
+ :param program: The program containing the calibrations to be used to schedule this block. Generally,
+ this should be the program from which the block was extracted.
+
+ Important note: If the basic block contains gates, the program must contain corresponding `DEFCAL`s for those gates.
+ Gates do not inherently have durations, but rather inherit them from the `PULSE`, `CAPTURE`, `DELAY`,
+ and other instructions within their calibrations. Without a calibration, a gate's duration cannot be computed.
+
+ The following example demonstrates construction of such a schedule for a simple program without explicit control
+ flow (and thus with only one basic block):
+
+ .. example-code::
+
+ .. code-block:: python
+
+ from quil.program import Program
+
+ program = Program.parse("CZ 0 1; CZ 0 2")
+
+ print(program.to_quil())
+
+ control_flow_graph = program.control_flow_graph()
+ assert control_flow_graph.has_dynamic_control_flow() == False
+
+ basic_blocks = control_flow_graph.basic_blocks()
+ assert len(basic_blocks) == 1
+
+ schedule = blocks[0].as_schedule_seconds(program)
+ print(f"Duration = {schedule.duration()}")
+
+ print(schedule.items())
+
+
+ Note: when an instruction is expanded, the "time" of that original instruction includes
+ the times of all of the resulting instructions. This may cause gate times to be
+ longer than a user might expect.
+
+ To understand why, consider a program like this:
+
+ .. example-code::
+
+ .. code-block:: text
+
+ # One-qubit frame
+ DEFFRAME 0 "a":
+ ATTRIBUTE: 1
+
+ # Two-qubit frame
+ DEFFRAME 0 1 "b":
+ ATTRIBUTE: 1
+
+ DEFCAL A 0:
+ PULSE 0 "a" flat(duration: 1.0)
+
+ DEFCAL B 0 1:
+ FENCE 1
+ PULSE 0 1 "b" flat(duration: 1.0)
+
+ A 0
+ B 0 1
+
+ `B 0` will be scheduled from time 0 to time 2, because its inner `FENCE` is scheduled for time 0.
+ This may be unexpected if the user expects to see only the timing of the inner `PULSE`.
+ """
+ def gate_depth(self, gate_minimum_qubit_count: int) -> int:
+ """Returns the length of the longest path from an initial instruction (one with no prerequisite instructions) to a final instruction (one with no dependent instructions), where the length of a path is the number of gate instructions in the path.
+
+ :param gate_minimum_qubit_count: The minimum number of qubits in a gate for it to be counted in the depth.
+ """
+ def label(self) -> Optional[Target]:
+ """Return the label of the block, if any. This is used to target this block in control flow."""
+ def instructions(self) -> List[Instruction]:
+ """Return a list of the instructions in the block, in order of definition.
+
+ This does not include the label or terminator instructions.
+ """
+ def terminator(self) -> Optional[Instruction]:
+ """Return the control flow terminator instruction of the block, if any.
+
+ If this is ``None``, the implicit behavior is to "continue" to the subsequent block.
+ """
+
+@final
+class CalibrationSet:
+ @staticmethod
+ def __new__(
+ cls,
+ calibrations: Sequence[Calibration],
+ measure_calibration_definitions: Sequence[MeasureCalibrationDefinition],
+ ) -> "CalibrationSet": ...
+ @property
+ def calibrations(self) -> List[Calibration]: ...
+ @property
+ def measure_calibrations(self) -> List[MeasureCalibrationDefinition]: ...
+ def expand(self, instruction: Instruction, previous_calibrations: Sequence[Instruction]) -> List[Instruction]:
+ """Given an instruction, return the instructions to which it is expanded if there is a match.
+
+ Recursively calibrate instructions, returning an error if a calibration directly or indirectly
+ expands into itself.
+ """
+ ...
+
+ def get_match_for_measurement(self, measurement: Measurement) -> Optional[MeasureCalibrationDefinition]:
+ """Returns the last-specified ``MeasureCalibrationDefinition`` that matches the target qubit (if any), or otherwise the last-specified one that specified no qubit."""
+ ...
+ def get_match_for_gate(self, gate: Gate) -> Optional[Calibration]:
+ """Return the final calibration which matches the gate per the QuilT specification.
+
+ A calibration matches a gate if:
+ 1. It has the same name
+ 2. It has the same modifiers
+ 3. It has the same qubit count (any mix of fixed & variable)
+ 4. It has the same parameter count (both specified and unspecified)
+ 5. All fixed qubits in the calibration definition match those in the gate
+ 6. All specified parameters in the calibration definition match those in the gate
+ """
+ def __len__(self) -> int: ...
+ def is_empty(self) -> bool:
+ """Returns ``True`` if the ``CalibrationSet`` contains no data."""
+ ...
+ def insert_calibration(self, calibration: Calibration) -> Optional[Calibration]:
+ """Insert another ``Calibration`` (`DEFCAL`) to the set.
+
+ If a calibration with the same name already exists, it is overwritten and this
+ function returns the previous calibration. Otherwise, None is returned.
+ """
+ ...
+ def insert_measurement_calibration(
+ self, calibration: MeasureCalibrationDefinition
+ ) -> Optional[MeasureCalibrationDefinition]:
+ """Add another ``MeasureCalibrationDefinition`` (`DEFCAL MEASURE`) to the set.
+
+ If a calibration with the same name already exists, it is overwritten and this
+ function returns the previous calibration. Otherwise, None is returned.
+ """
+ def extend(self, other: CalibrationSet):
+ """Append another [`CalibrationSet`] onto this one."""
+ ...
+ def to_instructions(self):
+ """Return the Quil instructions which describe the contained calibrations."""
+ ...
+
+class ScheduleSecondsItem:
+ """A single item within a fixed schedule, representing a single instruction within a basic block."""
+
+ @property
+ def instruction_index(self) -> int:
+ """The index of the instruction within the basic block."""
+ @property
+ def time_span(self) -> TimeSpanSeconds:
+ """The time span during which the instruction is scheduled."""
+
+class ControlFlowGraph:
+ """Representation of a control flow graph (CFG) for a Quil program.
+
+ The CFG is a directed graph where each node is a basic block and each edge is a control flow
+ transition between two basic blocks.
+ """
+ def __new__(cls, instance: "ControlFlowGraph") -> Self:
+ """Create a new instance of a `ControlFlowGraph` (or a subclass) using an existing instance."""
+
+ def has_dynamic_control_flow(self) -> bool:
+ """Return ``True`` if the program has dynamic control flow, i.e. contains a conditional branch instruction.
+
+ ``False`` does not imply that there is only one basic block in the program. Multiple basic blocks may have
+ non-conditional control flow among them, in which the execution order is deterministic and does not depend
+ on program state. This may be a sequence of basic blocks with fixed `JUMP`s or without explicit terminators.
+ """
+ def basic_blocks(self) -> List["BasicBlock"]:
+ """Return a list of all the basic blocks in the control flow graph, in order of definition."""
+
+class ScheduleSeconds:
+ def items(self) -> List[ScheduleSecondsItem]:
+ """All the items in the schedule, in unspecified order."""
+ def duration(self) -> float:
+ """The duration of the schedule, in seconds.
+
+ This is the maximum of the end time of all the items.
+ """
+
+class TimeSpanSeconds:
+ """Representation of a time span in seconds."""
+
+ @property
+ def start(self) -> float:
+ """The start time of the time span, in seconds.
+
+ This is relative to the start of the scheduling context (such as the basic block).
+ """
+ @property
+ def duration(self) -> float:
+ """The duration of the time span, in seconds."""
+ @property
+ def end(self) -> float:
+ """The end time of the time span, in seconds.
+
+ This is the sum of the start time and duration.
+ """
+
+@final
+class FrameSet:
+ @staticmethod
+ def __new__(cls) -> "FrameSet": ...
+ def get(self, identifier: FrameIdentifier) -> Optional[Dict[str, AttributeValue]]:
+ """Retrieve the attributes of a frame by its identifier."""
+ ...
+ def get_keys(self) -> List[FrameIdentifier]:
+ """Return a list of all ``FrameIdentifier``s described by this ``FrameSet``."""
+ ...
+ def insert(self, identifier: FrameIdentifier, attributes: Dict[str, AttributeValue]):
+ """Insert a new ``FrameIdentifier``, overwriting any existing one."""
+ ...
+ def merge(self, other: FrameSet):
+ """Merge another ``FrameSet`` into this one, overwriting any existing keys."""
+ def intersection(self, identifiers: FrozenSet[FrameIdentifier]) -> "FrameSet":
+ """Return a new ``FrameSet`` which describes only the given ``FrameIdentifier``s."""
+ ...
+ def is_empty(self) -> bool:
+ """Returns ``True`` if this ``FrameSet`` defines no frames."""
+ ...
+ def to_instructions(self) -> List[Instruction]:
+ """Return the Quil instructions which define the contained frames."""
+ ...
+ def get_all_frames(self) -> Dict[FrameIdentifier, Dict[str, AttributeValue]]: ...
+
+class MemoryRegion:
+ @staticmethod
+ def __new__(cls, size: Vector, sharing: Optional[Sharing]) -> "MemoryRegion": ...
+ @property
+ def size(self) -> Vector: ...
+ @size.setter
+ def size(self, size: Vector): ...
+ @property
+ def sharing(self) -> Optional[Sharing]: ...
+ @sharing.setter
+ def sharing(self, sharing: Optional[Sharing]): ...
diff --git a/quil-py/quil/py.typed b/quil-py/quil/py.typed
new file mode 100644
index 00000000..e69de29b
diff --git a/quil-py/quil/validation/__init__.py b/quil-py/quil/validation/__init__.py
new file mode 100644
index 00000000..9a7d29a9
--- /dev/null
+++ b/quil-py/quil/validation/__init__.py
@@ -0,0 +1,3 @@
+"""The `quil.validation` module contains classes and functions that can validate components of a Quil program or instruction."""
+
+from quil.validation import *
diff --git a/quil-py/quil/validation/__init__.pyi b/quil-py/quil/validation/__init__.pyi
new file mode 100644
index 00000000..bd850da7
--- /dev/null
+++ b/quil-py/quil/validation/__init__.pyi
@@ -0,0 +1 @@
+from . import identifier as identifier
diff --git a/quil-py/quil/validation/identifier.py b/quil-py/quil/validation/identifier.py
new file mode 100644
index 00000000..e7271869
--- /dev/null
+++ b/quil-py/quil/validation/identifier.py
@@ -0,0 +1 @@
+from quil.validation.identifier import *
diff --git a/quil-py/quil/validation/identifier.pyi b/quil-py/quil/validation/identifier.pyi
new file mode 100644
index 00000000..16950278
--- /dev/null
+++ b/quil-py/quil/validation/identifier.pyi
@@ -0,0 +1,12 @@
+class IdentifierValidationError(ValueError):
+ """Errors that may occur when validating a Quil identifier."""
+
+ ...
+
+def validate_identifier(ident: str):
+ """Raises an ``IdentifierValidationError` if ident isn't a valid Quil identifier."""
+ ...
+
+def validate_user_identifier(ident: str):
+ """Raises an ``IdentifierValidationError` if ident is reserved keyword or isn't a valid Quil identifier."""
+ ...
diff --git a/quil-py/src/expression.rs b/quil-py/src/expression.rs
new file mode 100644
index 00000000..60a60f96
--- /dev/null
+++ b/quil-py/src/expression.rs
@@ -0,0 +1,230 @@
+use std::collections::HashMap;
+
+use quil_rs::expression::{
+ Expression, ExpressionFunction, FunctionCallExpression, InfixExpression, InfixOperator,
+ PrefixExpression, PrefixOperator,
+};
+
+use rigetti_pyo3::{
+ create_init_submodule, impl_from_str, impl_hash, impl_parse, impl_repr, impl_str,
+ num_complex::Complex64,
+ py_wrap_data_struct, py_wrap_error, py_wrap_simple_enum, py_wrap_union_enum,
+ pyo3::{
+ exceptions::PyValueError,
+ pymethods,
+ types::{PyComplex, PyString},
+ Py, PyResult, Python,
+ },
+ wrap_error, PyTryFrom, PyWrapper, PyWrapperMut, ToPython, ToPythonError,
+};
+
+use crate::{impl_eq, impl_to_quil, instruction::PyMemoryReference};
+
+wrap_error!(RustEvaluationError(quil_rs::expression::EvaluationError));
+py_wrap_error!(quil, RustEvaluationError, EvaluationError, PyValueError);
+wrap_error!(RustParseExpressionError(quil_rs::program::ParseProgramError));
+py_wrap_error!(
+ quil,
+ RustParseExpressionError,
+ ParseExpressionError,
+ PyValueError
+);
+
+py_wrap_union_enum! {
+ #[derive(Debug, Hash, PartialEq, Eq)]
+ #[pyo3(module="quil.expression")]
+ PyExpression(Expression) as "Expression" {
+ address: Address => PyMemoryReference,
+ function_call: FunctionCall => PyFunctionCallExpression,
+ infix: Infix => PyInfixExpression,
+ number: Number => Py,
+ pi: PiConstant,
+ prefix: Prefix => PyPrefixExpression,
+ variable: Variable => Py
+ }
+}
+impl_repr!(PyExpression);
+impl_to_quil!(PyExpression);
+impl_from_str!(PyExpression, RustParseExpressionError);
+impl_hash!(PyExpression);
+impl_parse!(PyExpression);
+impl_eq!(PyExpression);
+
+#[pymethods]
+impl PyExpression {
+ pub fn simplify(&mut self) {
+ self.as_inner_mut().simplify()
+ }
+
+ pub fn into_simplified(&self, py: Python<'_>) -> PyResult {
+ self.as_inner().clone().into_simplified().to_python(py)
+ }
+
+ pub fn evaluate(
+ &self,
+ variables: HashMap,
+ memory_references: HashMap<&str, Vec>,
+ ) -> PyResult {
+ self.as_inner()
+ .evaluate(&variables, &memory_references)
+ .map_err(RustEvaluationError::from)
+ .map_err(RustEvaluationError::to_py_err)
+ }
+
+ pub fn substitute_variables(
+ &self,
+ py: Python<'_>,
+ variable_values: HashMap,
+ ) -> PyResult {
+ Ok(PyExpression(self.as_inner().clone().substitute_variables(
+ &HashMap::::py_try_from(py, &variable_values)?,
+ )))
+ }
+
+ pub fn to_real(&self) -> PyResult {
+ self.as_inner()
+ .to_real()
+ .map_err(RustEvaluationError::from)
+ .map_err(RustEvaluationError::to_py_err)
+ }
+
+ pub fn __add__(&self, other: PyExpression) -> Self {
+ PyExpression(self.as_inner().clone() + other.as_inner().clone())
+ }
+
+ pub fn __sub__(&self, other: PyExpression) -> Self {
+ PyExpression(self.as_inner().clone() - other.as_inner().clone())
+ }
+
+ pub fn __mul__(&self, other: PyExpression) -> Self {
+ PyExpression(self.as_inner().clone() * other.as_inner().clone())
+ }
+
+ pub fn __truediv__(&self, other: PyExpression) -> Self {
+ PyExpression(self.as_inner().clone() / other.as_inner().clone())
+ }
+}
+
+py_wrap_data_struct! {
+ #[pyo3(subclass)]
+ #[derive(Debug)]
+ PyFunctionCallExpression(FunctionCallExpression) as "FunctionCallExpression" {
+ function: ExpressionFunction => PyExpressionFunction,
+ expression: Box => PyExpression
+ }
+}
+impl_repr!(PyFunctionCallExpression);
+
+#[pymethods]
+impl PyFunctionCallExpression {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ function: PyExpressionFunction,
+ expression: PyExpression,
+ ) -> PyResult {
+ Ok(PyFunctionCallExpression(FunctionCallExpression::new(
+ ExpressionFunction::py_try_from(py, &function)?,
+ Box::::py_try_from(py, &expression)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug)]
+ #[pyo3(subclass)]
+ PyInfixExpression(InfixExpression) as "InfixExpression" {
+ left: Box => PyExpression,
+ operator: InfixOperator => PyInfixOperator,
+ right: Box => PyExpression
+ }
+}
+impl_repr!(PyInfixExpression);
+
+#[pymethods]
+impl PyInfixExpression {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ left: PyExpression,
+ operator: PyInfixOperator,
+ right: PyExpression,
+ ) -> PyResult {
+ Ok(PyInfixExpression(InfixExpression::new(
+ Box::::py_try_from(py, &left)?,
+ InfixOperator::py_try_from(py, &operator)?,
+ Box::::py_try_from(py, &right)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug)]
+ #[pyo3(subclass)]
+ PyPrefixExpression(PrefixExpression) as "PrefixExpression" {
+ operator: PrefixOperator => PyPrefixOperator,
+ expression: Box => PyExpression
+ }
+}
+
+#[pymethods]
+impl PyPrefixExpression {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ operator: PyPrefixOperator,
+ expression: PyExpression,
+ ) -> PyResult {
+ Ok(PyPrefixExpression(PrefixExpression::new(
+ PrefixOperator::py_try_from(py, &operator)?,
+ Box::::py_try_from(py, &expression)?,
+ )))
+ }
+}
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq, Eq, Hash)]
+ PyExpressionFunction(ExpressionFunction) as "ExpressionFunction" {
+ Cis,
+ Cosine,
+ Exponent,
+ Sine,
+ SquareRoot
+ }
+}
+impl_repr!(PyExpressionFunction);
+impl_str!(PyExpressionFunction);
+impl_hash!(PyExpressionFunction);
+impl_eq!(PyExpressionFunction);
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq, Eq, Hash)]
+ PyPrefixOperator(PrefixOperator) as "PrefixOperator" {
+ Plus,
+ Minus
+ }
+}
+impl_repr!(PyPrefixOperator);
+impl_str!(PyPrefixOperator);
+impl_hash!(PyPrefixOperator);
+impl_eq!(PyPrefixOperator);
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq, Eq, Hash)]
+ PyInfixOperator(InfixOperator) as "InfixOperator" {
+ Caret,
+ Plus,
+ Minus,
+ Slash,
+ Star
+ }
+}
+impl_repr!(PyInfixOperator);
+impl_str!(PyInfixOperator);
+impl_hash!(PyInfixOperator);
+impl_eq!(PyInfixOperator);
+
+create_init_submodule! {
+ classes: [PyExpression, PyFunctionCallExpression, PyInfixExpression, PyPrefixExpression, PyExpressionFunction, PyPrefixOperator, PyInfixOperator],
+ errors: [EvaluationError, ParseExpressionError],
+}
diff --git a/quil-py/src/instruction/calibration.rs b/quil-py/src/instruction/calibration.rs
new file mode 100644
index 00000000..146211c0
--- /dev/null
+++ b/quil-py/src/instruction/calibration.rs
@@ -0,0 +1,90 @@
+use quil_rs::{
+ expression::Expression,
+ instruction::{Calibration, GateModifier, Instruction, MeasureCalibrationDefinition, Qubit},
+};
+
+use rigetti_pyo3::{
+ impl_repr, py_wrap_data_struct,
+ pyo3::{pymethods, types::PyString, Py, PyResult, Python},
+ PyTryFrom, ToPythonError,
+};
+
+use crate::{
+ expression::PyExpression,
+ impl_copy_for_instruction, impl_eq, impl_to_quil,
+ instruction::{PyGateModifier, PyInstruction, PyQubit},
+ validation::identifier::RustIdentifierValidationError,
+};
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyCalibration(Calibration) as "Calibration" {
+ instructions: Vec => Vec,
+ modifiers: Vec => Vec,
+ name: String => Py,
+ parameters: Vec => Vec,
+ qubits: Vec => Vec
+ }
+}
+impl_repr!(PyCalibration);
+impl_to_quil!(PyCalibration);
+impl_copy_for_instruction!(PyCalibration);
+impl_eq!(PyCalibration);
+
+#[pymethods]
+impl PyCalibration {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ name: &str,
+ parameters: Vec,
+ qubits: Vec,
+ instructions: Vec,
+ modifiers: Vec,
+ ) -> PyResult {
+ Ok(Self(
+ Calibration::new(
+ name,
+ Vec::::py_try_from(py, ¶meters)?,
+ Vec::::py_try_from(py, &qubits)?,
+ Vec::::py_try_from(py, &instructions)?,
+ Vec::::py_try_from(py, &modifiers)?,
+ )
+ .map_err(RustIdentifierValidationError::from)
+ .map_err(RustIdentifierValidationError::to_py_err)?,
+ ))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyMeasureCalibrationDefinition(MeasureCalibrationDefinition) as "MeasureCalibrationDefinition" {
+ qubit: Option => Option,
+ parameter: String => Py,
+ instructions: Vec => Vec
+ }
+}
+impl_repr!(PyMeasureCalibrationDefinition);
+impl_to_quil!(PyMeasureCalibrationDefinition);
+impl_copy_for_instruction!(PyMeasureCalibrationDefinition);
+impl_eq!(PyMeasureCalibrationDefinition);
+
+#[pymethods]
+impl PyMeasureCalibrationDefinition {
+ #[new]
+ #[pyo3(signature = (qubit, parameter, instructions))]
+ pub fn new(
+ py: Python<'_>,
+ qubit: Option,
+ parameter: String,
+ instructions: Vec,
+ ) -> PyResult {
+ Ok(Self(MeasureCalibrationDefinition::new(
+ Option::::py_try_from(py, &qubit)?,
+ parameter,
+ Vec::::py_try_from(py, &instructions)?,
+ )))
+ }
+}
diff --git a/quil-py/src/instruction/circuit.rs b/quil-py/src/instruction/circuit.rs
new file mode 100644
index 00000000..5e2599a2
--- /dev/null
+++ b/quil-py/src/instruction/circuit.rs
@@ -0,0 +1,44 @@
+use quil_rs::instruction::{CircuitDefinition, Instruction};
+
+use rigetti_pyo3::{
+ impl_repr, py_wrap_data_struct,
+ pyo3::{pymethods, types::PyString, Py, PyResult, Python},
+ PyTryFrom,
+};
+
+use super::PyInstruction;
+use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil};
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyCircuitDefinition(CircuitDefinition) as "CircuitDefinition" {
+ name: String => Py,
+ parameters: Vec => Vec>,
+ qubit_variables: Vec => Vec>,
+ instructions: Vec => Vec
+ }
+}
+impl_repr!(PyCircuitDefinition);
+impl_to_quil!(PyCircuitDefinition);
+impl_copy_for_instruction!(PyCircuitDefinition);
+impl_eq!(PyCircuitDefinition);
+
+#[pymethods]
+impl PyCircuitDefinition {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ name: String,
+ parameters: Vec,
+ qubit_variables: Vec,
+ instructions: Vec,
+ ) -> PyResult {
+ Ok(Self(CircuitDefinition::new(
+ name,
+ parameters,
+ qubit_variables,
+ Vec::::py_try_from(py, &instructions)?,
+ )))
+ }
+}
diff --git a/quil-py/src/instruction/classical.rs b/quil-py/src/instruction/classical.rs
new file mode 100644
index 00000000..1ca692b4
--- /dev/null
+++ b/quil-py/src/instruction/classical.rs
@@ -0,0 +1,415 @@
+use quil_rs::instruction::{
+ Arithmetic, ArithmeticOperand, ArithmeticOperator, BinaryLogic, BinaryOperand, BinaryOperands,
+ BinaryOperator, Comparison, ComparisonOperand, ComparisonOperator, Convert, Exchange,
+ MemoryReference, Move, UnaryLogic, UnaryOperator,
+};
+
+use rigetti_pyo3::{
+ impl_as_mut_for_wrapper, impl_hash, impl_repr, py_wrap_data_struct, py_wrap_simple_enum,
+ py_wrap_type, py_wrap_union_enum,
+ pyo3::{
+ pymethods,
+ types::{PyFloat, PyInt},
+ Py, PyResult, Python,
+ },
+ PyTryFrom, PyWrapper, PyWrapperMut, ToPython,
+};
+
+use super::PyMemoryReference;
+use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil};
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyArithmetic(Arithmetic) as "Arithmetic" {
+ operator: ArithmeticOperator => PyArithmeticOperator,
+ destination: ArithmeticOperand => PyArithmeticOperand,
+ source: ArithmeticOperand => PyArithmeticOperand
+ }
+}
+impl_repr!(PyArithmetic);
+impl_to_quil!(PyArithmetic);
+impl_copy_for_instruction!(PyArithmetic);
+impl_hash!(PyArithmetic);
+impl_eq!(PyArithmetic);
+
+#[pymethods]
+impl PyArithmetic {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ operator: PyArithmeticOperator,
+ destination: PyArithmeticOperand,
+ source: PyArithmeticOperand,
+ ) -> PyResult {
+ Ok(PyArithmetic(Arithmetic::new(
+ ArithmeticOperator::py_try_from(py, &operator)?,
+ ArithmeticOperand::py_try_from(py, &destination)?,
+ ArithmeticOperand::py_try_from(py, &source)?,
+ )))
+ }
+}
+
+py_wrap_union_enum! {
+ #[derive(Debug, PartialEq)]
+ PyArithmeticOperand(ArithmeticOperand) as "ArithmeticOperand" {
+ literal_integer: LiteralInteger => Py,
+ literal_real: LiteralReal => Py,
+ memory_reference: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyArithmeticOperand);
+impl_to_quil!(PyArithmeticOperand);
+impl_hash!(PyArithmeticOperand);
+impl_eq!(PyArithmeticOperand);
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq)]
+ PyArithmeticOperator(ArithmeticOperator) as "ArithmeticOperator" {
+ Add,
+ Subtract,
+ Divide,
+ Multiply
+ }
+}
+impl_repr!(PyArithmeticOperator);
+impl_to_quil!(PyArithmeticOperator);
+impl_hash!(PyArithmeticOperator);
+impl_eq!(PyArithmeticOperator);
+
+py_wrap_union_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyBinaryOperand(BinaryOperand) as "BinaryOperand" {
+ literal_integer: LiteralInteger => Py,
+ memory_reference: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyBinaryOperand);
+impl_to_quil!(PyBinaryOperand);
+impl_hash!(PyBinaryOperand);
+impl_eq!(PyBinaryOperand);
+
+py_wrap_type! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyBinaryOperands(BinaryOperands) as "BinaryOperands"
+}
+impl_repr!(PyBinaryOperands);
+impl_hash!(PyBinaryOperands);
+impl_as_mut_for_wrapper!(PyBinaryOperands);
+impl_eq!(PyBinaryOperands);
+
+#[pymethods]
+impl PyBinaryOperands {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ memory_reference: PyMemoryReference,
+ operand: PyBinaryOperand,
+ ) -> PyResult {
+ Ok(Self((
+ MemoryReference::py_try_from(py, &memory_reference)?,
+ BinaryOperand::py_try_from(py, &operand)?,
+ )))
+ }
+
+ #[getter]
+ pub fn get_memory_reference(&self, py: Python<'_>) -> PyResult {
+ self.as_inner().0.to_python(py)
+ }
+
+ #[setter]
+ pub fn set_memory_reference(
+ &mut self,
+ py: Python<'_>,
+ memory_reference: PyMemoryReference,
+ ) -> PyResult<()> {
+ self.as_inner_mut().0 = MemoryReference::py_try_from(py, &memory_reference)?;
+ Ok(())
+ }
+
+ #[getter]
+ pub fn get_operand(&self, py: Python<'_>) -> PyResult {
+ self.as_inner().1.to_python(py)
+ }
+
+ #[setter]
+ pub fn set_operand(&mut self, py: Python<'_>, binary_operand: PyBinaryOperand) -> PyResult<()> {
+ self.as_inner_mut().1 = BinaryOperand::py_try_from(py, &binary_operand)?;
+ Ok(())
+ }
+}
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyBinaryOperator(BinaryOperator) as "BinaryOperator" {
+ And,
+ Ior,
+ Xor
+ }
+}
+impl_repr!(PyBinaryOperator);
+impl_to_quil!(PyBinaryOperator);
+impl_hash!(PyBinaryOperator);
+impl_eq!(PyBinaryOperator);
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyBinaryLogic(BinaryLogic) as "BinaryLogic" {
+ operator: BinaryOperator => PyBinaryOperator,
+ operands: BinaryOperands => PyBinaryOperands
+ }
+}
+impl_repr!(PyBinaryLogic);
+impl_to_quil!(PyBinaryLogic);
+impl_copy_for_instruction!(PyBinaryLogic);
+impl_eq!(PyBinaryLogic);
+
+#[pymethods]
+impl PyBinaryLogic {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ operator: PyBinaryOperator,
+ operands: PyBinaryOperands,
+ ) -> PyResult {
+ Ok(PyBinaryLogic(BinaryLogic::new(
+ BinaryOperator::py_try_from(py, &operator)?,
+ BinaryOperands::py_try_from(py, &operands)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyConvert(Convert) as "Convert" {
+ destination: MemoryReference => PyMemoryReference,
+ source: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyConvert);
+impl_to_quil!(PyConvert);
+impl_copy_for_instruction!(PyConvert);
+impl_hash!(PyConvert);
+impl_eq!(PyConvert);
+
+#[pymethods]
+impl PyConvert {
+ #[new]
+ fn new(
+ py: Python<'_>,
+ destination: PyMemoryReference,
+ source: PyMemoryReference,
+ ) -> PyResult {
+ Ok(Self(Convert::new(
+ MemoryReference::py_try_from(py, &destination)?,
+ MemoryReference::py_try_from(py, &source)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyMove(Move) as "Move" {
+ destination: MemoryReference => PyMemoryReference,
+ source: ArithmeticOperand => PyArithmeticOperand
+ }
+}
+impl_repr!(PyMove);
+impl_to_quil!(PyMove);
+impl_copy_for_instruction!(PyMove);
+impl_hash!(PyMove);
+impl_eq!(PyMove);
+
+#[pymethods]
+impl PyMove {
+ #[new]
+ fn new(
+ py: Python<'_>,
+ destination: PyMemoryReference,
+ source: PyArithmeticOperand,
+ ) -> PyResult {
+ Ok(Self(Move::new(
+ MemoryReference::py_try_from(py, &destination)?,
+ ArithmeticOperand::py_try_from(py, &source)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyExchange(Exchange) as "Exchange" {
+ left: MemoryReference => PyMemoryReference,
+ right: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyExchange);
+impl_to_quil!(PyExchange);
+impl_copy_for_instruction!(PyExchange);
+impl_hash!(PyExchange);
+impl_eq!(PyExchange);
+
+#[pymethods]
+impl PyExchange {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ left: PyMemoryReference,
+ right: PyMemoryReference,
+ ) -> PyResult {
+ Ok(Self(Exchange::new(
+ MemoryReference::py_try_from(py, &left)?,
+ MemoryReference::py_try_from(py, &right)?,
+ )))
+ }
+}
+
+py_wrap_union_enum! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyComparisonOperand(ComparisonOperand) as "ComparisonOperand" {
+ literal_integer: LiteralInteger => Py,
+ literal_real: LiteralReal => Py,
+ memory_reference: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyComparisonOperand);
+impl_to_quil!(PyComparisonOperand);
+impl_hash!(PyComparisonOperand);
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyComparisonOperator(ComparisonOperator) as "ComparisonOperator" {
+ Equal,
+ GreaterThanOrEqual,
+ GreaterThan,
+ LessThanOrEqual,
+ LessThan
+ }
+}
+
+type RustComparisonOperands = (MemoryReference, MemoryReference, ComparisonOperand);
+
+// This is a helper type to manage easy conversion of the inner tuple
+// with the macros. It should not be exposed directly.
+py_wrap_type! {
+ PyComparisonOperands(RustComparisonOperands)
+}
+
+impl PyComparisonOperands {
+ pub(crate) fn from_py_tuple(
+ py: Python<'_>,
+ tuple: (PyMemoryReference, PyMemoryReference, PyComparisonOperand),
+ ) -> PyResult {
+ Ok(Self((
+ MemoryReference::py_try_from(py, &tuple.0)?,
+ MemoryReference::py_try_from(py, &tuple.1)?,
+ ComparisonOperand::py_try_from(py, &tuple.2)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyComparison(Comparison) as "Comparison" {
+ operator: ComparisonOperator => PyComparisonOperator,
+ operands: RustComparisonOperands => PyComparisonOperands
+ }
+}
+impl_repr!(PyComparison);
+impl_to_quil!(PyComparison);
+impl_copy_for_instruction!(PyComparison);
+impl_hash!(PyComparison);
+impl_eq!(PyComparison);
+
+#[pymethods]
+impl PyComparison {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ operator: PyComparisonOperator,
+ operands: (PyMemoryReference, PyMemoryReference, PyComparisonOperand),
+ ) -> PyResult {
+ Ok(Self(Comparison::new(
+ ComparisonOperator::py_try_from(py, &operator)?,
+ RustComparisonOperands::py_try_from(
+ py,
+ &PyComparisonOperands::from_py_tuple(py, operands)?,
+ )?,
+ )))
+ }
+
+ // Override the getters/setters generated by [`py_wrap_data_struct!`] so that they
+ // return/take tuples instead of the wrapping [`PyComparisonOperands`] type.
+ #[getter(operands)]
+ fn get_operands_as_tuple(
+ &self,
+ py: Python<'_>,
+ ) -> PyResult<(PyMemoryReference, PyMemoryReference, PyComparisonOperand)> {
+ let operands = &self.as_inner().operands;
+ Ok((
+ operands.0.to_python(py)?,
+ operands.1.to_python(py)?,
+ operands.2.to_python(py)?,
+ ))
+ }
+
+ #[setter(operands)]
+ fn set_operands_from_tuple(
+ &mut self,
+ py: Python<'_>,
+ operands: (PyMemoryReference, PyMemoryReference, PyComparisonOperand),
+ ) -> PyResult<()> {
+ self.as_inner_mut().operands = RustComparisonOperands::py_try_from(
+ py,
+ &PyComparisonOperands::from_py_tuple(py, operands)?,
+ )?;
+ Ok(())
+ }
+}
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyUnaryOperator(UnaryOperator) as "UnaryOperator" {
+ Neg,
+ Not
+ }
+}
+impl_repr!(PyUnaryOperator);
+impl_to_quil!(PyUnaryOperator);
+impl_hash!(PyUnaryOperator);
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyUnaryLogic(UnaryLogic) as "UnaryLogic" {
+ operator: UnaryOperator => PyUnaryOperator,
+ operand: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyUnaryLogic);
+impl_to_quil!(PyUnaryLogic);
+impl_copy_for_instruction!(PyUnaryLogic);
+impl_hash!(PyUnaryLogic);
+impl_eq!(PyUnaryLogic);
+
+#[pymethods]
+impl PyUnaryLogic {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ operator: PyUnaryOperator,
+ operand: PyMemoryReference,
+ ) -> PyResult {
+ Ok(Self(UnaryLogic::new(
+ UnaryOperator::py_try_from(py, &operator)?,
+ MemoryReference::py_try_from(py, &operand)?,
+ )))
+ }
+}
diff --git a/quil-py/src/instruction/control_flow.rs b/quil-py/src/instruction/control_flow.rs
new file mode 100644
index 00000000..d694a504
--- /dev/null
+++ b/quil-py/src/instruction/control_flow.rs
@@ -0,0 +1,157 @@
+use quil_rs::instruction::{
+ Jump, JumpUnless, JumpWhen, Label, MemoryReference, Target, TargetPlaceholder,
+};
+use rigetti_pyo3::{
+ impl_compare, impl_hash, impl_repr, py_wrap_data_struct, py_wrap_type, py_wrap_union_enum,
+ pyo3::{pymethods, types::PyString, Py},
+ PyWrapper,
+};
+
+use crate::{impl_eq, impl_to_quil, instruction::PyMemoryReference};
+
+/// Implements __copy__ and __deepcopy__ for instructions containing a [`Target`].
+///
+/// __copy__ implements a shallow copy by returning a reference to the object.
+///
+/// __deepcopy__ performs a deep copy by cloning the Rust reference, and replacing
+/// any [`TargetPlaceholder`]s from the original intruction with new instances so
+/// that resolving placeholders on the copy does not affect the original.
+macro_rules! impl_copy_for_target_containing_instructions {
+ ($name: ident) => {
+ #[pyo3::pymethods]
+ impl $name {
+ pub fn __copy__(&self) -> Self {
+ self.clone()
+ }
+
+ pub fn __deepcopy__(&self, _memo: &pyo3::types::PyDict) -> Self {
+ use quil_rs::instruction::{Target, TargetPlaceholder};
+ let mut copy = rigetti_pyo3::PyWrapper::into_inner(self.clone());
+ if let Target::Placeholder(placeholder) = copy.target {
+ copy.target = Target::Placeholder(TargetPlaceholder::new(
+ placeholder.as_inner().to_string(),
+ ))
+ }
+
+ Self(copy)
+ }
+ }
+ };
+}
+
+py_wrap_data_struct! {
+ #[pyo3(subclass)]
+ #[derive(Debug, Hash, PartialEq, Eq)]
+ PyLabel(Label) as "Label" {
+ target: Target => PyTarget
+ }
+}
+impl_repr!(PyLabel);
+impl_hash!(PyLabel);
+impl_to_quil!(PyLabel);
+impl_copy_for_target_containing_instructions!(PyLabel);
+impl_eq!(PyLabel);
+
+#[pymethods]
+impl PyLabel {
+ #[new]
+ fn new(target: PyTarget) -> Self {
+ PyLabel(Label::new(target.into_inner()))
+ }
+}
+
+py_wrap_union_enum! {
+ #[derive(Debug, Hash, PartialEq, Eq)]
+ PyTarget(Target) as "Target" {
+ fixed: Fixed => Py,
+ placeholder: Placeholder => PyTargetPlaceholder
+ }
+}
+impl_repr!(PyTarget);
+impl_hash!(PyTarget);
+impl_to_quil!(PyTarget);
+impl_eq!(PyTarget);
+
+py_wrap_type! {
+ #[pyo3(subclass)]
+ #[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
+ PyTargetPlaceholder(TargetPlaceholder) as "TargetPlaceholder"
+}
+impl_repr!(PyTargetPlaceholder);
+impl_hash!(PyTargetPlaceholder);
+impl_compare!(PyTargetPlaceholder);
+
+#[pymethods]
+impl PyTargetPlaceholder {
+ #[new]
+ pub fn new(base_label: String) -> Self {
+ Self(TargetPlaceholder::new(base_label))
+ }
+
+ #[getter]
+ pub fn base_label(&self) -> &str {
+ PyWrapper::as_inner(self).as_inner()
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyJump(Jump) as "Jump" {
+ target: Target => PyTarget
+ }
+}
+impl_repr!(PyJump);
+impl_to_quil!(PyJump);
+impl_copy_for_target_containing_instructions!(PyJump);
+impl_eq!(PyJump);
+
+#[pymethods]
+impl PyJump {
+ #[new]
+ fn new(target: PyTarget) -> Self {
+ Self(Jump::new(target.into_inner()))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyJumpWhen(JumpWhen) as "JumpWhen" {
+ target: Target => PyTarget,
+ condition: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyJumpWhen);
+impl_to_quil!(PyJumpWhen);
+impl_copy_for_target_containing_instructions!(PyJumpWhen);
+impl_eq!(PyJumpWhen);
+
+#[pymethods]
+impl PyJumpWhen {
+ #[new]
+ fn new(target: PyTarget, condition: PyMemoryReference) -> Self {
+ Self(JumpWhen::new(target.into_inner(), condition.into_inner()))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyJumpUnless(JumpUnless) as "JumpUnless" {
+ target: Target => PyTarget,
+ condition: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyJumpUnless);
+impl_to_quil!(PyJumpUnless);
+impl_copy_for_target_containing_instructions!(PyJumpUnless);
+impl_eq!(PyJumpUnless);
+
+#[pymethods]
+impl PyJumpUnless {
+ #[new]
+ fn new(target: PyTarget, condition: PyMemoryReference) -> Self {
+ Self(JumpUnless::new(target.into_inner(), condition.into_inner()))
+ }
+}
diff --git a/quil-py/src/instruction/declaration.rs b/quil-py/src/instruction/declaration.rs
new file mode 100644
index 00000000..2e88d722
--- /dev/null
+++ b/quil-py/src/instruction/declaration.rs
@@ -0,0 +1,229 @@
+use quil_rs::instruction::{
+ ArithmeticOperand, Declaration, Load, MemoryReference, Offset, ScalarType, Sharing, Store,
+ Vector,
+};
+
+use super::PyArithmeticOperand;
+use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil};
+
+use rigetti_pyo3::{
+ impl_from_str, impl_hash, impl_parse, impl_repr, py_wrap_data_struct, py_wrap_error,
+ py_wrap_simple_enum,
+ pyo3::{
+ exceptions::PyValueError,
+ pymethods,
+ types::{PyInt, PyString},
+ Py, PyResult, Python,
+ },
+ wrap_error, PyTryFrom,
+};
+
+wrap_error!(RustParseMemoryReferenceError(quil_rs::program::SyntaxError));
+py_wrap_error!(
+ quil,
+ RustParseMemoryReferenceError,
+ ParseMemoryReferenceError,
+ PyValueError
+);
+
+py_wrap_simple_enum! {
+ PyScalarType(ScalarType) as "ScalarType" {
+ Bit,
+ Integer,
+ Octet,
+ Real
+ }
+}
+impl_repr!(PyScalarType);
+impl_to_quil!(PyScalarType);
+impl_hash!(PyScalarType);
+
+py_wrap_data_struct! {
+ #[derive(Debug, Hash, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyVector(Vector) as "Vector" {
+ data_type: ScalarType => PyScalarType,
+ length: u64 => Py
+ }
+}
+impl_repr!(PyVector);
+impl_to_quil!(PyVector);
+impl_hash!(PyVector);
+impl_eq!(PyVector);
+
+#[pymethods]
+impl PyVector {
+ #[new]
+ pub fn new(py: Python<'_>, data_type: PyScalarType, length: u64) -> PyResult {
+ Ok(Self(Vector::new(
+ ScalarType::py_try_from(py, &data_type)?,
+ length,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq, Hash)]
+ #[pyo3(subclass)]
+ PyOffset(Offset) as "Offset" {
+ offset: u64 => Py,
+ data_type: ScalarType => PyScalarType
+ }
+}
+impl_repr!(PyOffset);
+impl_to_quil!(PyOffset);
+impl_hash!(PyOffset);
+impl_eq!(PyOffset);
+
+#[pymethods]
+impl PyOffset {
+ #[new]
+ pub fn new(py: Python<'_>, offset: u64, data_type: PyScalarType) -> PyResult {
+ Ok(Self(Offset::new(
+ offset,
+ ScalarType::py_try_from(py, &data_type)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq, Hash)]
+ #[pyo3(subclass)]
+ PySharing(Sharing) as "Sharing" {
+ name: String => Py,
+ offsets: Vec => Vec
+ }
+}
+impl_repr!(PySharing);
+impl_hash!(PySharing);
+impl_eq!(PySharing);
+
+#[pymethods]
+impl PySharing {
+ #[new]
+ pub fn new(py: Python<'_>, name: String, offsets: Vec) -> PyResult {
+ Ok(Self(Sharing::new(
+ name,
+ Vec::::py_try_from(py, &offsets)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyDeclaration(Declaration) as "Declaration" {
+ name: String => Py,
+ size: Vector => PyVector,
+ sharing: Option => Option
+ }
+}
+impl_repr!(PyDeclaration);
+impl_to_quil!(PyDeclaration);
+impl_copy_for_instruction!(PyDeclaration);
+impl_hash!(PyDeclaration);
+impl_eq!(PyDeclaration);
+
+#[pymethods]
+impl PyDeclaration {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ name: String,
+ size: PyVector,
+ sharing: Option,
+ ) -> PyResult {
+ Ok(Self(Declaration::new(
+ name,
+ Vector::py_try_from(py, &size)?,
+ Option::::py_try_from(py, &sharing)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, Hash, PartialEq)]
+ #[pyo3(subclass)]
+ PyMemoryReference(MemoryReference) as "MemoryReference" {
+ name: String => Py,
+ index: u64 => Py
+ }
+}
+impl_hash!(PyMemoryReference);
+impl_repr!(PyMemoryReference);
+impl_to_quil!(PyMemoryReference);
+impl_from_str!(PyMemoryReference, RustParseMemoryReferenceError);
+impl_parse!(PyMemoryReference);
+impl_eq!(PyMemoryReference);
+
+#[pymethods]
+impl PyMemoryReference {
+ #[new]
+ pub fn new(name: String, index: u64) -> Self {
+ Self(MemoryReference::new(name, index))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyLoad(Load) as "Load" {
+ destination: MemoryReference => PyMemoryReference,
+ source: String => Py,
+ offset: MemoryReference => PyMemoryReference
+ }
+}
+impl_repr!(PyLoad);
+impl_to_quil!(PyLoad);
+impl_copy_for_instruction!(PyLoad);
+impl_hash!(PyLoad);
+impl_eq!(PyLoad);
+
+#[pymethods]
+impl PyLoad {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ destination: PyMemoryReference,
+ source: String,
+ offset: PyMemoryReference,
+ ) -> PyResult {
+ Ok(Self(Load::new(
+ MemoryReference::py_try_from(py, &destination)?,
+ source,
+ MemoryReference::py_try_from(py, &offset)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq)]
+ #[pyo3(subclass)]
+ PyStore(Store) as "Store" {
+ destination: String => Py,
+ offset: MemoryReference => PyMemoryReference,
+ source: ArithmeticOperand => PyArithmeticOperand
+ }
+}
+impl_repr!(PyStore);
+impl_to_quil!(PyStore);
+impl_copy_for_instruction!(PyStore);
+impl_hash!(PyStore);
+impl_eq!(PyStore);
+
+#[pymethods]
+impl PyStore {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ destination: String,
+ offset: PyMemoryReference,
+ source: PyArithmeticOperand,
+ ) -> PyResult {
+ Ok(Self(Store::new(
+ destination,
+ MemoryReference::py_try_from(py, &offset)?,
+ ArithmeticOperand::py_try_from(py, &source)?,
+ )))
+ }
+}
diff --git a/quil-py/src/instruction/frame.rs b/quil-py/src/instruction/frame.rs
new file mode 100644
index 00000000..487aef66
--- /dev/null
+++ b/quil-py/src/instruction/frame.rs
@@ -0,0 +1,357 @@
+use std::hash::Hash;
+
+use indexmap::IndexMap;
+
+use quil_rs::{
+ expression::Expression,
+ instruction::{
+ AttributeValue, Capture, FrameAttributes, FrameDefinition, FrameIdentifier,
+ MemoryReference, Pulse, Qubit, RawCapture, SetFrequency, SetPhase, SetScale,
+ ShiftFrequency, ShiftPhase, SwapPhases, WaveformInvocation,
+ },
+};
+use rigetti_pyo3::{
+ impl_hash, impl_repr, py_wrap_data_struct, py_wrap_union_enum,
+ pyo3::{
+ pymethods,
+ types::{PyBool, PyString},
+ Py, PyResult, Python,
+ },
+ PyTryFrom,
+};
+
+use super::PyQubit;
+use crate::{
+ expression::PyExpression,
+ impl_copy_for_instruction, impl_eq, impl_to_quil,
+ instruction::{PyMemoryReference, PyWaveformInvocation},
+};
+
+py_wrap_union_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyAttributeValue(AttributeValue) as "AttributeValue" {
+ string: String => Py,
+ expression: Expression => PyExpression
+ }
+}
+impl_repr!(PyAttributeValue);
+impl_to_quil!(PyAttributeValue);
+impl_hash!(PyAttributeValue);
+impl_eq!(PyAttributeValue);
+
+pub type PyFrameAttributes = IndexMap;
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyFrameDefinition(FrameDefinition) as "FrameDefinition" {
+ identifier: FrameIdentifier => PyFrameIdentifier,
+ attributes: FrameAttributes => PyFrameAttributes
+ }
+}
+impl_repr!(PyFrameDefinition);
+impl_to_quil!(PyFrameDefinition);
+impl_copy_for_instruction!(PyFrameDefinition);
+impl_eq!(PyFrameDefinition);
+
+#[pymethods]
+impl PyFrameDefinition {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ identifier: PyFrameIdentifier,
+ attributes: PyFrameAttributes,
+ ) -> PyResult {
+ Ok(Self(FrameDefinition::new(
+ FrameIdentifier::py_try_from(py, &identifier)?,
+ FrameAttributes::py_try_from(py, &attributes)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq, Hash)]
+ #[pyo3(subclass)]
+ PyFrameIdentifier(FrameIdentifier) as "FrameIdentifier" {
+ name: String => Py,
+ qubits: Vec => Vec
+ }
+}
+impl_repr!(PyFrameIdentifier);
+impl_to_quil!(PyFrameIdentifier);
+impl_hash!(PyFrameIdentifier);
+impl_eq!(PyFrameIdentifier);
+
+#[pymethods]
+impl PyFrameIdentifier {
+ #[new]
+ pub fn new(py: Python<'_>, name: String, qubits: Vec) -> PyResult {
+ Ok(Self(FrameIdentifier::new(
+ name,
+ Vec::::py_try_from(py, &qubits)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyCapture(Capture) as "Capture" {
+ blocking: bool => Py,
+ frame: FrameIdentifier => PyFrameIdentifier,
+ memory_reference: MemoryReference => PyMemoryReference,
+ waveform: WaveformInvocation => PyWaveformInvocation
+ }
+}
+impl_repr!(PyCapture);
+impl_to_quil!(PyCapture);
+impl_copy_for_instruction!(PyCapture);
+impl_eq!(PyCapture);
+
+#[pymethods]
+impl PyCapture {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ blocking: bool,
+ frame: PyFrameIdentifier,
+ memory_reference: PyMemoryReference,
+ waveform: PyWaveformInvocation,
+ ) -> PyResult {
+ Ok(Self(Capture::new(
+ blocking,
+ FrameIdentifier::py_try_from(py, &frame)?,
+ MemoryReference::py_try_from(py, &memory_reference)?,
+ WaveformInvocation::py_try_from(py, &waveform)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyPulse(Pulse) as "Pulse" {
+ blocking: bool => Py,
+ frame: FrameIdentifier => PyFrameIdentifier,
+ waveform: WaveformInvocation => PyWaveformInvocation
+ }
+}
+impl_repr!(PyPulse);
+impl_to_quil!(PyPulse);
+impl_copy_for_instruction!(PyPulse);
+impl_eq!(PyPulse);
+
+#[pymethods]
+impl PyPulse {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ blocking: bool,
+ frame: PyFrameIdentifier,
+ waveform: PyWaveformInvocation,
+ ) -> PyResult {
+ Ok(Self(Pulse::new(
+ blocking,
+ FrameIdentifier::py_try_from(py, &frame)?,
+ WaveformInvocation::py_try_from(py, &waveform)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyRawCapture(RawCapture) as "RawCapture" {
+ blocking: bool => Py,
+ frame: FrameIdentifier => PyFrameIdentifier,
+ duration: Expression => PyExpression,
+ memory_reference: MemoryReference => PyMemoryReference
+ }
+}
+
+impl_repr!(PyRawCapture);
+impl_to_quil!(PyRawCapture);
+impl_copy_for_instruction!(PyRawCapture);
+impl_hash!(PyRawCapture);
+impl_eq!(PyRawCapture);
+
+#[pymethods]
+impl PyRawCapture {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ blocking: bool,
+ frame: PyFrameIdentifier,
+ duration: PyExpression,
+ memory_reference: PyMemoryReference,
+ ) -> PyResult {
+ Ok(Self(RawCapture::new(
+ blocking,
+ FrameIdentifier::py_try_from(py, &frame)?,
+ Expression::py_try_from(py, &duration)?,
+ MemoryReference::py_try_from(py, &memory_reference)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PySetFrequency(SetFrequency) as "SetFrequency" {
+ frame: FrameIdentifier => PyFrameIdentifier,
+ frequency: Expression => PyExpression
+ }
+}
+impl_repr!(PySetFrequency);
+impl_to_quil!(PySetFrequency);
+impl_copy_for_instruction!(PySetFrequency);
+impl_hash!(PySetFrequency);
+impl_eq!(PySetFrequency);
+
+#[pymethods]
+impl PySetFrequency {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ frame: PyFrameIdentifier,
+ frequency: PyExpression,
+ ) -> PyResult {
+ Ok(Self(SetFrequency::new(
+ FrameIdentifier::py_try_from(py, &frame)?,
+ Expression::py_try_from(py, &frequency)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PySetPhase(SetPhase) as "SetPhase" {
+ frame: FrameIdentifier => PyFrameIdentifier,
+ phase: Expression => PyExpression
+ }
+}
+impl_repr!(PySetPhase);
+impl_to_quil!(PySetPhase);
+impl_copy_for_instruction!(PySetPhase);
+impl_hash!(PySetPhase);
+impl_eq!(PySetPhase);
+
+#[pymethods]
+impl PySetPhase {
+ #[new]
+ pub fn new(py: Python<'_>, frame: PyFrameIdentifier, phase: PyExpression) -> PyResult {
+ Ok(Self(SetPhase::new(
+ FrameIdentifier::py_try_from(py, &frame)?,
+ Expression::py_try_from(py, &phase)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PySetScale(SetScale) as "SetScale" {
+ frame: FrameIdentifier => PyFrameIdentifier,
+ scale: Expression => PyExpression
+ }
+}
+impl_repr!(PySetScale);
+impl_to_quil!(PySetScale);
+impl_copy_for_instruction!(PySetScale);
+impl_hash!(PySetScale);
+impl_eq!(PySetScale);
+
+#[pymethods]
+impl PySetScale {
+ #[new]
+ pub fn new(py: Python<'_>, frame: PyFrameIdentifier, scale: PyExpression) -> PyResult {
+ Ok(Self(SetScale::new(
+ FrameIdentifier::py_try_from(py, &frame)?,
+ Expression::py_try_from(py, &scale)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyShiftFrequency(ShiftFrequency) as "ShiftFrequency" {
+ frame: FrameIdentifier => PyFrameIdentifier,
+ frequency: Expression => PyExpression
+ }
+}
+impl_repr!(PyShiftFrequency);
+impl_to_quil!(PyShiftFrequency);
+impl_copy_for_instruction!(PyShiftFrequency);
+impl_hash!(PyShiftFrequency);
+impl_eq!(PyShiftFrequency);
+
+#[pymethods]
+impl PyShiftFrequency {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ frame: PyFrameIdentifier,
+ frequency: PyExpression,
+ ) -> PyResult {
+ Ok(Self(ShiftFrequency::new(
+ FrameIdentifier::py_try_from(py, &frame)?,
+ Expression::py_try_from(py, &frequency)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyShiftPhase(ShiftPhase) as "ShiftPhase" {
+ frame: FrameIdentifier => PyFrameIdentifier,
+ phase: Expression => PyExpression
+ }
+}
+impl_repr!(PyShiftPhase);
+impl_to_quil!(PyShiftPhase);
+impl_copy_for_instruction!(PyShiftPhase);
+impl_hash!(PyShiftPhase);
+impl_eq!(PyShiftPhase);
+
+#[pymethods]
+impl PyShiftPhase {
+ #[new]
+ pub fn new(py: Python<'_>, frame: PyFrameIdentifier, phase: PyExpression) -> PyResult {
+ Ok(Self(ShiftPhase::new(
+ FrameIdentifier::py_try_from(py, &frame)?,
+ Expression::py_try_from(py, &phase)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PySwapPhases(SwapPhases) as "SwapPhases" {
+ frame_1: FrameIdentifier => PyFrameIdentifier,
+ frame_2: FrameIdentifier => PyFrameIdentifier
+ }
+}
+impl_repr!(PySwapPhases);
+impl_to_quil!(PySwapPhases);
+impl_copy_for_instruction!(PySwapPhases);
+impl_hash!(PySwapPhases);
+impl_eq!(PySwapPhases);
+
+#[pymethods]
+impl PySwapPhases {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ frame_1: PyFrameIdentifier,
+ frame_2: PyFrameIdentifier,
+ ) -> PyResult {
+ Ok(Self(SwapPhases::new(
+ FrameIdentifier::py_try_from(py, &frame_1)?,
+ FrameIdentifier::py_try_from(py, &frame_2)?,
+ )))
+ }
+}
diff --git a/quil-py/src/instruction/gate.rs b/quil-py/src/instruction/gate.rs
new file mode 100644
index 00000000..3d35f280
--- /dev/null
+++ b/quil-py/src/instruction/gate.rs
@@ -0,0 +1,294 @@
+use numpy::{PyArray2, ToPyArray};
+use quil_rs::{
+ expression::Expression,
+ instruction::{
+ Gate, GateDefinition, GateModifier, GateSpecification, PauliGate, PauliSum, PauliTerm,
+ Qubit,
+ },
+};
+use rigetti_pyo3::{
+ impl_from_str, impl_hash, impl_parse, impl_repr, impl_str,
+ num_complex::Complex64,
+ py_wrap_data_struct, py_wrap_error, py_wrap_simple_enum, py_wrap_type, py_wrap_union_enum,
+ pyo3::{
+ exceptions::PyValueError,
+ pymethods,
+ types::{PyInt, PyString},
+ Py, PyErr, PyResult, Python,
+ },
+ wrap_error, PyTryFrom, PyWrapper, PyWrapperMut, ToPython, ToPythonError,
+};
+use strum;
+
+use crate::{
+ expression::PyExpression, impl_copy_for_instruction, impl_eq, impl_to_quil,
+ instruction::PyQubit,
+};
+
+wrap_error!(RustGateError(quil_rs::instruction::GateError));
+py_wrap_error!(quil, RustGateError, GateError, PyValueError);
+wrap_error!(RustParseEnumError(strum::ParseError));
+py_wrap_error!(quil, RustParseEnumError, EnumParseError, PyValueError);
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyGate(Gate) as "Gate" {
+ name: String => Py,
+ parameters: Vec => Vec,
+ qubits: Vec => Vec,
+ modifiers: Vec => Vec
+ }
+}
+impl_repr!(PyGate);
+impl_copy_for_instruction!(PyGate);
+impl_to_quil!(PyGate);
+impl_hash!(PyGate);
+impl_eq!(PyGate);
+
+#[pymethods]
+impl PyGate {
+ #[new]
+ fn new(
+ py: Python<'_>,
+ name: String,
+ parameters: Vec,
+ qubits: Vec,
+ modifiers: Vec,
+ ) -> PyResult {
+ Ok(Self(
+ Gate::new(
+ &name,
+ Vec::::py_try_from(py, ¶meters)?,
+ Vec::::py_try_from(py, &qubits)?,
+ Vec::::py_try_from(py, &modifiers)?,
+ )
+ .map_err(RustGateError::from)
+ .map_err(RustGateError::to_py_err)?,
+ ))
+ }
+
+ fn dagger(&self, py: Python<'_>) -> PyResult {
+ self.as_inner().clone().dagger().to_python(py)
+ }
+
+ fn controlled(&self, py: Python<'_>, control_qubit: PyQubit) -> PyResult {
+ self.as_inner()
+ .clone()
+ .controlled(Qubit::py_try_from(py, &control_qubit)?)
+ .to_python(py)
+ }
+
+ fn forked(
+ &self,
+ py: Python<'_>,
+ fork_qubit: PyQubit,
+ alt_params: Vec,
+ ) -> PyResult {
+ self.as_inner()
+ .clone()
+ .forked(
+ Qubit::py_try_from(py, &fork_qubit)?,
+ Vec::::py_try_from(py, &alt_params)?,
+ )
+ .map_err(RustGateError::from)
+ .map_err(RustGateError::to_py_err)?
+ .to_python(py)
+ }
+
+ fn to_unitary_mut(
+ &mut self,
+ py: Python<'_>,
+ n_qubits: u64,
+ ) -> PyResult>> {
+ Ok(self
+ .as_inner_mut()
+ .to_unitary(n_qubits)
+ .map_err(RustGateError::from)
+ .map_err(RustGateError::to_py_err)?
+ .to_pyarray(py)
+ .to_owned())
+ }
+}
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyGateModifier(GateModifier) as "GateModifier" {
+ Controlled,
+ Dagger,
+ Forked
+ }
+}
+impl_repr!(PyGateModifier);
+impl_to_quil!(PyGateModifier);
+impl_hash!(PyGateModifier);
+impl_eq!(PyGateModifier);
+
+py_wrap_simple_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyPauliGate(PauliGate) as "PauliGate" {
+ I,
+ X,
+ Y,
+ Z
+ }
+}
+impl_repr!(PyPauliGate);
+impl_str!(PyPauliGate);
+impl_hash!(PyPauliGate);
+impl_from_str!(PyPauliGate, RustParseEnumError);
+impl_parse!(PyPauliGate);
+
+// This is a helper type to help manage easy conversion of the inner tuple
+// with the macros. It should not be exposed directly.
+py_wrap_type! {
+ PyPauliPair((PauliGate, String))
+}
+
+impl PyPauliPair {
+ pub(crate) fn from_py_tuple(py: Python<'_>, tuple: (PyPauliGate, String)) -> PyResult {
+ Ok(Self((PauliGate::py_try_from(py, &tuple.0)?, tuple.1)))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyPauliTerm(PauliTerm) as "PauliTerm" {
+ arguments: Vec<(PauliGate, String)> => Vec,
+ expression: Expression => PyExpression
+ }
+}
+
+#[pymethods]
+impl PyPauliTerm {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ arguments: Vec<(PyPauliGate, String)>,
+ expression: PyExpression,
+ ) -> PyResult {
+ Ok(Self(PauliTerm::new(
+ Vec::<(PauliGate, String)>::py_try_from(
+ py,
+ &PyPauliTerm::py_pairs_from_tuples(py, arguments)?,
+ )?,
+ Expression::py_try_from(py, &expression)?,
+ )))
+ }
+
+ // Override the getters/setters generated by [`py_wrap_data_struct!`] so that they
+ // return/take tuples instead of the wrapping [`PyPauliPair`] type.
+ #[getter(arguments)]
+ fn get_arguments_as_tuple(&self, py: Python<'_>) -> PyResult> {
+ let mut pairs: Vec<(PyPauliGate, String)> =
+ Vec::with_capacity(self.as_inner().arguments.len());
+ self.as_inner()
+ .arguments
+ .iter()
+ .try_for_each(|(gate, arg)| {
+ pairs.push((gate.to_python(py)?, arg.clone()));
+ Ok::<(), PyErr>(())
+ })?;
+ Ok(pairs)
+ }
+
+ #[setter(arguments)]
+ fn set_arguments_from_tuple(
+ &mut self,
+ py: Python<'_>,
+ arguments: Vec<(PyPauliGate, String)>,
+ ) -> PyResult<()> {
+ self.as_inner_mut().arguments = Vec::<(PauliGate, String)>::py_try_from(
+ py,
+ &PyPauliTerm::py_pairs_from_tuples(py, arguments)?,
+ )?;
+ Ok(())
+ }
+}
+
+impl PyPauliTerm {
+ pub(crate) fn py_pairs_from_tuples(
+ py: Python<'_>,
+ tuples: Vec<(PyPauliGate, String)>,
+ ) -> PyResult> {
+ let mut pairs: Vec = Vec::with_capacity(tuples.len());
+ tuples.into_iter().try_for_each(|tuple| {
+ pairs.push(PyPauliPair::from_py_tuple(py, tuple)?);
+ Ok::<(), PyErr>(())
+ })?;
+ Ok(pairs)
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyPauliSum(PauliSum) as "PauliSum" {
+ arguments: Vec => Vec>,
+ terms: Vec => Vec
+ }
+}
+impl_repr!(PyPauliSum);
+impl_eq!(PyPauliSum);
+
+#[pymethods]
+impl PyPauliSum {
+ #[new]
+ pub fn new(py: Python<'_>, arguments: Vec, terms: Vec) -> PyResult {
+ Ok(Self(
+ PauliSum::new(arguments, Vec::::py_try_from(py, &terms)?)
+ .map_err(RustGateError::from)
+ .map_err(RustGateError::to_py_err)?,
+ ))
+ }
+}
+
+py_wrap_union_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyGateSpecification(GateSpecification) as "GateSpecification" {
+ matrix: Matrix => Vec>,
+ permutation: Permutation => Vec>,
+ pauli_sum: PauliSum => PyPauliSum
+ }
+}
+impl_repr!(PyGateSpecification);
+impl_to_quil!(PyGateSpecification);
+impl_hash!(PyGateSpecification);
+impl_eq!(PyGateSpecification);
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyGateDefinition(GateDefinition) as "GateDefinition" {
+ name: String => Py,
+ parameters: Vec => Vec>,
+ specification: GateSpecification => PyGateSpecification
+ }
+}
+impl_repr!(PyGateDefinition);
+impl_to_quil!(PyGateDefinition);
+impl_copy_for_instruction!(PyGateDefinition);
+impl_hash!(PyGateDefinition);
+impl_eq!(PyGateDefinition);
+
+#[pymethods]
+impl PyGateDefinition {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ name: String,
+ parameters: Vec,
+ specification: PyGateSpecification,
+ ) -> PyResult {
+ Ok(Self(
+ GateDefinition::new(
+ name,
+ parameters,
+ GateSpecification::py_try_from(py, &specification)?,
+ )
+ .map_err(RustGateError::from)
+ .map_err(RustGateError::to_py_err)?,
+ ))
+ }
+}
diff --git a/quil-py/src/instruction/measurement.rs b/quil-py/src/instruction/measurement.rs
new file mode 100644
index 00000000..ea13ea8a
--- /dev/null
+++ b/quil-py/src/instruction/measurement.rs
@@ -0,0 +1,40 @@
+use quil_rs::instruction::{Measurement, MemoryReference, Qubit};
+use rigetti_pyo3::{
+ impl_hash, impl_repr, py_wrap_data_struct,
+ pyo3::{pymethods, PyResult, Python},
+ PyTryFrom,
+};
+
+use crate::{
+ impl_copy_for_instruction, impl_eq, impl_to_quil,
+ instruction::{PyMemoryReference, PyQubit},
+};
+
+py_wrap_data_struct! {
+ #[pyo3(subclass)]
+ #[derive(Debug, PartialEq, Eq)]
+ PyMeasurement(Measurement) as "Measurement" {
+ qubit: Qubit => PyQubit,
+ target: Option => Option
+ }
+}
+impl_to_quil!(PyMeasurement);
+impl_copy_for_instruction!(PyMeasurement);
+impl_hash!(PyMeasurement);
+impl_repr!(PyMeasurement);
+impl_eq!(PyMeasurement);
+
+#[pymethods]
+impl PyMeasurement {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ qubit: PyQubit,
+ target: Option,
+ ) -> PyResult {
+ Ok(Self(Measurement::new(
+ Qubit::py_try_from(py, &qubit)?,
+ Option::::py_try_from(py, &target)?,
+ )))
+ }
+}
diff --git a/quil-py/src/instruction/mod.rs b/quil-py/src/instruction/mod.rs
new file mode 100644
index 00000000..bb2c4ba7
--- /dev/null
+++ b/quil-py/src/instruction/mod.rs
@@ -0,0 +1,257 @@
+use quil_rs::instruction::Instruction;
+use rigetti_pyo3::{
+ create_init_submodule, impl_repr, py_wrap_union_enum,
+ pyo3::{pymethods, types::PyDict, PyResult, Python},
+ PyWrapper,
+};
+
+use crate::{impl_eq, impl_to_quil};
+
+pub use self::{
+ calibration::{PyCalibration, PyMeasureCalibrationDefinition},
+ circuit::PyCircuitDefinition,
+ classical::{
+ PyArithmetic, PyArithmeticOperand, PyArithmeticOperator, PyBinaryLogic, PyBinaryOperand,
+ PyBinaryOperands, PyBinaryOperator, PyComparison, PyComparisonOperand,
+ PyComparisonOperator, PyConvert, PyExchange, PyMove, PyUnaryLogic, PyUnaryOperator,
+ },
+ control_flow::{PyJump, PyJumpUnless, PyJumpWhen, PyLabel, PyTarget, PyTargetPlaceholder},
+ declaration::{
+ ParseMemoryReferenceError, PyDeclaration, PyLoad, PyMemoryReference, PyOffset,
+ PyScalarType, PySharing, PyStore, PyVector,
+ },
+ frame::{
+ PyAttributeValue, PyCapture, PyFrameAttributes, PyFrameDefinition, PyFrameIdentifier,
+ PyPulse, PyRawCapture, PySetFrequency, PySetPhase, PySetScale, PyShiftFrequency,
+ PyShiftPhase, PySwapPhases,
+ },
+ gate::{
+ GateError, PyGate, PyGateDefinition, PyGateModifier, PyGateSpecification, PyPauliGate,
+ PyPauliSum, PyPauliTerm,
+ },
+ measurement::PyMeasurement,
+ pragma::{PyInclude, PyPragma, PyPragmaArgument},
+ qubit::{PyQubit, PyQubitPlaceholder},
+ reset::PyReset,
+ timing::{PyDelay, PyFence},
+ waveform::{PyWaveform, PyWaveformDefinition, PyWaveformInvocation},
+};
+
+mod calibration;
+mod circuit;
+mod classical;
+mod control_flow;
+mod declaration;
+mod frame;
+mod gate;
+mod measurement;
+mod pragma;
+mod qubit;
+mod reset;
+mod timing;
+mod waveform;
+
+py_wrap_union_enum! {
+ #[derive(Debug, PartialEq)]
+ PyInstruction(Instruction) as "Instruction" {
+ arithmetic: Arithmetic => PyArithmetic,
+ binary_logic: BinaryLogic => PyBinaryLogic,
+ calibration_definition: CalibrationDefinition => PyCalibration,
+ capture: Capture => PyCapture,
+ circuit_definition: CircuitDefinition => PyCircuitDefinition,
+ convert: Convert => PyConvert,
+ comparison: Comparison => PyComparison,
+ declaration: Declaration => PyDeclaration,
+ delay: Delay => PyDelay,
+ exchange: Exchange => PyExchange,
+ fence: Fence => PyFence,
+ frame_definition: FrameDefinition => PyFrameDefinition,
+ gate: Gate => PyGate,
+ gate_definition: GateDefinition => PyGateDefinition,
+ halt: Halt,
+ include: Include => PyInclude,
+ jump: Jump => PyJump,
+ jump_when: JumpWhen => PyJumpWhen,
+ jump_unless: JumpUnless => PyJumpUnless,
+ label: Label => PyLabel,
+ load: Load => PyLoad,
+ measure_calibration_definition: MeasureCalibrationDefinition => PyMeasureCalibrationDefinition,
+ measurement: Measurement => PyMeasurement,
+ move: Move => PyMove,
+ nop: Nop,
+ pragma: Pragma => PyPragma,
+ pulse: Pulse => PyPulse,
+ raw_capture: RawCapture => PyRawCapture,
+ reset: Reset => PyReset,
+ set_frequency: SetFrequency => PySetFrequency,
+ set_phase: SetPhase => PySetPhase,
+ set_scale: SetScale => PySetScale,
+ shift_frequency: ShiftFrequency => PyShiftFrequency,
+ shift_phase: ShiftPhase => PyShiftPhase,
+ store: Store => PyStore,
+ swap_phases: SwapPhases => PySwapPhases,
+ unary_logic: UnaryLogic => PyUnaryLogic,
+ waveform_definition: WaveformDefinition => PyWaveformDefinition,
+ wait: Wait
+ }
+}
+impl_repr!(PyInstruction);
+impl_to_quil!(PyInstruction);
+impl_eq!(PyInstruction);
+
+#[pymethods]
+impl PyInstruction {
+ pub fn is_quil_t(&self) -> bool {
+ self.as_inner().is_quil_t()
+ }
+
+ // Implement the __copy__ and __deepcopy__ dunder methods, which are used by Python's
+ // `copy` module.
+ //
+ // If the instruction contains some inner data, then the implementation for __deepcopy__
+ // is delegated to that inner type so that each type can define its own copy behavior.
+ // This comes with the caveat that this implementation will error if the inner type doesn't
+ // implement __deepcopy__ itself. See [`impl_copy_for_instruction!`] for an easy way to
+ // implement these methods on any variant of [`PyInstruction`].
+ pub fn __copy__(&self) -> Self {
+ self.clone()
+ }
+
+ pub fn __deepcopy__(&self, py: Python<'_>, memo: &PyDict) -> PyResult {
+ match self.inner(py) {
+ Ok(inner) => Ok(PyInstruction::new(
+ py,
+ inner.call_method1(py, "__deepcopy__", (memo,))?.as_ref(py),
+ )?),
+ Err(_) => Ok(self.clone()), // No inner data implies this is a simple instruction, safe to
+ // just clone.
+ }
+ }
+}
+
+create_init_submodule! {
+ classes: [
+ PyInstruction,
+ PyArithmetic,
+ PyArithmeticOperand,
+ PyArithmeticOperator,
+ PyBinaryLogic,
+ PyBinaryOperand,
+ PyBinaryOperands,
+ PyBinaryOperator,
+ PyComparison,
+ PyComparisonOperand,
+ PyComparisonOperator,
+ PyConvert,
+ PyExchange,
+ PyMove,
+ PyUnaryLogic,
+ PyUnaryOperator,
+ PyCalibration,
+ PyCircuitDefinition,
+ PyMeasureCalibrationDefinition,
+ PyDeclaration,
+ PyLoad,
+ PyOffset,
+ PySharing,
+ PyStore,
+ PyScalarType,
+ PyVector,
+ PyMeasurement,
+ PyInclude,
+ PyPragma,
+ PyPragmaArgument,
+ PyAttributeValue,
+ PyCapture,
+ PyFrameDefinition,
+ PyFrameIdentifier,
+ PyPulse,
+ PyRawCapture,
+ PySetFrequency,
+ PySetPhase,
+ PySetScale,
+ PyShiftFrequency,
+ PyShiftPhase,
+ PySwapPhases,
+ PyGate,
+ PyGateDefinition,
+ PyGateModifier,
+ PyGateSpecification,
+ PyPauliGate,
+ PyPauliTerm,
+ PyPauliSum,
+ PyJump,
+ PyJumpWhen,
+ PyJumpUnless,
+ PyLabel,
+ PyTarget,
+ PyTargetPlaceholder,
+ PyMeasurement,
+ PyMemoryReference,
+ PyQubit,
+ PyQubitPlaceholder,
+ PyReset,
+ PyDelay,
+ PyFence,
+ PyWaveform,
+ PyWaveformDefinition,
+ PyWaveformInvocation
+ ],
+ errors: [ GateError, ParseMemoryReferenceError ],
+}
+
+/// Implements __copy__ and __deepcopy__ on any variant of the [`PyInstruction`] class, making
+/// them compatible with Python's `copy` module.
+///
+/// The `__copy__` method returns a reference to the instruction, making it shallow: any changes
+/// to the copy will update the original.
+///
+/// The `__deepcopy__` method creates a deep copy by cloning the inner instruction, querying its
+/// qubits, and replacing any [`quil_rs::instruction::QubitPlaceholder`]s with new instances so
+/// that resolving them in one copy doesn't affect the other. Duplicates of the same instruction in
+/// the original instruction will be replaced with the same copy in the new instruction.
+#[macro_export]
+macro_rules! impl_copy_for_instruction {
+ ($py_name: ident) => {
+ #[pyo3::pymethods]
+ impl $py_name {
+ pub fn __deepcopy__(
+ &self,
+ py: Python<'_>,
+ _memo: &pyo3::types::PyDict,
+ ) -> pyo3::PyResult {
+ let mut instruction = $crate::instruction::PyInstruction::new(
+ py,
+ pyo3::ToPyObject::to_object(&self, py).as_ref(py),
+ )?;
+
+ use quil_rs::instruction::{Qubit, QubitPlaceholder};
+ use std::collections::HashMap;
+ let mut placeholders: HashMap = HashMap::new();
+
+ for qubit in
+ rigetti_pyo3::PyWrapperMut::as_inner_mut(&mut instruction).get_qubits_mut()
+ {
+ match qubit {
+ Qubit::Fixed(_) | Qubit::Variable(_) => *qubit = qubit.clone(),
+ Qubit::Placeholder(placeholder) => {
+ *qubit = Qubit::Placeholder(
+ placeholders.entry(placeholder.clone()).or_default().clone(),
+ )
+ }
+ }
+ }
+
+ Ok(instruction
+ .inner(py)
+ .unwrap()
+ .extract::<$py_name>(py)
+ .expect("a copy of a type should extract to the same type"))
+ }
+
+ pub fn __copy__(&self) -> Self {
+ self.clone()
+ }
+ }
+ };
+}
diff --git a/quil-py/src/instruction/pragma.rs b/quil-py/src/instruction/pragma.rs
new file mode 100644
index 00000000..94dd318a
--- /dev/null
+++ b/quil-py/src/instruction/pragma.rs
@@ -0,0 +1,78 @@
+use quil_rs::instruction::{Include, Pragma, PragmaArgument};
+
+use rigetti_pyo3::{
+ impl_hash, impl_repr, py_wrap_data_struct, py_wrap_union_enum,
+ pyo3::{
+ pymethods,
+ types::{PyInt, PyString},
+ Py, PyResult, Python,
+ },
+ PyTryFrom,
+};
+
+use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil};
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyPragma(Pragma) as "Pragma" {
+ name: String => Py,
+ arguments: Vec => Vec,
+ data: Option => Option>
+ }
+}
+impl_repr!(PyPragma);
+impl_to_quil!(PyPragma);
+impl_copy_for_instruction!(PyPragma);
+impl_hash!(PyPragma);
+impl_eq!(PyPragma);
+
+#[pymethods]
+impl PyPragma {
+ #[new]
+ fn new(
+ py: Python<'_>,
+ name: String,
+ arguments: Vec,
+ data: Option,
+ ) -> PyResult {
+ Ok(Self(Pragma::new(
+ name,
+ Vec::::py_try_from(py, &arguments)?,
+ data,
+ )))
+ }
+}
+
+py_wrap_union_enum! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyPragmaArgument(PragmaArgument) as "PragmaArgument" {
+ identifier: Identifier => Py,
+ integer: Integer => Py
+ }
+}
+impl_repr!(PyPragmaArgument);
+impl_to_quil!(PyPragmaArgument);
+impl_hash!(PyPragmaArgument);
+impl_eq!(PyPragmaArgument);
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyInclude(Include) as "Include" {
+ filename: String => Py
+ }
+}
+impl_repr!(PyInclude);
+impl_to_quil!(PyInclude);
+impl_copy_for_instruction!(PyInclude);
+impl_hash!(PyInclude);
+impl_eq!(PyInclude);
+
+#[pymethods]
+impl PyInclude {
+ #[new]
+ pub fn new(filename: String) -> Self {
+ Self(Include::new(filename))
+ }
+}
diff --git a/quil-py/src/instruction/qubit.rs b/quil-py/src/instruction/qubit.rs
new file mode 100644
index 00000000..e99e3e3b
--- /dev/null
+++ b/quil-py/src/instruction/qubit.rs
@@ -0,0 +1,42 @@
+use quil_rs::instruction::{Qubit, QubitPlaceholder};
+
+use rigetti_pyo3::{
+ impl_compare, impl_hash, impl_repr, py_wrap_type, py_wrap_union_enum,
+ pyo3::{
+ pymethods,
+ types::{PyLong, PyString},
+ Py,
+ },
+};
+
+use crate::{impl_eq, impl_to_quil};
+
+py_wrap_union_enum! {
+ #[derive(Debug, Eq, Hash, PartialEq)]
+ PyQubit(Qubit) as "Qubit" {
+ fixed: Fixed => Py,
+ variable: Variable => Py,
+ placeholder: Placeholder => PyQubitPlaceholder
+ }
+}
+impl_repr!(PyQubit);
+impl_to_quil!(PyQubit);
+impl_hash!(PyQubit);
+impl_eq!(PyQubit);
+
+py_wrap_type! {
+ #[pyo3(subclass)]
+ #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+ PyQubitPlaceholder(QubitPlaceholder) as "QubitPlaceholder"
+}
+impl_repr!(PyQubitPlaceholder);
+impl_hash!(PyQubitPlaceholder);
+impl_compare!(PyQubitPlaceholder);
+
+#[pymethods]
+impl PyQubitPlaceholder {
+ #[new]
+ fn new() -> Self {
+ Self(QubitPlaceholder::default())
+ }
+}
diff --git a/quil-py/src/instruction/reset.rs b/quil-py/src/instruction/reset.rs
new file mode 100644
index 00000000..14d5ba1b
--- /dev/null
+++ b/quil-py/src/instruction/reset.rs
@@ -0,0 +1,30 @@
+use quil_rs::instruction::{Qubit, Reset};
+
+use rigetti_pyo3::{
+ impl_hash, impl_repr, py_wrap_data_struct,
+ pyo3::{pymethods, PyResult, Python},
+ PyTryFrom,
+};
+
+use crate::{impl_copy_for_instruction, impl_eq, impl_to_quil, instruction::PyQubit};
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyReset(Reset) as "Reset" {
+ qubit: Option => Option
+ }
+}
+impl_repr!(PyReset);
+impl_copy_for_instruction!(PyReset);
+impl_to_quil!(PyReset);
+impl_hash!(PyReset);
+impl_eq!(PyReset);
+
+#[pymethods]
+impl PyReset {
+ #[new]
+ fn new(py: Python<'_>, qubit: Option) -> PyResult {
+ Ok(Self(Reset::new(Option::::py_try_from(py, &qubit)?)))
+ }
+}
diff --git a/quil-py/src/instruction/timing.rs b/quil-py/src/instruction/timing.rs
new file mode 100644
index 00000000..cfcf4eda
--- /dev/null
+++ b/quil-py/src/instruction/timing.rs
@@ -0,0 +1,64 @@
+use quil_rs::expression::Expression;
+use quil_rs::instruction::{Delay, Fence, Qubit};
+
+use rigetti_pyo3::{
+ impl_hash, impl_repr, py_wrap_data_struct,
+ pyo3::{pymethods, types::PyString, Py, PyResult, Python},
+ PyTryFrom,
+};
+
+use super::PyQubit;
+use crate::{expression::PyExpression, impl_copy_for_instruction, impl_eq, impl_to_quil};
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyDelay(Delay) as "Delay" {
+ duration: Expression => PyExpression,
+ frame_names: Vec => Vec>,
+ qubits: Vec => Vec
+ }
+}
+impl_repr!(PyDelay);
+impl_to_quil!(PyDelay);
+impl_copy_for_instruction!(PyDelay);
+impl_hash!(PyDelay);
+impl_eq!(PyDelay);
+
+#[pymethods]
+impl PyDelay {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ duration: PyExpression,
+ frame_names: Vec,
+ qubits: Vec,
+ ) -> PyResult {
+ Ok(Self(Delay::new(
+ Expression::py_try_from(py, &duration)?,
+ frame_names,
+ Vec::::py_try_from(py, &qubits)?,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyFence(Fence) as "Fence" {
+ qubits: Vec => Vec
+ }
+}
+impl_repr!(PyFence);
+impl_to_quil!(PyFence);
+impl_copy_for_instruction!(PyFence);
+impl_hash!(PyFence);
+impl_eq!(PyFence);
+
+#[pymethods]
+impl PyFence {
+ #[new]
+ pub fn new(py: Python<'_>, qubits: Vec) -> PyResult {
+ Ok(Self(Fence::new(Vec::::py_try_from(py, &qubits)?)))
+ }
+}
diff --git a/quil-py/src/instruction/waveform.rs b/quil-py/src/instruction/waveform.rs
new file mode 100644
index 00000000..a670663b
--- /dev/null
+++ b/quil-py/src/instruction/waveform.rs
@@ -0,0 +1,91 @@
+use indexmap::IndexMap;
+
+use quil_rs::{
+ expression::Expression,
+ instruction::{Waveform, WaveformDefinition, WaveformInvocation, WaveformParameters},
+};
+
+use rigetti_pyo3::{
+ impl_hash, impl_repr, py_wrap_data_struct,
+ pyo3::{pymethods, types::PyString, Py, PyResult, Python},
+ PyTryFrom,
+};
+
+use crate::{expression::PyExpression, impl_copy_for_instruction, impl_eq, impl_to_quil};
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyWaveform(Waveform) as "Waveform" {
+ matrix: Vec => Vec,
+ parameters: Vec => Vec>
+ }
+}
+impl_repr!(PyWaveform);
+impl_hash!(PyWaveform);
+impl_eq!(PyWaveform);
+
+#[pymethods]
+impl PyWaveform {
+ #[new]
+ pub fn new(
+ py: Python<'_>,
+ matrix: Vec,
+ parameters: Vec,
+ ) -> PyResult {
+ Ok(Self(Waveform::new(
+ Vec::::py_try_from(py, &matrix)?,
+ parameters,
+ )))
+ }
+}
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyWaveformDefinition(WaveformDefinition) as "WaveformDefinition" {
+ name: String => Py,
+ definition: Waveform => PyWaveform
+ }
+}
+impl_repr!(PyWaveformDefinition);
+impl_to_quil!(PyWaveformDefinition);
+impl_copy_for_instruction!(PyWaveformDefinition);
+impl_hash!(PyWaveformDefinition);
+impl_eq!(PyWaveformDefinition);
+
+#[pymethods]
+impl PyWaveformDefinition {
+ #[new]
+ pub fn new(py: Python<'_>, name: String, definition: PyWaveform) -> PyResult {
+ Ok(Self(WaveformDefinition::new(
+ name,
+ Waveform::py_try_from(py, &definition)?,
+ )))
+ }
+}
+
+pub type PyWaveformParameters = IndexMap;
+
+py_wrap_data_struct! {
+ #[derive(Debug, PartialEq, Eq)]
+ #[pyo3(subclass)]
+ PyWaveformInvocation(WaveformInvocation) as "WaveformInvocation" {
+ name: String => Py,
+ parameters: WaveformParameters => PyWaveformParameters
+ }
+}
+impl_repr!(PyWaveformInvocation);
+impl_to_quil!(PyWaveformInvocation);
+impl_eq!(PyWaveformInvocation);
+
+#[pymethods]
+impl PyWaveformInvocation {
+ #[new]
+ pub fn new(py: Python<'_>, name: String, parameters: PyWaveformParameters) -> PyResult {
+ Ok(Self(WaveformInvocation::new(
+ name,
+ WaveformParameters::py_try_from(py, ¶meters)?,
+ )))
+ }
+}
diff --git a/quil-py/src/lib.rs b/quil-py/src/lib.rs
new file mode 100644
index 00000000..17ba774e
--- /dev/null
+++ b/quil-py/src/lib.rs
@@ -0,0 +1,68 @@
+use pyo3::prelude::*;
+use rigetti_pyo3::create_init_submodule;
+
+pub mod expression;
+pub mod instruction;
+pub mod program;
+pub mod validation;
+
+create_init_submodule! {
+ submodules: [
+ "expression": expression::init_submodule,
+ "instructions": instruction::init_submodule,
+ "program": program::init_submodule,
+ "validation": validation::init_submodule
+ ],
+}
+
+#[pymodule]
+fn quil(py: Python<'_>, m: &PyModule) -> PyResult<()> {
+ init_submodule("quil", py, m)?;
+ Ok(())
+}
+
+pub fn init_quil_submodule(name: &str, py: Python<'_>, m: &PyModule) -> PyResult<()> {
+ init_submodule(name, py, m)?;
+ Ok(())
+}
+
+/// Implement `to_quil` and `to_quil_or_debug` methods for wrapper types whose inner type
+/// implements [`Quil`](quil_rs::quil::Quil).
+#[macro_export]
+macro_rules! impl_to_quil {
+ ($name: ident) => {
+ #[pyo3::pymethods]
+ impl $name {
+ pub fn to_quil(&self) -> pyo3::PyResult {
+ quil_rs::quil::Quil::to_quil(rigetti_pyo3::PyWrapper::as_inner(self))
+ .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
+ }
+
+ pub fn to_quil_or_debug(&self) -> String {
+ quil_rs::quil::Quil::to_quil_or_debug(rigetti_pyo3::PyWrapper::as_inner(self))
+ }
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! impl_eq {
+ ($name: ident) => {
+ #[pyo3::pymethods]
+ impl $name {
+ pub fn __richcmp__(
+ &self,
+ py: pyo3::Python<'_>,
+ other: &Self,
+ op: pyo3::pyclass::CompareOp,
+ ) -> pyo3::PyObject {
+ use pyo3::IntoPy;
+ match op {
+ pyo3::pyclass::CompareOp::Eq => (self == other).into_py(py),
+ pyo3::pyclass::CompareOp::Ne => (self != other).into_py(py),
+ _ => py.NotImplemented(),
+ }
+ }
+ }
+ };
+}
diff --git a/quil-py/src/program/analysis.rs b/quil-py/src/program/analysis.rs
new file mode 100644
index 00000000..edb655f0
--- /dev/null
+++ b/quil-py/src/program/analysis.rs
@@ -0,0 +1,104 @@
+use pyo3::{exceptions::PyValueError, types::PyType};
+use quil_rs::program::analysis::{
+ BasicBlock, BasicBlockOwned, BasicBlockScheduleError, ControlFlowGraph, ControlFlowGraphOwned,
+ QubitGraph, QubitGraphError,
+};
+use rigetti_pyo3::{
+ impl_repr, py_wrap_error, py_wrap_type, pyo3::prelude::*, wrap_error, PyWrapper, ToPythonError,
+};
+
+use crate::instruction::{PyInstruction, PyTarget};
+
+use super::{scheduling::PyScheduleSeconds, PyProgram};
+
+py_wrap_type! {
+ #[pyo3(subclass)]
+ PyControlFlowGraph(ControlFlowGraphOwned) as "ControlFlowGraph"
+}
+
+impl_repr!(PyControlFlowGraph);
+
+#[pymethods]
+impl PyControlFlowGraph {
+ #[new]
+ #[classmethod]
+ pub fn new(_: Py, instance: Self) -> Self {
+ instance
+ }
+
+ pub fn has_dynamic_control_flow(&self) -> bool {
+ ControlFlowGraph::from(self.as_inner()).has_dynamic_control_flow()
+ }
+
+ pub fn basic_blocks(&self) -> Vec {
+ ControlFlowGraph::from(self.as_inner())
+ .into_blocks()
+ .into_iter()
+ .map(BasicBlockOwned::from)
+ .map(PyBasicBlock::from)
+ .collect()
+ }
+}
+
+py_wrap_type! {
+ #[pyo3(subclass)]
+ PyBasicBlock(BasicBlockOwned) as "BasicBlock"
+}
+impl_repr!(PyBasicBlock);
+
+wrap_error!(RustBasicBlockScheduleError(BasicBlockScheduleError));
+py_wrap_error!(
+ quil,
+ RustBasicBlockScheduleError,
+ PyBasicBlockScheduleError,
+ PyValueError
+);
+
+wrap_error!(RustQubitGraphError(QubitGraphError));
+py_wrap_error!(quil, RustQubitGraphError, PyQubitGraphError, PyValueError);
+
+#[pymethods]
+impl PyBasicBlock {
+ #[new]
+ #[classmethod]
+ pub fn new(_: Py, instance: Self) -> Self {
+ instance
+ }
+
+ pub fn as_schedule_seconds(&self, program: &PyProgram) -> PyResult {
+ BasicBlock::from(self.as_inner())
+ .as_schedule_seconds(program.as_inner())
+ .map(|v| v.into())
+ .map_err(RustBasicBlockScheduleError::from)
+ .map_err(RustBasicBlockScheduleError::to_py_err)
+ }
+
+ pub fn gate_depth(&self, gate_minimum_qubit_count: usize) -> PyResult {
+ let block = BasicBlock::from(self.as_inner());
+ QubitGraph::try_from(&block)
+ .map(|graph| graph.gate_depth(gate_minimum_qubit_count))
+ .map_err(RustQubitGraphError::from)
+ .map_err(RustQubitGraphError::to_py_err)
+ }
+
+ pub fn instructions(&self) -> Vec {
+ BasicBlock::from(self.as_inner())
+ .instructions()
+ .iter()
+ .copied()
+ .map(PyInstruction::from)
+ .collect()
+ }
+
+ pub fn label(&self) -> Option {
+ BasicBlock::from(self.as_inner()).label().map(|l| l.into())
+ }
+
+ pub fn terminator(&self) -> Option {
+ BasicBlock::from(self.as_inner())
+ .terminator()
+ .clone()
+ .into_instruction()
+ .map(PyInstruction::from)
+ }
+}
diff --git a/quil-py/src/program/calibration.rs b/quil-py/src/program/calibration.rs
new file mode 100644
index 00000000..4b54cb57
--- /dev/null
+++ b/quil-py/src/program/calibration.rs
@@ -0,0 +1,142 @@
+use quil_rs::{
+ instruction::{Calibration, Gate, Instruction, MeasureCalibrationDefinition, Measurement},
+ program::Calibrations,
+};
+use rigetti_pyo3::{
+ impl_as_mut_for_wrapper, impl_repr, py_wrap_type,
+ pyo3::{pymethods, PyResult, Python},
+ PyTryFrom, PyWrapper, PyWrapperMut, ToPython, ToPythonError,
+};
+
+use crate::{
+ impl_eq,
+ instruction::{
+ PyCalibration, PyGate, PyInstruction, PyMeasureCalibrationDefinition, PyMeasurement,
+ },
+};
+
+use super::ProgramError;
+
+py_wrap_type! {
+ #[derive(Debug, PartialEq)]
+ PyCalibrationSet(Calibrations) as "CalibrationSet"
+}
+impl_as_mut_for_wrapper!(PyCalibrationSet);
+impl_repr!(PyCalibrationSet);
+impl_eq!(PyCalibrationSet);
+
+#[pymethods]
+impl PyCalibrationSet {
+ #[new]
+ pub fn new(
+ calibrations: Vec,
+ measure_calibrations: Vec,
+ ) -> PyResult {
+ Ok(Self(Calibrations {
+ calibrations: calibrations
+ .into_iter()
+ .map(|c| c.into_inner())
+ .collect::>()
+ .into(),
+ measure_calibrations: measure_calibrations
+ .into_iter()
+ .map(|c| c.into_inner())
+ .collect::>()
+ .into(),
+ }))
+ }
+
+ #[getter]
+ pub fn calibrations(&self, py: Python<'_>) -> PyResult> {
+ self.as_inner().calibrations().to_python(py)
+ }
+
+ #[getter]
+ pub fn measure_calibrations(
+ &self,
+ py: Python<'_>,
+ ) -> PyResult> {
+ self.as_inner().measure_calibrations().to_python(py)
+ }
+
+ pub fn expand(
+ &self,
+ py: Python<'_>,
+ instruction: PyInstruction,
+ previous_calibrations: Vec,
+ ) -> PyResult>> {
+ self.as_inner()
+ .expand(
+ &Instruction::py_try_from(py, &instruction)?,
+ &Vec::::py_try_from(py, &previous_calibrations)?,
+ )
+ .map_err(ProgramError::from)
+ .map_err(ProgramError::to_py_err)?
+ .to_python(py)
+ }
+
+ pub fn get_match_for_measurement(
+ &self,
+ py: Python<'_>,
+ measurement: PyMeasurement,
+ ) -> PyResult> {
+ Ok(self
+ .as_inner()
+ .get_match_for_measurement(&Measurement::py_try_from(py, &measurement)?)
+ .map(PyMeasureCalibrationDefinition::from))
+ }
+
+ pub fn get_match_for_gate(
+ &self,
+ py: Python<'_>,
+ gate: PyGate,
+ ) -> PyResult > {
+ Ok(self
+ .as_inner()
+ .get_match_for_gate(&Gate::py_try_from(py, &gate)?)
+ .map(PyCalibration::from))
+ }
+
+ pub fn __len__(&self) -> usize {
+ self.as_inner().len()
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.as_inner().is_empty()
+ }
+
+ pub fn insert_calibration(
+ &mut self,
+ py: Python<'_>,
+ calibration: PyCalibration,
+ ) -> PyResult > {
+ Ok(self
+ .as_inner_mut()
+ .insert_calibration(Calibration::py_try_from(py, &calibration)?)
+ .map(PyCalibration::from))
+ }
+
+ pub fn insert_measurement_calibration(
+ &mut self,
+ py: Python<'_>,
+ calibration: PyMeasureCalibrationDefinition,
+ ) -> PyResult > {
+ Ok(self
+ .as_inner_mut()
+ .insert_measurement_calibration(MeasureCalibrationDefinition::py_try_from(
+ py,
+ &calibration,
+ )?)
+ .map(PyMeasureCalibrationDefinition::from))
+ }
+
+ pub fn extend(&mut self, py: Python<'_>, other: PyCalibrationSet) -> PyResult<()> {
+ self.as_inner_mut()
+ .extend(Calibrations::py_try_from(py, &other)?);
+ Ok(())
+ }
+
+ pub fn to_instructions(&self, py: Python<'_>) -> PyResult> {
+ self.as_inner().to_instructions().to_python(py)
+ }
+}
diff --git a/quil-py/src/program/frame.rs b/quil-py/src/program/frame.rs
new file mode 100644
index 00000000..d40ec3ab
--- /dev/null
+++ b/quil-py/src/program/frame.rs
@@ -0,0 +1,110 @@
+use std::borrow::Borrow;
+use std::collections::{HashMap, HashSet};
+use std::convert::AsRef;
+
+use quil_rs::{
+ instruction::{FrameAttributes, FrameIdentifier},
+ program::FrameSet,
+};
+use rigetti_pyo3::{
+ impl_as_mut_for_wrapper, impl_repr, py_wrap_type,
+ pyo3::{pymethods, PyResult, Python},
+ PyTryFrom, PyWrapper, PyWrapperMut, ToPython,
+};
+
+use crate::{
+ impl_eq,
+ instruction::{PyFrameAttributes, PyFrameIdentifier, PyInstruction},
+};
+
+py_wrap_type! {
+ #[derive(Debug, PartialEq, Eq)]
+ PyFrameSet(FrameSet) as "FrameSet"
+}
+impl_repr!(PyFrameSet);
+impl_as_mut_for_wrapper!(PyFrameSet);
+impl_eq!(PyFrameSet);
+
+#[pymethods]
+impl PyFrameSet {
+ #[new]
+ pub fn new() -> Self {
+ Self(FrameSet::new())
+ }
+
+ pub fn get(
+ &self,
+ py: Python<'_>,
+ identifier: PyFrameIdentifier,
+ ) -> PyResult> {
+ self.as_inner()
+ .get(&FrameIdentifier::py_try_from(py, &identifier)?)
+ .to_python(py)
+ }
+
+ pub fn get_keys(&self, py: Python<'_>) -> PyResult> {
+ self.as_inner().get_keys().to_python(py)
+ }
+
+ pub fn get_all_frames(
+ &self,
+ py: Python<'_>,
+ ) -> PyResult> {
+ self.as_inner()
+ .iter()
+ .map(|(ident, attribs)| Ok((ident.to_python(py)?, attribs.to_python(py)?)))
+ .collect()
+ }
+
+ pub fn insert(
+ &mut self,
+ py: Python<'_>,
+ identifier: PyFrameIdentifier,
+ attributes: PyFrameAttributes,
+ ) -> PyResult<()> {
+ self.as_inner_mut().insert(
+ FrameIdentifier::py_try_from(py, &identifier)?,
+ FrameAttributes::py_try_from(py, &attributes)?,
+ );
+ Ok(())
+ }
+
+ pub fn merge(&mut self, py: Python<'_>, other: PyFrameSet) -> PyResult<()> {
+ self.as_inner_mut()
+ .merge(FrameSet::py_try_from(py, &other)?);
+ Ok(())
+ }
+
+ pub fn intersection(
+ &self,
+ py: Python<'_>,
+ identifiers: HashSet,
+ ) -> PyResult {
+ Ok(Self(
+ self.as_inner().intersection(
+ &HashSet::::py_try_from(py, &identifiers)?
+ .iter()
+ .map(Borrow::borrow)
+ .collect(),
+ ),
+ ))
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.as_inner().is_empty()
+ }
+
+ pub fn to_instructions(&self, py: Python<'_>) -> PyResult> {
+ self.as_inner().to_instructions().to_python(py)
+ }
+
+ pub fn __len__(&self) -> usize {
+ self.as_inner().len()
+ }
+}
+
+impl Default for PyFrameSet {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/quil-py/src/program/memory.rs b/quil-py/src/program/memory.rs
new file mode 100644
index 00000000..654cc18a
--- /dev/null
+++ b/quil-py/src/program/memory.rs
@@ -0,0 +1,37 @@
+use quil_rs::{
+ instruction::{Sharing, Vector},
+ program::MemoryRegion,
+};
+use rigetti_pyo3::{
+ impl_hash, impl_repr, py_wrap_data_struct,
+ pyo3::{pymethods, PyResult, Python},
+ PyTryFrom,
+};
+
+use crate::{
+ impl_eq,
+ instruction::{PySharing, PyVector},
+};
+
+py_wrap_data_struct! {
+ #[derive(Debug, Eq, PartialEq, Hash)]
+ #[pyo3(subclass)]
+ PyMemoryRegion(MemoryRegion) as "MemoryRegion" {
+ size: Vector => PyVector,
+ sharing: Option => Option
+ }
+}
+impl_repr!(PyMemoryRegion);
+impl_hash!(PyMemoryRegion);
+impl_eq!(PyMemoryRegion);
+
+#[pymethods]
+impl PyMemoryRegion {
+ #[new]
+ pub fn new(py: Python<'_>, size: PyVector, sharing: Option) -> PyResult {
+ Ok(Self(MemoryRegion::new(
+ Vector::py_try_from(py, &size)?,
+ Option::::py_try_from(py, &sharing)?,
+ )))
+ }
+}
diff --git a/quil-py/src/program/mod.rs b/quil-py/src/program/mod.rs
new file mode 100644
index 00000000..9df4ab7d
--- /dev/null
+++ b/quil-py/src/program/mod.rs
@@ -0,0 +1,378 @@
+use std::{
+ collections::{HashMap, HashSet},
+ str::FromStr,
+};
+
+use indexmap::IndexMap;
+use numpy::{PyArray2, ToPyArray};
+use quil_rs::{
+ instruction::{Instruction, QubitPlaceholder, TargetPlaceholder, Waveform},
+ program::{
+ analysis::{ControlFlowGraph, ControlFlowGraphOwned},
+ Calibrations, FrameSet, MemoryRegion,
+ },
+ Program,
+};
+use rigetti_pyo3::{
+ create_init_submodule, impl_as_mut_for_wrapper, impl_from_str, impl_parse, impl_repr,
+ num_complex::Complex64,
+ py_wrap_error, py_wrap_type,
+ pyo3::{
+ exceptions::PyValueError,
+ prelude::*,
+ types::{PyBytes, PyFunction, PyList},
+ IntoPy,
+ },
+ wrap_error, PyTryFrom, PyWrapper, PyWrapperMut, ToPython, ToPythonError,
+};
+
+use crate::{
+ impl_eq, impl_to_quil,
+ instruction::{
+ PyDeclaration, PyGateDefinition, PyInstruction, PyMemoryReference, PyQubit, PyTarget,
+ PyWaveform,
+ },
+};
+
+use self::{
+ analysis::{PyBasicBlock, PyControlFlowGraph},
+ scheduling::{PyScheduleSeconds, PyScheduleSecondsItem, PyTimeSpanSeconds},
+};
+pub use self::{calibration::PyCalibrationSet, frame::PyFrameSet, memory::PyMemoryRegion};
+
+mod analysis;
+mod calibration;
+mod frame;
+mod memory;
+mod scheduling;
+
+wrap_error!(ProgramError(quil_rs::program::ProgramError));
+py_wrap_error!(quil, ProgramError, PyProgramError, PyValueError);
+
+py_wrap_type! {
+ #[derive(Debug, PartialEq)]
+ // If unset, the module defaults to builtin, which can't be pickled
+ #[pyo3(module = "quil.program")]
+ PyProgram(Program) as "Program"
+}
+impl_as_mut_for_wrapper!(PyProgram);
+impl_repr!(PyProgram);
+impl_from_str!(PyProgram, ProgramError);
+impl_parse!(PyProgram);
+impl_to_quil!(PyProgram);
+impl_eq!(PyProgram);
+
+impl Default for PyProgram {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+#[pymethods]
+impl PyProgram {
+ #[new]
+ pub fn new() -> Self {
+ Self(Program::default())
+ }
+
+ pub fn clone_without_body_instructions(&self) -> Self {
+ Self(self.as_inner().clone_without_body_instructions())
+ }
+
+ pub fn copy(&self) -> Self {
+ Self(self.as_inner().clone())
+ }
+
+ pub fn control_flow_graph(&self) -> PyControlFlowGraph {
+ ControlFlowGraphOwned::from(ControlFlowGraph::from(self.as_inner())).into()
+ }
+
+ #[getter]
+ pub fn body_instructions<'a>(&self, py: Python<'a>) -> PyResult<&'a PyList> {
+ Ok(PyList::new(
+ py,
+ self.as_inner()
+ .body_instructions()
+ .map(|i| i.to_python(py))
+ .collect::>>()?,
+ ))
+ }
+
+ #[getter]
+ pub fn calibrations(&self, py: Python<'_>) -> PyResult {
+ self.as_inner().calibrations.to_python(py)
+ }
+
+ #[setter]
+ pub fn set_calibrations(
+ &mut self,
+ py: Python<'_>,
+ calibrations: PyCalibrationSet,
+ ) -> PyResult<()> {
+ let program = self.as_inner_mut();
+ program.calibrations = Calibrations::py_try_from(py, &calibrations)?;
+ Ok(())
+ }
+
+ #[getter]
+ pub fn waveforms(&self, py: Python<'_>) -> PyResult