├── .clang-format ├── .clang-tidy ├── .cmake-format.yaml ├── .editorconfig ├── .git_archival.txt ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ └── feature-request.yml ├── codecov.yml ├── contributing.md ├── pull_request_template.md ├── release-drafter.yml ├── renovate.json5 ├── support.md └── workflows │ ├── cd.yml │ ├── ci.yml │ ├── release-drafter.yml │ ├── update-mqt-core.yml │ └── upstream.yml ├── .gitignore ├── .license-tools-config.json ├── .pre-commit-config.yaml ├── .python_version ├── .readthedocs.yaml ├── CHANGELOG.md ├── CITATION.cff ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── UPGRADING.md ├── cmake ├── ExternalDependencies.cmake └── cmake_uninstall.cmake.in ├── docs ├── CHANGELOG.md ├── UPGRADING.md ├── _static │ ├── custom.css │ ├── mqt_dark.png │ └── mqt_light.png ├── _templates │ └── page.html ├── compilation_flow_verification.md ├── conf.py ├── contributing.md ├── development_guide.md ├── equivalence_checking.md ├── images │ ├── compilation_flow.png │ ├── parameterized_flow.svg │ └── verification_flow.png ├── index.md ├── installation.md ├── lit_header.bib ├── parametrized_circuits.md ├── partial_equivalence.md ├── quickstart.md ├── references.md ├── refs.bib └── support.md ├── include ├── Configuration.hpp ├── EquivalenceCheckingManager.hpp ├── EquivalenceCriterion.hpp ├── ThreadSafeQueue.hpp └── checker │ ├── EquivalenceChecker.hpp │ ├── dd │ ├── DDAlternatingChecker.hpp │ ├── DDConstructionChecker.hpp │ ├── DDEquivalenceChecker.hpp │ ├── DDPackageConfigs.hpp │ ├── DDSimulationChecker.hpp │ ├── TaskManager.hpp │ ├── applicationscheme │ │ ├── ApplicationScheme.hpp │ │ ├── GateCostApplicationScheme.hpp │ │ ├── LookaheadApplicationScheme.hpp │ │ ├── OneToOneApplicationScheme.hpp │ │ ├── ProportionalApplicationScheme.hpp │ │ └── SequentialApplicationScheme.hpp │ └── simulation │ │ ├── StateGenerator.hpp │ │ └── StateType.hpp │ └── zx │ └── ZXChecker.hpp ├── noxfile.py ├── pyproject.toml ├── src ├── CMakeLists.txt ├── Configuration.cpp ├── EquivalenceCheckingManager.cpp ├── checker │ ├── EquivalenceChecker.cpp │ ├── dd │ │ ├── DDAlternatingChecker.cpp │ │ ├── DDConstructionChecker.cpp │ │ ├── DDEquivalenceChecker.cpp │ │ ├── DDSimulationChecker.cpp │ │ ├── applicationscheme │ │ │ └── LookaheadApplicationScheme.cpp │ │ └── simulation │ │ │ └── StateGenerator.cpp │ └── zx │ │ └── ZXChecker.cpp ├── mqt │ └── qcec │ │ ├── __init__.py │ │ ├── _compat │ │ ├── __init__.py │ │ ├── importlib │ │ │ ├── __init__.py │ │ │ └── resources.py │ │ ├── optional.py │ │ └── typing.py │ │ ├── _version.pyi │ │ ├── compilation_flow_profiles.py │ │ ├── configuration.py │ │ ├── parameterized.py │ │ ├── profiles │ │ ├── qiskit_O0_noancilla.profile │ │ ├── qiskit_O0_recursion.profile │ │ ├── qiskit_O0_v-chain.profile │ │ ├── qiskit_O1_noancilla.profile │ │ ├── qiskit_O1_recursion.profile │ │ ├── qiskit_O1_v-chain.profile │ │ ├── qiskit_O2_noancilla.profile │ │ ├── qiskit_O2_recursion.profile │ │ ├── qiskit_O2_v-chain.profile │ │ ├── qiskit_O3_noancilla.profile │ │ ├── qiskit_O3_recursion.profile │ │ └── qiskit_O3_v-chain.profile │ │ ├── py.typed │ │ ├── pyqcec.pyi │ │ ├── verify.py │ │ └── verify_compilation_flow.py └── python │ ├── CMakeLists.txt │ └── bindings.cpp ├── test ├── CMakeLists.txt ├── circuits │ ├── original │ │ ├── 5xp1_194.qasm │ │ ├── C7552_205.qasm │ │ ├── add6_196.qasm │ │ ├── alu1_198.qasm │ │ ├── apla_203.qasm │ │ ├── c2_181.qasm │ │ ├── c2_182.qasm │ │ ├── cm150a_210.qasm │ │ ├── cm151a_211.qasm │ │ ├── cm163a_213.qasm │ │ ├── cu_219.qasm │ │ ├── dk17_224.qasm │ │ ├── dk27_225.qasm │ │ ├── example2_231.qasm │ │ ├── mlp4_245.qasm │ │ ├── mod5adder_306.qasm │ │ ├── pcler8_248.qasm │ │ ├── rd73_312.qasm │ │ ├── rd84_313.qasm │ │ └── sym9_317.qasm │ ├── partialEquivalenceTest │ │ ├── Grover_1.qasm │ │ ├── Grover_2.qasm │ │ ├── add6_196_1.qasm │ │ ├── add6_196_2.qasm │ │ ├── bv_1.qasm │ │ ├── bv_2.qasm │ │ ├── entanglement_1.qasm │ │ ├── entanglement_2.qasm │ │ ├── grover-noancilla_indep_qiskit_3.qasm │ │ ├── grover-noancilla_nativegates_ibm_qiskit_opt0_3.qasm │ │ ├── grover-noancilla_nativegates_ibm_qiskit_opt0_7.qasm │ │ ├── grover-noancilla_nativegates_ibm_qiskit_opt1_7.qasm │ │ ├── period_finding_1.qasm │ │ ├── period_finding_2.qasm │ │ ├── random_1.qasm │ │ └── random_2.qasm │ ├── test │ │ ├── test.qasm │ │ ├── test2.qasm │ │ ├── test2_optimized.qasm │ │ ├── test_alternative.qasm │ │ ├── test_ancilla.qasm │ │ ├── test_ancilla_inputperm.qasm │ │ ├── test_ancilla_inputperm_outputperm.qasm │ │ ├── test_ancilla_inputperm_outputperm_optimizedswap.qasm │ │ ├── test_ancilla_inputperm_outputperm_optimizedswap2.qasm │ │ ├── test_erroneous.qasm │ │ ├── test_inputperm.qasm │ │ ├── test_optimizedswap.qasm │ │ ├── test_original.qasm │ │ ├── test_outputperm.qasm │ │ └── test_swap.qasm │ └── transpiled │ │ ├── 5xp1_194_transpiled.qasm │ │ ├── C7552_205_transpiled.qasm │ │ ├── add6_196_transpiled.qasm │ │ ├── alu1_198_transpiled.qasm │ │ ├── apla_203_transpiled.qasm │ │ ├── c2_181_transpiled.qasm │ │ ├── c2_182_transpiled.qasm │ │ ├── cm150a_210_transpiled.qasm │ │ ├── cm150a_210_transpiled.real │ │ ├── cm151a_211_transpiled.qasm │ │ ├── cm163a_213_transpiled.qasm │ │ ├── cu_219_transpiled.qasm │ │ ├── dk17_224_transpiled.qasm │ │ ├── dk27_225_transpiled.qasm │ │ ├── example2_231_transpiled.qasm │ │ ├── mlp4_245_transpiled.qasm │ │ ├── mod5adder_306_transpiled.qasm │ │ ├── pcler8_248_transpiled.qasm │ │ ├── rd73_312_transpiled.qasm │ │ ├── rd84_313_transpiled.qasm │ │ └── sym9_317_transpiled.qasm ├── python │ ├── test.py │ ├── test_compilation_flow_profiles.py │ ├── test_configuration.py │ ├── test_construction.py │ ├── test_dynamic_circuits.py │ ├── test_partial_equivalence.py │ ├── test_symbolic.py │ ├── test_verify.py │ └── test_verify_compilation.py ├── test_compilationflow.cpp ├── test_dynamic_circuits.cpp ├── test_equality.cpp ├── test_functionality.cpp ├── test_journal.cpp ├── test_partial_equivalence.cpp ├── test_simple_circuit_identities.cpp ├── test_simulation.cpp ├── test_symbolic.cpp └── test_zx.cpp └── uv.lock /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IncludeBlocks: Regroup 3 | PointerAlignment: Left 4 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | FormatStyle: file 2 | 3 | Checks: | 4 | bugprone-*, 5 | -bugprone-easily-swappable-parameters, 6 | -bugprone-unchecked-optional-access, 7 | clang-analyzer-*, 8 | -clang-analyzer-core.NullDereference, 9 | clang-diagnostic-*, 10 | cppcoreguidelines-*, 11 | -cppcoreguidelines-non-private-member-variables-in-classes, 12 | -cppcoreguidelines-special-member-functions, 13 | -cppcoreguidelines-avoid-magic-numbers, 14 | -cppcoreguidelines-macro-usage, 15 | google-*, 16 | -google-readability-todo, 17 | -google-build-using-namespace, 18 | misc-*, 19 | -misc-no-recursion, 20 | -misc-non-private-member-variables-in-classes, 21 | modernize-*, 22 | -modernize-use-trailing-return-type, 23 | performance-*, 24 | portability-*, 25 | readability-*, 26 | -readability-identifier-length, 27 | -readability-magic-numbers, 28 | -readability-function-cognitive-complexity 29 | 30 | CheckOptions: 31 | - key: readability-identifier-naming.ClassCase 32 | value: CamelCase 33 | - key: readability-identifier-naming.ClassIgnoredRegexp 34 | value: ".*ZX.*|.*SWAP.*|.*CEX.*|.*DD.*|.*EQ.*" 35 | - key: readability-identifier-naming.ConstantParameterCase 36 | value: camelBack 37 | - key: readability-identifier-naming.EnumCase 38 | value: CamelCase 39 | - key: readability-identifier-naming.EnumConstantCase 40 | value: CamelCase 41 | - key: readability-identifier-naming.FunctionCase 42 | value: camelBack 43 | - key: readability-identifier-naming.FunctionIgnoredRegexp 44 | value: ".*ZX.*|.*SWAP.*|.*CEX.*|.*DD.*|.*EQ.*" 45 | - key: readability-identifier-naming.GlobalConstantCase 46 | value: UPPER_CASE 47 | - key: readability-identifier-naming.IgnoreMainLikeFunctions 48 | value: "true" 49 | - key: readability-identifier-naming.LocalConstantCase 50 | value: camelBack 51 | - key: readability-identifier-naming.LocalVariableCase 52 | value: camelBack 53 | - key: readability-identifier-naming.MemberCase 54 | value: camelBack 55 | - key: readability-identifier-naming.MemberIgnoredRegexp 56 | value: ".*ZX.*|.*SWAP.*|.*CEX.*|.*DD.*|.*EQ.*" 57 | - key: readability-identifier-naming.MethodCase 58 | value: camelBack 59 | - key: readability-identifier-naming.ParameterCase 60 | value: camelBack 61 | - key: readability-identifier-naming.ParameterIgnoredRegexp 62 | value: ".*ZX.*|.*SWAP.*|.*CEX.*|.*DD.*|.*EQ.*" 63 | - key: readability-identifier-naming.NamespaceCase 64 | value: lower_case 65 | - key: readability-identifier-naming.StaticConstantCase 66 | value: UPPER_CASE 67 | - key: readability-identifier-naming.StructCase 68 | value: CamelCase 69 | - key: readability-identifier-naming.VariableCase 70 | value: camelBack 71 | -------------------------------------------------------------------------------- /.cmake-format.yaml: -------------------------------------------------------------------------------- 1 | format: 2 | line_width: 100 3 | keyword_case: "upper" 4 | autosort: true 5 | 6 | markup: 7 | first_comment_is_literal: true 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.{py,pyi}] 12 | indent_size = 4 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | 17 | [{*.{cmake,cmake.in},CMakeLists.txt}] 18 | max_line_length = 100 19 | -------------------------------------------------------------------------------- /.git_archival.txt: -------------------------------------------------------------------------------- 1 | node: 206ae43ff4b9a12138580dc8c0d4ee1b4bbe0956 2 | node-date: 2025-06-11T17:49:22+02:00 3 | describe-name: v3.0.0-16-g206ae43f 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | test/circuits/** linguist-vendored 2 | .git_archival.txt export-subst 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | name: 🐛 Bug Report 10 | description: Report a problem or unexpected behavior 11 | title: "🐛 " 12 | body: 13 | - type: markdown 14 | attributes: 15 | value: >- 16 | **Thanks for taking the time to report an issue!** 17 | 18 | ⚠ Before submitting: 19 | 1. Search [existing issues](https://github.com/munich-quantum-toolkit/qcec/search?q=is%3Aissue&type=issues) to avoid duplicates 20 | 2. For questions or discussions, please use our [discussions forum](https://github.com/munich-quantum-toolkit/qcec/discussions) 21 | - type: textarea 22 | attributes: 23 | label: System Information 24 | description: Please provide details about your environment 25 | placeholder: | 26 | - Operating System (including version): 27 | - MQT QCEC version: 28 | - Python/C++ compiler version (if applicable): 29 | - Any relevant dependencies and their versions: 30 | validations: 31 | required: true 32 | - type: textarea 33 | attributes: 34 | label: Bug Description 35 | description: Provide a clear and detailed explanation of the issue you're experiencing. 36 | placeholder: | 37 | What happened? 38 | What did you expect to happen instead? 39 | Include any error messages or unexpected behavior you observed. 40 | validations: 41 | required: true 42 | - type: textarea 43 | attributes: 44 | label: Steps to Reproduce 45 | description: Provide specific steps to reproduce this issue 46 | placeholder: | 47 | 1. Set up environment with '...' 48 | 2. Configure workflow using '...' 49 | 3. Execute command '...' 50 | 4. Observe error/issue: '...' 51 | 52 | Include any relevant code snippets, workflow configurations, or input files that help demonstrate the problem. 53 | validations: 54 | required: true 55 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | name: ✨ Feature request 10 | description: Suggest a new feature or improvement 11 | title: "✨ " 12 | body: 13 | - type: markdown 14 | attributes: 15 | value: > 16 | **Thanks for helping improve this project by suggesting a feature!** 17 | 18 | ⚠ Before submitting: 19 | - Search [existing feature requests](https://github.com/munich-quantum-toolkit/qcec/search?q=is%3Aissue&type=issues) to avoid duplicates 20 | - One feature per issue helps us track and implement ideas effectively 21 | 22 | - type: textarea 23 | attributes: 24 | label: Problem Statement 25 | description: >- 26 | Describe the problem you're facing and why it needs to be solved. What limitations are you encountering? 27 | placeholder: >- 28 | Currently, when I try to [action/task], I'm unable to [blockers/limitations]. 29 | This creates problems because [impact/consequences]. 30 | validations: 31 | required: true 32 | 33 | - type: textarea 34 | attributes: 35 | label: Proposed Solution 36 | description: > 37 | Describe your ideal solution. What would the feature look like? How would it work? 38 | placeholder: >- 39 | I'd like to see [feature/change] that would: 40 | - [benefit 1] 41 | - [benefit 2] 42 | - [example usage/scenario] 43 | validations: 44 | required: true 45 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "extern/**/*" 3 | - "**/python" 4 | - "test/**/*" 5 | 6 | coverage: 7 | range: 60..90 8 | precision: 1 9 | status: 10 | project: off 11 | patch: off 12 | 13 | flag_management: 14 | default_rules: 15 | carryforward: true 16 | statuses: 17 | - type: project 18 | target: auto 19 | threshold: 0.5% 20 | removed_code_behavior: adjust_base 21 | - type: patch 22 | target: 90% 23 | threshold: 1% 24 | individual_flags: 25 | - name: cpp 26 | paths: 27 | - "include" 28 | - "src" 29 | - name: python 30 | paths: 31 | - "src/mqt/**/*.py" 32 | statuses: 33 | - type: project 34 | threshold: 0.5% 35 | removed_code_behavior: adjust_base 36 | - type: patch 37 | target: 95% 38 | threshold: 1% 39 | 40 | parsers: 41 | gcov: 42 | branch_detection: 43 | conditional: no 44 | loop: no 45 | 46 | comment: 47 | layout: "reach, diff, flags, files" 48 | require_changes: true 49 | show_carryforward_flags: true 50 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please include a summary of the change and, if applicable, which issue is fixed. 4 | Please also include relevant motivation and context. 5 | List any dependencies that are required for this change. 6 | 7 | Fixes #(issue) <!--- Replace `(issue)` with the issue number fixed by this pull request. If this PR does not fix an issue, please remove this line. --> 8 | 9 | ## Checklist: 10 | 11 | <!--- 12 | This checklist serves as a reminder of a couple of things that ensure your pull request will be merged swiftly. 13 | --> 14 | 15 | - [ ] The pull request only contains commits that are focused and relevant to this change. 16 | - [ ] I have added appropriate tests that cover the new/changed functionality. 17 | - [ ] I have updated the documentation to reflect these changes. 18 | - [ ] I have added entries to the changelog for any noteworthy additions, changes, fixes or removals. 19 | - [ ] I have added migration instructions to the upgrade guide (if needed). 20 | - [ ] The changes follow the project's style guidelines and introduce no new warnings. 21 | - [ ] The changes are fully tested and pass the CI checks. 22 | - [ ] I have reviewed my own code changes. 23 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: "MQT QCEC $RESOLVED_VERSION Release" 2 | tag-template: "v$RESOLVED_VERSION" 3 | categories: 4 | - title: "🚀 Features and Enhancements" 5 | labels: 6 | - "feature" 7 | - "enhancement" 8 | - "usability" 9 | - "refactor" 10 | - title: "🐛 Bug Fixes" 11 | labels: 12 | - "bug" 13 | - "fix" 14 | - title: "📄 Documentation" 15 | labels: 16 | - "documentation" 17 | - title: "📦 Packaging" 18 | labels: 19 | - "packaging" 20 | - title: "🧹 Code Quality" 21 | labels: 22 | - "code quality" 23 | - title: "🤖 CI" 24 | labels: 25 | - "continuous integration" 26 | - title: "⬆️ Dependencies" 27 | collapse-after: 5 28 | labels: 29 | - "dependencies" 30 | - "submodules" 31 | - "github_actions" 32 | - "pre-commit" 33 | change-template: "- $TITLE @$AUTHOR (#$NUMBER)" 34 | change-title-escapes: '\<*_&' 35 | version-resolver: 36 | major: 37 | labels: 38 | - "major" 39 | minor: 40 | labels: 41 | - "minor" 42 | patch: 43 | labels: 44 | - "patch" 45 | default: patch 46 | 47 | template: | 48 | ## 👀 What Changed 49 | 50 | _Please refer to the [changelog](https://github.com/$OWNER/$REPOSITORY/blob/main/CHANGELOG.md) and the [upgrade guide](https://github.com/$OWNER/$REPOSITORY/blob/main/UPGRADING.md) for a structured overview of the changes._ 51 | 52 | $CHANGES 53 | 54 | **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION 55 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | extends: ["config:recommended", ":gitSignOff"], 4 | prHourlyLimit: 10, 5 | enabledManagers: ["github-actions", "pre-commit", "pep621"], 6 | "pre-commit": { 7 | enabled: true 8 | }, 9 | lockFileMaintenance: { 10 | enabled: true, 11 | automerge: true, 12 | }, 13 | configMigration: true, 14 | labels: ["dependencies"], 15 | schedule: ["every weekend"], 16 | packageRules: [ 17 | { 18 | matchManagers: ["github-actions"], 19 | addLabels: ["github-actions"], 20 | commitMessagePrefix: "⬆\uFE0F\uD83D\uDC68\u200D\uD83D\uDCBB" 21 | }, 22 | { 23 | matchManagers: ["pep621"], 24 | addLabels: ["python"], 25 | commitMessagePrefix: "⬆\uFE0F\uD83D\uDC0D" 26 | }, 27 | { 28 | matchManagers: ["pre-commit"], 29 | addLabels: ["pre-commit"], 30 | commitMessagePrefix: "⬆\uFE0F\uD83E\uDE9D", 31 | }, 32 | { 33 | description: "Automerge patch updates", 34 | matchUpdateTypes: ["patch"], 35 | automerge: true 36 | }, 37 | { 38 | description: "Automerge minor updates for stable dependencies", 39 | matchManagers: ["pep621", "pre-commit"], 40 | matchUpdateTypes: ["minor", "patch"], 41 | matchCurrentVersion: "!/^0/", 42 | automerge: true 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /.github/support.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | If you are stuck with a problem using MQT QCEC or have questions, please get in touch at our [Issues](https://github.com/munich-quantum-toolkit/qcec/issues) or [Discussions](https://github.com/munich-quantum-toolkit/qcec/discussions). We'd love to help. 4 | 5 | You can save time by following this procedure when reporting a problem: 6 | 7 | - Do try to solve the problem on your own first. 8 | - Search through past [Issues](https://github.com/munich-quantum-toolkit/qcec/issues) and [Discussions](https://github.com/munich-quantum-toolkit/qcec/discussions) to see if someone else already had the same problem. 9 | - Before filing a bug report, try to create a minimal working example (MWE) that reproduces the problem. It is much easier to identify the cause for the problem if a handful of lines suffice to show that something is not working. 10 | 11 | You can also always reach us at [quantum.cda@xcit.tum.de](mailto:quantum.cda@xcit.tum.de). 12 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: CD 🚀 2 | on: 3 | release: 4 | types: [published] 5 | workflow_dispatch: 6 | 7 | permissions: 8 | attestations: write 9 | contents: read 10 | id-token: write 11 | 12 | jobs: 13 | # Builds the sdist and wheels on all supported platforms and uploads the resulting 14 | # wheels as GitHub artifacts `dev-cibw-*` or `cibw-*`, depending on whether the 15 | # workflow is triggered from a PR or a release, respectively. 16 | python-packaging: 17 | name: 🐍 Packaging 18 | uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-python-packaging.yml@v1.9 19 | with: 20 | # Runs to enable 21 | enable-ubuntu2404: true 22 | enable-ubuntu2404-arm: true 23 | enable-macos13: true 24 | enable-macos14: true 25 | enable-windows2022: true 26 | enable-windows11-arm: true 27 | # Runs to disable 28 | enable-ubuntu2204: false 29 | enable-ubuntu2204-arm: false 30 | enable-macos15: false 31 | enable-windows2025: false 32 | 33 | # Downloads the previously generated artifacts and deploys to PyPI on published releases. 34 | deploy: 35 | if: github.event_name == 'release' && github.event.action == 'published' 36 | name: 🚀 Deploy to PyPI 37 | runs-on: ubuntu-latest 38 | environment: 39 | name: pypi 40 | url: https://pypi.org/p/mqt.qcec 41 | needs: [python-packaging] 42 | steps: 43 | - uses: actions/download-artifact@v4 44 | with: 45 | pattern: cibw-* 46 | path: dist 47 | merge-multiple: true 48 | - name: Generate artifact attestation for sdist and wheels 49 | uses: actions/attest-build-provenance@v2 50 | with: 51 | subject-path: "dist/*" 52 | - uses: pypa/gh-action-pypi-publish@release/v1 53 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: [opened, reopened, synchronize] 9 | merge_group: 10 | 11 | jobs: 12 | update_release_draft: 13 | name: Run 14 | permissions: 15 | contents: write 16 | pull-requests: write 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: release-drafter/release-drafter@v6 20 | env: 21 | GITHUB_TOKEN: ${{ github.token }} 22 | -------------------------------------------------------------------------------- /.github/workflows/update-mqt-core.yml: -------------------------------------------------------------------------------- 1 | name: Update MQT Core 2 | on: 3 | schedule: 4 | # run once a month on the first day of the month at 00:00 UTC 5 | - cron: "0 0 1 * *" 6 | workflow_dispatch: 7 | inputs: 8 | update-to-head: 9 | description: "Update to the latest commit on the default branch" 10 | type: boolean 11 | required: false 12 | default: false 13 | pull_request: 14 | paths: 15 | - .github/workflows/update-mqt-core.yml 16 | 17 | concurrency: 18 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 19 | cancel-in-progress: true 20 | 21 | jobs: 22 | update-mqt-core: 23 | name: ⬆️ Update MQT Core 24 | uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-mqt-core-update.yml@v1.9 25 | with: 26 | update-to-head: ${{ github.event.inputs.update-to-head == 'true' }} 27 | -------------------------------------------------------------------------------- /.github/workflows/upstream.yml: -------------------------------------------------------------------------------- 1 | name: Qiskit Upstream Tests 2 | on: 3 | schedule: 4 | # Run every Monday at 00:00 UTC 5 | - cron: "0 0 * * 1" 6 | pull_request: 7 | paths: 8 | - ".github/workflows/upstream.yml" 9 | workflow_dispatch: # Allow manual triggering 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | qiskit-upstream-tests: 17 | name: 🐍⚛️ 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | os: [ubuntu-24.04, macos-15, windows-2025] 22 | uses: munich-quantum-toolkit/workflows/.github/workflows/reusable-qiskit-upstream.yml@v1.9 23 | with: 24 | runs-on: ${{ matrix.os }} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | .ccache/ 9 | cmake-build-* 10 | 11 | # Distribution / packaging 12 | .Python 13 | /build/ 14 | /test/*/build 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | cover/ 56 | *.profraw 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | docs/api/ 78 | 79 | # PyBuilder 80 | .pybuilder/ 81 | target/ 82 | 83 | # Jupyter Notebook 84 | .ipynb_checkpoints 85 | 86 | # IPython 87 | profile_default/ 88 | ipython_config.py 89 | 90 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 91 | __pypackages__/ 92 | 93 | # Celery stuff 94 | celerybeat-schedule 95 | celerybeat.pid 96 | 97 | # SageMath parsed files 98 | *.sage.py 99 | 100 | # Environments 101 | .env* 102 | .venv* 103 | env*/ 104 | venv*/ 105 | ENV/ 106 | env.bak/ 107 | venv.bak/ 108 | 109 | # Spyder project settings 110 | .spyderproject 111 | .spyproject 112 | 113 | # Rope project settings 114 | .ropeproject 115 | 116 | # mkdocs documentation 117 | /site 118 | 119 | # mypy 120 | .mypy_cache/ 121 | .dmypy.json 122 | dmypy.json 123 | 124 | # Pyre type checker 125 | .pyre/ 126 | 127 | # pytype static type analyzer 128 | .pytype/ 129 | 130 | # Cython debug symbols 131 | cython_debug/ 132 | 133 | # setuptools_scm 134 | src/*/_version.py 135 | 136 | # SKBuild cache dir 137 | _skbuild/ 138 | 139 | # Any build dirs in the tests 140 | test/**/build/ 141 | /src/mqt/**/_version.py 142 | 143 | # Common editor files 144 | *~ 145 | *.swp 146 | 147 | # RPM spec file 148 | !/distro/*.spec 149 | /distro/*.tar.gz 150 | *.rpm 151 | 152 | # ruff 153 | .ruff_cache/ 154 | 155 | # OS specific stuff 156 | .DS_Store 157 | .DS_Store? 158 | ._* 159 | .Spotlight-V100 160 | .Trashes 161 | ehthumbs.db 162 | Thumbs.db 163 | 164 | .idea/ 165 | .vscode/ 166 | # tmt setup 167 | /distro/main.fmf 168 | /distro/plans/main.fmf 169 | /distro/tests/main.fmf 170 | 171 | /docs/**/build 172 | .vs 173 | out/build 174 | 175 | node_modules/ 176 | wheelhouse/ 177 | -------------------------------------------------------------------------------- /.license-tools-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "Chair for Design Automation, TUM\nCopyright (c) 2025 Munich Quantum Software Company GmbH", 4 | "years": [2023, 2025] 5 | }, 6 | "force_author": true, 7 | "license": "MIT", 8 | "title": false, 9 | "include": ["**/*"], 10 | "style_override_for_suffix": { 11 | ".pyi": "DOCSTRING_STYLE", 12 | ".in": "POUND_STYLE", 13 | ".mlir": "SLASH_STYLE", 14 | ".td": "SLASH_STYLE", 15 | ".yaml": "POUND_STYLE", 16 | ".toml": "POUND_STYLE", 17 | ".yml": "POUND_STYLE" 18 | }, 19 | "exclude": [ 20 | "^\\.[^/]+", 21 | "/\\.[^/]+", 22 | ".*\\.qasm", 23 | ".*\\.md", 24 | ".*\\.bib", 25 | ".*\\.cff", 26 | ".*\\.css", 27 | ".*\\.json", 28 | ".*\\.html", 29 | ".*\\.tfc", 30 | ".*\\.qc", 31 | ".*\\.real", 32 | ".*\\.tex", 33 | ".*\\.profile", 34 | "uv\\.lock", 35 | "py\\.typed", 36 | ".*build.*" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # To run all pre-commit checks, use: 2 | # 3 | # pre-commit run -a 4 | # 5 | # To install pre-commit hooks that run every time you commit: 6 | # 7 | # pre-commit install 8 | # 9 | 10 | ci: 11 | autoupdate_commit_msg: "⬆️🪝 update pre-commit hooks" 12 | autoupdate_schedule: quarterly 13 | autofix_commit_msg: "🎨 pre-commit fixes" 14 | skip: [mypy] 15 | 16 | repos: 17 | # Standard hooks 18 | - repo: https://github.com/pre-commit/pre-commit-hooks 19 | rev: v5.0.0 20 | hooks: 21 | - id: check-added-large-files 22 | - id: check-case-conflict 23 | - id: check-docstring-first 24 | - id: check-merge-conflict 25 | - id: check-toml 26 | - id: check-yaml 27 | - id: debug-statements 28 | - id: end-of-file-fixer 29 | - id: mixed-line-ending 30 | - id: trailing-whitespace 31 | 32 | # Clean jupyter notebooks 33 | - repo: https://github.com/srstevenson/nb-clean 34 | rev: 4.0.1 35 | hooks: 36 | - id: nb-clean 37 | args: 38 | - --remove-empty-cells 39 | - --preserve-cell-metadata 40 | - raw_mimetype 41 | - -- 42 | 43 | # Handling unwanted unicode characters 44 | - repo: https://github.com/sirosen/texthooks 45 | rev: 0.6.8 46 | hooks: 47 | - id: fix-ligatures 48 | - id: fix-smartquotes 49 | 50 | # Check for common mistakes 51 | - repo: https://github.com/pre-commit/pygrep-hooks 52 | rev: v1.10.0 53 | hooks: 54 | - id: rst-backticks 55 | - id: rst-directive-colons 56 | - id: rst-inline-touching-normal 57 | 58 | # Check for license headers 59 | - repo: https://github.com/emzeat/mz-lictools 60 | rev: v2.7.0 61 | hooks: 62 | - id: license-tools 63 | 64 | # Python linting and formatting using ruff 65 | - repo: https://github.com/astral-sh/ruff-pre-commit 66 | rev: v0.11.13 67 | hooks: 68 | - id: ruff 69 | args: ["--fix", "--show-fixes"] 70 | types_or: [python, pyi, jupyter] 71 | - id: ruff-format 72 | types_or: [python, pyi, jupyter] 73 | 74 | # Also run Black on examples in the documentation 75 | - repo: https://github.com/adamchainz/blacken-docs 76 | rev: 1.19.1 77 | hooks: 78 | - id: blacken-docs 79 | additional_dependencies: [black==24.*] 80 | 81 | # CMake format and lint the CMakeLists.txt files 82 | - repo: https://github.com/cheshirekow/cmake-format-precommit 83 | rev: v0.6.13 84 | hooks: 85 | - id: cmake-format 86 | additional_dependencies: [pyyaml] 87 | types: [file] 88 | files: (\.cmake|CMakeLists.txt)(.in)?$ 89 | 90 | # Clang-format the C++ part of the code base automatically 91 | - repo: https://github.com/pre-commit/mirrors-clang-format 92 | rev: v20.1.5 93 | hooks: 94 | - id: clang-format 95 | types_or: [c++, c, cuda] 96 | 97 | # Format configuration files with prettier 98 | - repo: https://github.com/rbubley/mirrors-prettier 99 | rev: v3.5.3 100 | hooks: 101 | - id: prettier 102 | types_or: [yaml, markdown, html, css, scss, javascript, json] 103 | 104 | # Check static types with mypy 105 | - repo: https://github.com/pre-commit/mirrors-mypy 106 | rev: v1.16.0 107 | hooks: 108 | - id: mypy 109 | files: ^(src/mqt|test/python|noxfile.py) 110 | args: [] 111 | additional_dependencies: 112 | - importlib_resources 113 | - nox 114 | - numpy 115 | - pytest 116 | - mqt.core>=3.0.0rc2 117 | 118 | # Check for spelling 119 | - repo: https://github.com/crate-ci/typos 120 | rev: v1.33.1 121 | hooks: 122 | - id: typos 123 | 124 | # Catch common capitalization mistakes 125 | - repo: local 126 | hooks: 127 | - id: disallow-caps 128 | name: Disallow improper capitalization 129 | language: pygrep 130 | entry: PyBind|Numpy|Cmake|CCache|Github|PyTest|Mqt|Tum 131 | exclude: .pre-commit-config.yaml 132 | 133 | # Check best practices for scientific Python code 134 | - repo: https://github.com/scientific-python/cookie 135 | rev: 2025.01.22 136 | hooks: 137 | - id: sp-repo-review 138 | additional_dependencies: ["repo-review[cli]"] 139 | 140 | # Check JSON schemata 141 | - repo: https://github.com/python-jsonschema/check-jsonschema 142 | rev: 0.33.0 143 | hooks: 144 | - id: check-dependabot 145 | - id: check-github-workflows 146 | - id: check-readthedocs 147 | 148 | # Check the pyproject.toml file 149 | - repo: https://github.com/henryiii/validate-pyproject-schema-store 150 | rev: 2025.04.07 151 | hooks: 152 | - id: validate-pyproject 153 | 154 | # Tidy up BibTeX files 155 | - repo: https://github.com/FlamingTempura/bibtex-tidy 156 | rev: v1.14.0 157 | hooks: 158 | - id: bibtex-tidy 159 | args: 160 | [ 161 | "--align=20", 162 | "--curly", 163 | "--months", 164 | "--blank-lines", 165 | "--sort", 166 | "--strip-enclosing-braces", 167 | "--sort-fields", 168 | "--trailing-commas", 169 | "--remove-empty-fields", 170 | ] 171 | -------------------------------------------------------------------------------- /.python_version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | formats: 4 | - pdf 5 | - htmlzip 6 | 7 | build: 8 | os: ubuntu-24.04 9 | tools: 10 | python: "3.12" 11 | apt_packages: 12 | - graphviz 13 | - inkscape 14 | jobs: 15 | post_checkout: 16 | # Skip docs build if the commit message contains "skip ci" 17 | - (git --no-pager log --pretty="tformat:%s -- %b" -1 | grep -viq "skip ci") || exit 183 18 | # Skip docs build if there are no changes related to docs 19 | - | 20 | if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml src/mqt/ src/python include/*/python .github/contributing* .github/support*; 21 | then 22 | exit 183; 23 | fi 24 | # Unshallow the git clone and fetch tags to get proper version information 25 | - git fetch --unshallow --tags 26 | pre_build: 27 | # Set up uv 28 | - asdf plugin add uv 29 | - asdf install uv latest 30 | - asdf global uv latest 31 | # Set up build time dependencies including a source distribution of mqt-core. 32 | - uv sync --only-group build --only-group docs --no-binary-package mqt-core 33 | # The default version of CMake on Ubuntu 24.04 is too old, so we need to install a newer version. 34 | - uv pip install cmake 35 | build: 36 | html: 37 | - uv run --frozen --no-dev --no-build-isolation-package mqt-qcec -m sphinx -T -b html -d docs/_build/doctrees -D language=en docs $READTHEDOCS_OUTPUT/html 38 | htmlzip: 39 | - uv run --frozen --no-dev --no-build-isolation-package mqt-qcec -m sphinx -T -b dirhtml -d docs/_build/doctrees -D language=en docs docs/_build/dirhtml 40 | - mkdir -p $READTHEDOCS_OUTPUT/htmlzip 41 | - zip -r $READTHEDOCS_OUTPUT/htmlzip/html.zip docs/_build/dirhtml/* 42 | pdf: 43 | - uv run --frozen --no-dev --no-build-isolation-package mqt-qcec -m sphinx -T -b latex -d docs/_build/doctrees -D language=en docs docs/_build/latex 44 | - cd docs/_build/latex && latexmk -pdf -f -dvi- -ps- -interaction=nonstopmode -jobname=$READTHEDOCS_PROJECT 45 | - mkdir -p $READTHEDOCS_OUTPUT/pdf 46 | - cp docs/_build/latex/$READTHEDOCS_PROJECT.pdf $READTHEDOCS_OUTPUT/pdf/$READTHEDOCS_PROJECT.pdf 47 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on a mixture of [Keep a Changelog] and [Common Changelog]. 6 | This project adheres to [Semantic Versioning], with the exception that minor releases may include breaking changes. 7 | 8 | ## [Unreleased] 9 | 10 | ## [3.0.0] - 2025-05-05 11 | 12 | _If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md#300)._ 13 | 14 | ### Added 15 | 16 | - ✨ Support Qiskit 2.0+ ([#571]) ([**@burgholzer**]) 17 | 18 | ### Changed 19 | 20 | - **Breaking**: 🚚 Move MQT QCEC to the [munich-quantum-toolkit] GitHub organization 21 | - **Breaking**: ♻️ Use the `mqt-core` Python package for handling circuits ([#432]) ([**@burgholzer**]) 22 | - **Breaking**: ♻️ Return counterexamples as decision diagrams instead of dense arrays ([#566]) ([**@burgholzer**]) 23 | - **Breaking**: ♻️ Reduce and restructure public interface of the `EquivalenceCheckingManager` ([#566]) ([**@burgholzer**]) 24 | - **Breaking**: ⬆️ Bump minimum required CMake version to `3.24.0` ([#582]) ([**@burgholzer**]) 25 | - 📝 Rework existing project documentation ([#566]) ([**@burgholzer**]) 26 | 27 | ### Removed 28 | 29 | - **Breaking**: 🔥 Remove support for `.real`, `.qc`, `.tfc`, and `GRCS` files ([#582]) ([**@burgholzer**]) 30 | - **Breaking**: 🔥 Remove several re-exports from the top-level `mqt-qcec` package ([#566]) ([**@burgholzer**]) 31 | 32 | ## [2.8.2] - 2025-02-18 33 | 34 | _📚 Refer to the [GitHub Release Notes] for previous changelogs._ 35 | 36 | <!-- Version links --> 37 | 38 | [unreleased]: https://github.com/munich-quantum-toolkit/qcec/compare/v3.0.0...HEAD 39 | [3.0.0]: https://github.com/munich-quantum-toolkit/qcec/compare/v2.8.2...v3.0.0 40 | [2.8.2]: https://github.com/munich-quantum-toolkit/qcec/releases/tag/v2.8.2 41 | 42 | <!-- PR links --> 43 | 44 | [#582]: https://github.com/munich-quantum-toolkit/qcec/pulls/582 45 | [#571]: https://github.com/munich-quantum-toolkit/qcec/pulls/571 46 | [#566]: https://github.com/munich-quantum-toolkit/qcec/pulls/566 47 | [#432]: https://github.com/munich-quantum-toolkit/qcec/pulls/432 48 | 49 | <!-- Contributor --> 50 | 51 | [**@burgholzer**]: https://github.com/burgholzer 52 | 53 | <!-- General links --> 54 | 55 | [Keep a Changelog]: https://keepachangelog.com/en/1.1.0/ 56 | [Common Changelog]: https://common-changelog.org 57 | [Semantic Versioning]: https://semver.org/spec/v2.0.0.html 58 | [GitHub Release Notes]: https://github.com/munich-quantum-toolkit/qcec/releases 59 | [munich-quantum-toolkit]: https://github.com/munich-quantum-toolkit 60 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | title: MQT QCEC - A tool for Quantum Circuit Equivalence Checking 3 | message: >- 4 | If you use this software, please cite both the article from preferred-citation and the software itself. 5 | type: software 6 | authors: 7 | - given-names: Lukas 8 | family-names: Burgholzer 9 | email: lukas.burgholzer@tum.de 10 | affiliation: 'Technical University of Munich, Germany' 11 | orcid: 'https://orcid.org/0000-0003-4699-1316' 12 | - given-names: Tom 13 | family-names: Peham 14 | email: tom.peham@tum.de 15 | affiliation: 'Technical University of Munich, Germany' 16 | orcid: 'https://orcid.org/0000-0003-3434-7881' 17 | - given-names: Robert 18 | family-names: Wille 19 | email: robert.wille@tum.de 20 | affiliation: 'Technical University of Munich, Germany' 21 | orcid: 'https://orcid.org/0000-0002-4993-7860' 22 | 23 | identifiers: 24 | - type: doi 25 | value: 10.1109/TCAD.2020.3032630 26 | - type: url 27 | value: 'https://arxiv.org/abs/2004.08420' 28 | url: 'https://mqt.readthedocs.io/projects/qcec' 29 | license: MIT 30 | preferred-citation: 31 | type: article 32 | title: "Advanced equivalence checking for quantum circuits" 33 | journal: "IEEE Transactions on CAD of Integrated Circuits and Systems" 34 | year: 2021 35 | month: 9 36 | doi: "10.1109/TCAD.2020.3032630" 37 | authors: 38 | - given-names: Lukas 39 | family-names: Burgholzer 40 | email: lukas.burgholzer@tum.de 41 | affiliation: 'Technical University of Munich, Germany' 42 | orcid: 'https://orcid.org/0000-0003-4699-1316' 43 | - given-names: Robert 44 | family-names: Wille 45 | email: robert.wille@tum.de 46 | affiliation: 'Technical University of Munich, Germany' 47 | orcid: 'https://orcid.org/0000-0002-4993-7860' 48 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | # set required cmake version 10 | cmake_minimum_required(VERSION 3.24...4.0) 11 | 12 | project( 13 | mqt-qcec 14 | LANGUAGES C CXX 15 | DESCRIPTION "MQT QCEC - A tool for Quantum Circuit Equivalence Checking") 16 | 17 | option(BUILD_MQT_QCEC_BINDINGS "Build the MQT QCEC Python bindings" OFF) 18 | if(BUILD_MQT_QCEC_BINDINGS) 19 | # ensure that the BINDINGS option is set 20 | set(BINDINGS 21 | ON 22 | CACHE INTERNAL "Enable settings related to Python bindings") 23 | # Some common settings for finding Python 24 | set(Python_FIND_VIRTUALENV 25 | FIRST 26 | CACHE STRING "Give precedence to virtualenvs when searching for Python") 27 | set(Python_FIND_FRAMEWORK 28 | LAST 29 | CACHE STRING "Prefer Brew/Conda to Apple framework Python") 30 | set(Python_ARTIFACTS_INTERACTIVE 31 | ON 32 | CACHE BOOL "Prevent multiple searches for Python and instead cache the results.") 33 | 34 | if(DISABLE_GIL) 35 | message(STATUS "Disabling Python GIL") 36 | add_compile_definitions(Py_GIL_DISABLED) 37 | endif() 38 | 39 | # top-level call to find Python 40 | find_package( 41 | Python 3.9 REQUIRED 42 | COMPONENTS Interpreter Development.Module 43 | OPTIONAL_COMPONENTS Development.SABIModule) 44 | endif() 45 | 46 | # check if this is the master project or used via add_subdirectory 47 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) 48 | set(MQT_QCEC_MASTER_PROJECT ON) 49 | else() 50 | set(MQT_QCEC_MASTER_PROJECT OFF) 51 | endif() 52 | 53 | option(BUILD_MQT_QCEC_TESTS "Also build tests for the MQT QCEC project" ${MQT_QCEC_MASTER_PROJECT}) 54 | 55 | include(cmake/ExternalDependencies.cmake) 56 | 57 | # set the include directory for the build tree 58 | set(MQT_QCEC_INCLUDE_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") 59 | 60 | # add main library code 61 | add_subdirectory(src) 62 | 63 | # add test code 64 | if(BUILD_MQT_QCEC_TESTS) 65 | enable_testing() 66 | include(GoogleTest) 67 | add_subdirectory(test) 68 | endif() 69 | 70 | if(MQT_QCEC_MASTER_PROJECT) 71 | if(NOT TARGET mqt-qcec-uninstall) 72 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in 73 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake IMMEDIATE @ONLY) 74 | add_custom_target(mqt-qcec-uninstall COMMAND ${CMAKE_COMMAND} -P 75 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 76 | endif() 77 | else() 78 | set(mqt-qcec_FOUND 79 | TRUE 80 | CACHE INTERNAL "True if mqt-qcec is found on the system") 81 | endif() 82 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 4 | Copyright (c) 2025 Munich Quantum Software Company GmbH 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | 3 | This document describes breaking changes and how to upgrade. For a complete list of changes including minor and patch releases, please refer to the [changelog](CHANGELOG.md). 4 | 5 | ## [Unreleased] 6 | 7 | ## [3.0.0] 8 | 9 | This major release introduces several breaking changes, including the removal of deprecated features and the introduction of new APIs. 10 | The following paragraphs describe the most important changes and how to adapt your code accordingly. 11 | We intend to provide a more comprehensive migration guide for future releases. 12 | 13 | The major change in this major release is the move to the MQT Core Python package. 14 | This move allows us to make `qiskit` a fully optional dependency and entirely rely on the MQT Core IR for representing circuits. 15 | Additionally, the `mqt-core` Python package now ships all its C++ libraries as shared libraries so that these need not be fetched or built as part of the build process. 16 | This was tricky to achieve cross-platform, and you can find some more backstory in the corresponding [PR](https://github.com/munich-quantum-toolkit/qcec/pulls/432). 17 | We expect this integration to mature over the next few releases. 18 | If you encounter any issues, please let us know. 19 | 20 | Some internals of QCEC have been streamlined and refactored to improve the overall code quality and maintainability. 21 | Most notably, counterexamples are now returned as decision diagrams instead of dense arrays. 22 | This was made possible by the move to the MQT Core Python package, which now also exposes the underlying DD package to Python. 23 | The returned DDs have a [`get_vector()`](https://mqt.readthedocs.io/projects/core/en/v3.0.2/api/mqt/core/dd/#mqt.core.dd.VectorDD.get_vector) method that can be used to convert them to a dense array if needed. 24 | 25 | MQT Core itself dropped support for several parsers in `v3.0.0`, including the `.real`, `.qc`, `.tfc`, and `GRCS` parsers. 26 | The `.real` parser lives on as part of the [MQT SyReC] project. All others have been removed without replacement. 27 | Consequently, these input formats are no longer supported in MQT QCEC. 28 | 29 | MQT QCEC has moved to the [munich-quantum-toolkit](https://github.com/munich-quantum-toolkit) GitHub organization under https://github.com/munich-quantum-toolkit/qcec. 30 | While most links should be automatically redirected, please update any links in your code to point to the new location. 31 | All links in the documentation have been updated accordingly. 32 | 33 | MQT QCEC now requires CMake 3.24 or higher. 34 | Most modern operating systems should have this version available in their package manager. 35 | Alternatively, CMake can be conveniently installed from PyPI using the [`cmake`](https://pypi.org/project/cmake/) package. 36 | 37 | [MQT SyReC]: https://github.com/cda-tum/mqt-syrec 38 | [unreleased]: https://github.com/munich-quantum-toolkit/core/compare/v3.0.0...HEAD 39 | [3.0.0]: https://github.com/munich-quantum-toolkit/qcec/compare/v2.8.2...v3.0.0 40 | -------------------------------------------------------------------------------- /cmake/ExternalDependencies.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | # Declare all external dependencies and make sure that they are available. 10 | 11 | include(FetchContent) 12 | set(FETCH_PACKAGES "") 13 | 14 | if(BUILD_MQT_QCEC_BINDINGS) 15 | # Manually detect the installed mqt-core package. 16 | execute_process( 17 | COMMAND "${Python_EXECUTABLE}" -m mqt.core --cmake_dir 18 | OUTPUT_STRIP_TRAILING_WHITESPACE 19 | OUTPUT_VARIABLE mqt-core_DIR 20 | ERROR_QUIET) 21 | 22 | # Add the detected directory to the CMake prefix path. 23 | if(mqt-core_DIR) 24 | list(APPEND CMAKE_PREFIX_PATH "${mqt-core_DIR}") 25 | message(STATUS "Found mqt-core package: ${mqt-core_DIR}") 26 | endif() 27 | 28 | if(NOT SKBUILD) 29 | # Manually detect the installed pybind11 package. 30 | execute_process( 31 | COMMAND "${Python_EXECUTABLE}" -m pybind11 --cmakedir 32 | OUTPUT_STRIP_TRAILING_WHITESPACE 33 | OUTPUT_VARIABLE pybind11_DIR) 34 | 35 | # Add the detected directory to the CMake prefix path. 36 | list(APPEND CMAKE_PREFIX_PATH "${pybind11_DIR}") 37 | endif() 38 | 39 | # add pybind11 library 40 | find_package(pybind11 2.13.6 CONFIG REQUIRED) 41 | endif() 42 | 43 | # cmake-format: off 44 | set(MQT_CORE_VERSION 3.0.3 45 | CACHE STRING "MQT Core version") 46 | set(MQT_CORE_REV "08e61d14291da0e7e39af3f5e6c46a6641635eb7" 47 | CACHE STRING "MQT Core identifier (tag, branch or commit hash)") 48 | set(MQT_CORE_REPO_OWNER "munich-quantum-toolkit" 49 | CACHE STRING "MQT Core repository owner (change when using a fork)") 50 | # cmake-format: on 51 | FetchContent_Declare( 52 | mqt-core 53 | GIT_REPOSITORY https://github.com/${MQT_CORE_REPO_OWNER}/core.git 54 | GIT_TAG ${MQT_CORE_REV} 55 | FIND_PACKAGE_ARGS ${MQT_CORE_VERSION}) 56 | list(APPEND FETCH_PACKAGES mqt-core) 57 | 58 | if(BUILD_MQT_QCEC_TESTS) 59 | set(gtest_force_shared_crt 60 | ON 61 | CACHE BOOL "" FORCE) 62 | set(GTEST_VERSION 63 | 1.16.0 64 | CACHE STRING "Google Test version") 65 | set(GTEST_URL https://github.com/google/googletest/archive/refs/tags/v${GTEST_VERSION}.tar.gz) 66 | FetchContent_Declare(googletest URL ${GTEST_URL} FIND_PACKAGE_ARGS ${GTEST_VERSION} NAMES GTest) 67 | list(APPEND FETCH_PACKAGES googletest) 68 | endif() 69 | 70 | if(BUILD_MQT_QCEC_BINDINGS) 71 | # add pybind11_json library 72 | FetchContent_Declare( 73 | pybind11_json 74 | GIT_REPOSITORY https://github.com/pybind/pybind11_json 75 | FIND_PACKAGE_ARGS) 76 | list(APPEND FETCH_PACKAGES pybind11_json) 77 | endif() 78 | 79 | # Make all declared dependencies available. 80 | FetchContent_MakeAvailable(${FETCH_PACKAGES}) 81 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | # Source: https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake 10 | 11 | if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") 12 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") 13 | endif() 14 | 15 | file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) 16 | string(REGEX REPLACE "\n" ";" files "${files}") 17 | foreach(file ${files}) 18 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 19 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 20 | exec_program( 21 | "@CMAKE_COMMAND@" ARGS 22 | "-E remove \"$ENV{DESTDIR}${file}\"" 23 | OUTPUT_VARIABLE rm_out 24 | RETURN_VALUE rm_retval) 25 | if(NOT "${rm_retval}" STREQUAL 0) 26 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 27 | endif() 28 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 29 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 30 | endif() 31 | endforeach() 32 | -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ```{include} ../CHANGELOG.md 2 | 3 | ``` 4 | -------------------------------------------------------------------------------- /docs/UPGRADING.md: -------------------------------------------------------------------------------- 1 | ```{include} ../UPGRADING.md 2 | 3 | ``` 4 | -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | .acknowledgements { 2 | margin-top: 1rem; 3 | padding-bottom: 1rem; 4 | padding-top: 1rem; 5 | border-top: 1px solid var(--color-background-border); 6 | font-size: var(--font-size--small); 7 | color: var(--color-foreground-secondary); 8 | } 9 | 10 | .acknowledgements-logos { 11 | display: grid; 12 | grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); 13 | grid-gap: 1em; 14 | align-items: center; 15 | margin-top: 0.5rem; 16 | } 17 | .acknowledgement { 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | } 23 | 24 | /* override the default background color for literal strings */ 25 | body:not([data-theme="light"]) .highlight .sa, 26 | .highlight .sb, 27 | .highlight .sc, 28 | .highlight .dl, 29 | .highlight .sd, 30 | .highlight .s2, 31 | .highlight .se, 32 | .highlight .sh, 33 | .highlight .si, 34 | .highlight .sx, 35 | .highlight .sr, 36 | .highlight .s1, 37 | .highlight .ss, 38 | .highlight .s1, 39 | .highlight .s { 40 | background-color: #00000001; 41 | } 42 | 43 | /* provide dark mode overrides for mystnb variables */ 44 | body:not([data-theme="light"]) { 45 | --mystnb-source-bg-color: #131416; 46 | --mystnb-stdout-bg-color: #1a1c1e; 47 | --mystnb-stderr-bg-color: #442222; 48 | --mystnb-traceback-bg-color: #202020; 49 | } 50 | 51 | body:not([data-theme="light"]) .highlight .gp { 52 | color: #c65d09; 53 | } 54 | -------------------------------------------------------------------------------- /docs/_static/mqt_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/munich-quantum-toolkit/qcec/206ae43ff4b9a12138580dc8c0d4ee1b4bbe0956/docs/_static/mqt_dark.png -------------------------------------------------------------------------------- /docs/_static/mqt_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/munich-quantum-toolkit/qcec/206ae43ff4b9a12138580dc8c0d4ee1b4bbe0956/docs/_static/mqt_light.png -------------------------------------------------------------------------------- /docs/compilation_flow_verification.md: -------------------------------------------------------------------------------- 1 | --- 2 | file_format: mystnb 3 | kernelspec: 4 | name: python3 5 | mystnb: 6 | number_source_lines: true 7 | --- 8 | 9 | # Verifying the Results of Compilation Flows 10 | 11 | ## Quantum Circuit Compilation 12 | 13 | Initially, quantum algorithms are described in a way which is agnostic of the device they are planned to be executed on. 14 | However, physical devices today impose several constraints on the circuits to be executed: 15 | 16 | 1. **Limited gate-set:** Typically, only a small set of gates is natively supported by devices, e.g., consisting of arbitrary single-qubit gates and the two-qubit CNOT operation. 17 | 18 | 2. **Limited connectivity:** Devices frequently limit the pairs of qubits that operations may be applied to. This is usually described by a coupling graph, where the graph's nodes represent the qubits and an edge between two nodes indicates that a CNOT operation may be applied to those qubits. 19 | 20 | 3. **Short coherence times and limited fidelity:** A device's physical qubits are inherently affected by noise. Until a certain threshold concerning the number of available qubits is reached, error correction is not yet an option. 21 | 22 | The first two, i.e., the limited gate-set and connectivity, constitute hard constraints---a computation not conforming to these restrictions may not be executed on the device. 23 | In contrast, the short coherence time and limited gate fidelity represent soft constraints---a quantum circuit may be executed on a device, but it is not guaranteed to produce meaningful results if the circuit, e.g., is too large for the state to stay coherent. 24 | 25 | Just as in classical computing, a conceptual algorithm needs to be compiled to the targeted architecture to address these constraints. 26 | Throughout the compilation process, the gates and the structure of the underlying circuit is changed considerably. 27 | The following figure exemplary illustrates the compilation of a 3-qubit circuit implementing the Grover search algorithm to the 5-qubit IBMQ London architecture. 28 | 29 | ```{image} images/compilation_flow.png 30 | :width: 100% 31 | :alt: Compilation of a quantum circuit 32 | ``` 33 | 34 | It is of utmost importance that, after compilation, the resulting (compiled) circuit still implements the same functionality as the originally given circuit. 35 | This can be guaranteed by verifying the results of the compilation flow, i.e., checking the equivalence of the original circuit description with the compiled quantum circuit. 36 | 37 | ## Using QCEC to Verify Compilation Flow Results 38 | 39 | First, construct your quantum circuit as usual. 40 | 41 | ```{code-cell} ipython3 42 | from qiskit import QuantumCircuit 43 | 44 | circ = QuantumCircuit(3) 45 | circ.x(2) 46 | circ.h(range(3)) 47 | circ.ccx(0, 1, 2) 48 | circ.h(range(2)) 49 | circ.x(range(2)) 50 | circ.h(1) 51 | circ.cx(0, 1) 52 | circ.h(1) 53 | circ.x(range(2)) 54 | circ.h(range(2)) 55 | circ.measure_all() 56 | circ.draw(output="mpl", style="iqp") 57 | ``` 58 | 59 | ```{note} 60 | It is essential to include measurements at the end of the circuit, since the equivalence checker uses the measurements to determine the final location of the logical qubits in the compiled circuit. 61 | Failing to do so may result in incorrect results because the checker will then simply assume that the logical qubits are mapped to the physical qubits in the same order as they appear in the circuit. 62 | Make sure to insert measurements *before* the circuit is compiled to the target architecture. 63 | ``` 64 | 65 | Then, compile the circuit to the desired target architecture. 66 | 67 | ```{code-cell} ipython3 68 | from qiskit import transpile 69 | from qiskit.providers.fake_provider import GenericBackendV2 70 | 71 | # define the target architecture 72 | backend = GenericBackendV2(num_qubits=5, coupling_map=[[0, 1], [1, 0], [1, 2], [2, 1], [1, 3], [3, 1], [3, 4], [4, 3]]) 73 | 74 | # compile circuit to the target architecture 75 | optimization_level = 1 76 | circ_comp = transpile(circ, backend=backend, optimization_level=optimization_level) 77 | circ_comp.draw(output="mpl", fold=-1, style="iqp") 78 | ``` 79 | 80 | Then, using QCEC to verify that the circuit has been compiled correctly is as easy as 81 | 82 | ```{code-cell} ipython3 83 | from mqt import qcec 84 | 85 | results = qcec.verify_compilation(circ, circ_comp, optimization_level=optimization_level) 86 | results.equivalence 87 | ``` 88 | 89 | Check out the {py:func}`reference documentation <.verify_compilation>` for more information. 90 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | ```{include} ../.github/contributing.md 2 | 3 | ``` 4 | -------------------------------------------------------------------------------- /docs/images/compilation_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/munich-quantum-toolkit/qcec/206ae43ff4b9a12138580dc8c0d4ee1b4bbe0956/docs/images/compilation_flow.png -------------------------------------------------------------------------------- /docs/images/verification_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/munich-quantum-toolkit/qcec/206ae43ff4b9a12138580dc8c0d4ee1b4bbe0956/docs/images/verification_flow.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # MQT QCEC - A tool for Quantum Circuit Equivalence Checking 2 | 3 | ```{raw} latex 4 | \begin{abstract} 5 | ``` 6 | 7 | MQT QCEC is an open-source C++17 and Python library for {doc}`quantum circuit equivalence checking <equivalence_checking>` developed as part of the _{doc}`Munich Quantum Toolkit (MQT) <mqt:index>`_ [^1]. 8 | 9 | This documentation provides a comprehensive guide to the MQT QCEC library, including {doc}`installation instructions <installation>`, a {doc}`quickstart guide <quickstart>`, and detailed {doc}`API documentation <api/mqt/qcec/index>`. 10 | The source code of MQT QCEC is publicly available on GitHub at [munich-quantum-toolkit/qcec](https://github.com/munich-quantum-toolkit/qcec), while pre-built binaries are available via [PyPI](https://pypi.org/project/mqt.qcec/) for all major operating systems and all modern Python versions. 11 | MQT QCEC is fully compatible with Qiskit 1.0 and above. 12 | 13 | [^1]: 14 | The _[Munich Quantum Toolkit (MQT)](https://mqt.readthedocs.io)_ is a collection of software tools for quantum computing developed by the [Chair for Design Automation](https://www.cda.cit.tum.de/) at the [Technical University of Munich](https://www.tum.de/) as well as the [Munich Quantum Software Company (MQSC)](https://munichquantum.software). 15 | Among others, it is part of the [Munich Quantum Software Stack (MQSS)](https://www.munich-quantum-valley.de/research/research-areas/mqss) ecosystem, which is being developed as part of the [Munich Quantum Valley (MQV)](https://www.munich-quantum-valley.de) initiative. 16 | 17 | ````{only} latex 18 | ```{note} 19 | A live version of this document is available at [mqt.readthedocs.io/projects/qcec](https://mqt.readthedocs.io/projects/qcec). 20 | ``` 21 | ```` 22 | 23 | ```{raw} latex 24 | \end{abstract} 25 | 26 | \sphinxtableofcontents 27 | ``` 28 | 29 | ```{toctree} 30 | :hidden: 31 | 32 | self 33 | ``` 34 | 35 | ```{toctree} 36 | :maxdepth: 2 37 | :caption: User Guide 38 | 39 | installation 40 | quickstart 41 | equivalence_checking 42 | compilation_flow_verification 43 | parametrized_circuits 44 | partial_equivalence 45 | references 46 | CHANGELOG 47 | UPGRADING 48 | ``` 49 | 50 | ````{only} not latex 51 | ```{toctree} 52 | :maxdepth: 2 53 | :titlesonly: 54 | :caption: Developers 55 | :glob: 56 | 57 | contributing 58 | support 59 | development_guide 60 | ``` 61 | ```` 62 | 63 | ```{toctree} 64 | :hidden: 65 | :maxdepth: 6 66 | :caption: API Reference 67 | 68 | api/mqt/qcec/index 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/parametrized_circuits.md: -------------------------------------------------------------------------------- 1 | --- 2 | file_format: mystnb 3 | kernelspec: 4 | name: python3 5 | mystnb: 6 | number_source_lines: true 7 | --- 8 | 9 | # Verifying Parameterized Quantum Circuits 10 | 11 | ## Variational Quantum Algorithms 12 | 13 | Variational quantum algorithms are a family of mixed quantum-classical algorithms that try to achieve a quantum advantage via low-depth circuits. This is achieved by offloading a substantial amount of computational work to a classical processor. The quantum circuits employed by variational quantum algorithms involve _parameterized gates_ which depend on some a-priori uninstantiated variable. 14 | 15 | Variational quantum algorithms try to optimize the circuit's parameters in each iteration with the classical post-processor while the quantum circuit is used to compute the cost function that is being optimized. Because recompiling the quantum circuit in each of these iterations is a costly procedure, the circuit is usually compiled in _parameterized_ form in which the parameters tuned by the classical optimization routine are not bound to specific values. 16 | 17 | As is the case with parameter-free circuits, errors can be made during the compilation process. Therefore, verifying the correctness of compilations of parameterized quantum circuits is an important task for near-term quantum computing. 18 | 19 | ## Equivalence Checking of Parameterized Quantum Circuits 20 | 21 | Having unbound parameters in a quantum circuits brings new challenges to the task of quantum circuit verification as many data structures have difficulty supporting symbolic computations directly. 22 | However, _ZX-diagrams_ are an exceptions to this as most rewrite rules used for equivalence checking with the _ZX-calculus_ only involve summation of parameters. 23 | The ZX-calculus equivalence checker in QCEC cannot be used to prove non-equivalence of quantum circuits. 24 | To still show non-equivalence of parameterized quantum circuits QCEC uses a scheme of repeatedly instantiating a circuits parameters in such a way as to make the check as simple as possible while still guaranteeing that either equivalence or non-equivalence can be proven. 25 | The resulting _equivalence checking flow_ looks as follows 26 | 27 | ```{image} images/parameterized_flow.svg 28 | :width: 90% 29 | :align: center 30 | :alt: Equivalence Checking Flow for Parameterized Quantum Circuits 31 | ``` 32 | 33 | See {cite:p}`peham2023EquivalenceCheckingParameterizedCircuits` for more information. 34 | 35 | ## Using QCEC to Verify Parameterized Quantum Circuits 36 | 37 | Consider the following quantum circuit 38 | 39 | ```{code-cell} ipython3 40 | from qiskit import QuantumCircuit 41 | from qiskit.circuit import Parameter 42 | 43 | alpha = Parameter("alpha") 44 | beta = Parameter("beta") 45 | 46 | qc_lhs = QuantumCircuit(2) 47 | qc_lhs.rz(alpha, 1) 48 | qc_lhs.cx(0, 1) 49 | qc_lhs.rz(beta, 1) 50 | qc_lhs.cx(0, 1) 51 | qc_lhs.draw(output="mpl", style="iqp") 52 | ``` 53 | 54 | A well known commutation rule for the $R_Z$ gate, states that this circuit is equivalent to the following one 55 | 56 | ```{code-cell} ipython3 57 | qc_rhs = QuantumCircuit(2) 58 | qc_rhs.cx(0, 1) 59 | qc_rhs.rz(beta, 1) 60 | qc_rhs.cx(0, 1) 61 | qc_rhs.rz(alpha, 1) 62 | qc_rhs.draw(output="mpl", style="iqp") 63 | ``` 64 | 65 | This equality can be proved with QCEC by using the {py:func}`.verify` function just as with any regular circuit 66 | 67 | ```{code-cell} ipython3 68 | from mqt import qcec 69 | 70 | qcec.verify(qc_lhs, qc_rhs) 71 | ``` 72 | 73 | QCEC also manages to show non-equivalence of parameterized quantum circuits. 74 | It is easy to erroneously exchange the parameters in the above commutation rule. 75 | 76 | ```{code-cell} ipython3 77 | qc_rhs_err = QuantumCircuit(2) 78 | qc_rhs_err.cx(0, 1) 79 | qc_rhs_err.rz(alpha, 1) 80 | qc_rhs_err.cx(0, 1) 81 | qc_rhs_err.rz(beta, 1) 82 | qc_rhs_err.draw(output="mpl", style="iqp") 83 | ``` 84 | 85 | QCEC will tell us that this is incorrect 86 | 87 | ```{code-cell} ipython3 88 | qcec.verify(qc_lhs, qc_rhs_err) 89 | ``` 90 | 91 | Check out the {py:func}`reference documentation <.verify>` for more information. 92 | -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | --- 2 | file_format: mystnb 3 | kernelspec: 4 | name: python3 5 | mystnb: 6 | number_source_lines: true 7 | --- 8 | 9 | # Quickstart 10 | 11 | Assume you want to prove that the following two circuits are equivalent: 12 | 13 | ```{code-cell} ipython3 14 | from qiskit import QuantumCircuit 15 | 16 | qc1 = QuantumCircuit(2) 17 | qc1.cx(0, 1) 18 | qc1.draw(output="mpl", style="iqp") 19 | ``` 20 | 21 | ```{code-cell} ipython3 22 | from qiskit import QuantumCircuit 23 | 24 | qc2 = QuantumCircuit(2) 25 | qc2.h(0) 26 | qc2.h(1) 27 | qc2.cx(1, 0) 28 | qc2.h(1) 29 | qc2.h(0) 30 | qc2.draw(output="mpl", style="iqp") 31 | ``` 32 | 33 | Then, using QCEC to check the equivalence of these two circuits is as easy as 34 | 35 | ```{code-cell} ipython3 36 | from mqt import qcec 37 | 38 | qcec.verify(qc1, qc2) 39 | ``` 40 | 41 | Check out the {py:func}`reference documentation <.verify>` for more information. 42 | -------------------------------------------------------------------------------- /docs/references.md: -------------------------------------------------------------------------------- 1 | ```{raw} latex 2 | \begingroup 3 | \renewcommand\section[1]{\endgroup} 4 | \phantomsection 5 | ``` 6 | 7 | ```{only} html 8 | # References 9 | 10 | *QCEC* is academic software. Thus, many of its built-in algorithms have been published as scientific papers. 11 | 12 | If you use *QCEC* in your work, we would appreciate if you cited {cite:p}`burgholzer2021advanced` (which subsumes {cite:p}`burgholzer2020ImprovedDDbasedEquivalence` and {cite:p}`burgholzer2020PowerSimulationEquivalence`). 13 | 14 | Furthermore, if you use any of the particular algorithms such as 15 | 16 | - the compilation flow result verification scheme {cite:p}`burgholzer2020verifyingResultsIBM`, 17 | - the dedicated stimuli generation schemes {cite:p}`burgholzer2021randomStimuliGenerationQuantum`, 18 | - the transformation scheme for circuits containing non-unitaries {cite:p}`burgholzer2022handlingNonUnitaries`, 19 | - the equivalence checker based on ZX-diagrams {cite:p}`peham2022equivalenceCheckingZXCalculus`, or 20 | - the method for checking equivalence of parameterized circuits {cite:p}`peham2023EquivalenceCheckingParameterizedCircuits` 21 | 22 | please consider citing their respective papers as well. A full list of references is given below. 23 | ``` 24 | 25 | ```{bibliography} 26 | 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/support.md: -------------------------------------------------------------------------------- 1 | ```{include} ../.github/support.md 2 | 3 | ``` 4 | -------------------------------------------------------------------------------- /include/Configuration.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "checker/dd/applicationscheme/ApplicationScheme.hpp" 14 | #include "checker/dd/applicationscheme/GateCostApplicationScheme.hpp" 15 | #include "checker/dd/simulation/StateType.hpp" 16 | #include "dd/DDDefinitions.hpp" 17 | #include "dd/RealNumber.hpp" 18 | 19 | #include <algorithm> 20 | #include <cstddef> 21 | #include <iosfwd> 22 | #include <nlohmann/json_fwd.hpp> 23 | #include <string> 24 | #include <thread> 25 | 26 | namespace ec { 27 | 28 | class Configuration { 29 | public: 30 | // configuration options for execution 31 | struct Execution { 32 | dd::fp numericalTolerance = dd::RealNumber::eps; 33 | 34 | bool parallel = true; 35 | std::size_t nthreads = std::max(2U, std::thread::hardware_concurrency()); 36 | double timeout = 0.; // in seconds 37 | 38 | bool runConstructionChecker = false; 39 | bool runSimulationChecker = true; 40 | bool runAlternatingChecker = true; 41 | bool runZXChecker = true; 42 | }; 43 | 44 | // configuration options for pre-check optimizations 45 | struct Optimizations { 46 | bool fuseSingleQubitGates = true; 47 | bool reconstructSWAPs = true; 48 | bool removeDiagonalGatesBeforeMeasure = false; 49 | bool transformDynamicCircuit = false; 50 | bool reorderOperations = true; 51 | bool backpropagateOutputPermutation = false; 52 | bool elidePermutations = true; 53 | }; 54 | 55 | // configuration options for application schemes 56 | struct Application { 57 | ApplicationSchemeType constructionScheme = 58 | ApplicationSchemeType::Proportional; 59 | ApplicationSchemeType simulationScheme = 60 | ApplicationSchemeType::Proportional; 61 | ApplicationSchemeType alternatingScheme = 62 | ApplicationSchemeType::Proportional; 63 | 64 | // options for the gate cost application scheme 65 | std::string profile; 66 | CostFunction costFunction = [](const GateCostLookupTableKeyType& /*key*/) { 67 | return 1U; 68 | }; 69 | }; 70 | 71 | struct Functionality { 72 | double traceThreshold = 1e-8; 73 | bool checkPartialEquivalence = false; 74 | }; 75 | 76 | // configuration options for the simulation scheme 77 | struct Simulation { 78 | double fidelityThreshold = 1e-8; 79 | std::size_t maxSims = computeMaxSims(); 80 | StateType stateType = StateType::ComputationalBasis; 81 | std::size_t seed = 0U; 82 | 83 | // this function makes sure that the maximum number of simulations is 84 | // configured properly. 85 | static std::size_t computeMaxSims() { 86 | constexpr std::size_t defaultMaxSims = 16U; 87 | constexpr std::size_t defaultConfiguredOtherCheckers = 2U; 88 | const auto systemThreads = std::thread::hardware_concurrency(); 89 | // catch the case where hardware_concurrency() returns 0 or the other 90 | // pre-configured checkers already use up all the available threads 91 | if (systemThreads < defaultConfiguredOtherCheckers) { 92 | return defaultMaxSims; 93 | } 94 | return std::max(defaultMaxSims, 95 | systemThreads - defaultConfiguredOtherCheckers); 96 | } 97 | }; 98 | 99 | struct Parameterized { 100 | double parameterizedTol = 1e-12; 101 | std::size_t nAdditionalInstantiations = 0; 102 | }; 103 | 104 | Execution execution{}; 105 | Optimizations optimizations{}; 106 | Application application{}; 107 | Functionality functionality{}; 108 | Simulation simulation{}; 109 | Parameterized parameterized{}; 110 | 111 | [[nodiscard]] bool anythingToExecute() const noexcept; 112 | 113 | [[nodiscard]] bool onlySingleTask() const noexcept; 114 | 115 | [[nodiscard]] bool onlyZXCheckerConfigured() const noexcept; 116 | 117 | [[nodiscard]] bool onlySimulationCheckerConfigured() const noexcept; 118 | 119 | [[nodiscard]] nlohmann::json json() const; 120 | 121 | [[nodiscard]] std::string toString() const; 122 | 123 | friend std::ostream& operator<<(std::ostream& os, 124 | const Configuration& config); 125 | }; 126 | } // namespace ec 127 | -------------------------------------------------------------------------------- /include/EquivalenceCriterion.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include <cstdint> 14 | #include <iostream> 15 | #include <string> 16 | 17 | namespace ec { 18 | enum class EquivalenceCriterion : std::uint8_t { 19 | NotEquivalent = 0, 20 | Equivalent = 1, 21 | NoInformation = 2, 22 | ProbablyEquivalent = 3, 23 | EquivalentUpToGlobalPhase = 4, 24 | EquivalentUpToPhase = 5, 25 | ProbablyNotEquivalent = 6 26 | }; 27 | 28 | inline std::string toString(const EquivalenceCriterion& criterion) noexcept { 29 | switch (criterion) { 30 | case EquivalenceCriterion::NotEquivalent: 31 | return "not_equivalent"; 32 | case EquivalenceCriterion::Equivalent: 33 | return "equivalent"; 34 | case EquivalenceCriterion::ProbablyEquivalent: 35 | return "probably_equivalent"; 36 | case EquivalenceCriterion::EquivalentUpToGlobalPhase: 37 | return "equivalent_up_to_global_phase"; 38 | case EquivalenceCriterion::EquivalentUpToPhase: 39 | return "equivalent_up_to_phase"; 40 | case EquivalenceCriterion::ProbablyNotEquivalent: 41 | return "probably_not_equivalent"; 42 | default: 43 | return "no_information"; 44 | } 45 | } 46 | 47 | inline EquivalenceCriterion fromString(const std::string& criterion) noexcept { 48 | if ((criterion == "not_equivalent") || (criterion == "0")) { 49 | return EquivalenceCriterion::NotEquivalent; 50 | } 51 | if ((criterion == "equivalent") || (criterion == "1")) { 52 | return EquivalenceCriterion::Equivalent; 53 | } 54 | if ((criterion == "probably_equivalent") || (criterion == "2")) { 55 | return EquivalenceCriterion::ProbablyEquivalent; 56 | } 57 | if ((criterion == "equivalent_up_to_global_phase") || (criterion == "3")) { 58 | return EquivalenceCriterion::EquivalentUpToGlobalPhase; 59 | } 60 | if ((criterion == "equivalent_up_to_phase") || (criterion == "4")) { 61 | return EquivalenceCriterion::EquivalentUpToPhase; 62 | } 63 | if ((criterion == "no_information") || (criterion == "5")) { 64 | return EquivalenceCriterion::NoInformation; 65 | } 66 | if ((criterion == "probably_not_equivalent") || (criterion == "6")) { 67 | return EquivalenceCriterion::ProbablyNotEquivalent; 68 | } 69 | std::cerr << "Unknown equivalence criterion: " << criterion 70 | << ". Defaulting to `no_information`.\n"; 71 | return EquivalenceCriterion::NoInformation; 72 | } 73 | 74 | inline std::istream& operator>>(std::istream& in, 75 | EquivalenceCriterion& criterion) { 76 | std::string token; 77 | in >> token; 78 | 79 | if (token.empty()) { 80 | in.setstate(std::istream::failbit); 81 | return in; 82 | } 83 | 84 | criterion = fromString(token); 85 | return in; 86 | } 87 | 88 | inline std::ostream& operator<<(std::ostream& out, 89 | const EquivalenceCriterion& criterion) { 90 | out << toString(criterion); 91 | return out; 92 | } 93 | } // namespace ec 94 | -------------------------------------------------------------------------------- /include/ThreadSafeQueue.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include <chrono> 14 | #include <condition_variable> 15 | #include <memory> 16 | #include <mutex> 17 | 18 | namespace ec { 19 | template <typename T> class ThreadSafeQueue { 20 | public: 21 | ThreadSafeQueue() : tail(head.get()) {} 22 | 23 | ThreadSafeQueue(const ThreadSafeQueue& other) = delete; 24 | 25 | ThreadSafeQueue& operator=(const ThreadSafeQueue& other) = delete; 26 | 27 | std::shared_ptr<T> waitAndPop() { 28 | auto const oldHead = waitPopHead(); 29 | return oldHead->data; 30 | } 31 | 32 | template <typename Clock, typename Dur> 33 | std::shared_ptr<T> 34 | waitAndPopUntil(const std::chrono::time_point<Clock, Dur>& timepoint) { 35 | if (const auto oldHead = waitPopHeadUntil(timepoint)) { 36 | return oldHead->data; 37 | } 38 | return nullptr; 39 | } 40 | 41 | void push(T value) { 42 | auto data(std::make_shared<T>(std::move(value))); 43 | auto p = std::make_unique<Node>(); 44 | { 45 | const std::lock_guard tailLock(tailMutex); 46 | tail->data = data; 47 | Node* const newTail = p.get(); 48 | tail->next = std::move(p); 49 | tail = newTail; 50 | } 51 | dataCond.notify_one(); 52 | } 53 | [[nodiscard]] bool empty() { 54 | const std::lock_guard headLock(headMutex); 55 | return head.get() == getTail(); 56 | } 57 | 58 | private: 59 | struct Node { 60 | std::shared_ptr<T> data; 61 | std::unique_ptr<Node> next; 62 | }; 63 | std::mutex headMutex; 64 | std::unique_ptr<Node> head = std::make_unique<Node>(); 65 | std::mutex tailMutex; 66 | Node* tail; 67 | std::condition_variable dataCond; 68 | 69 | auto getTail() { 70 | const std::lock_guard tailLock(tailMutex); 71 | return tail; 72 | } 73 | 74 | auto popHead() { 75 | auto oldHead = std::move(head); 76 | head = std::move(oldHead->next); 77 | return oldHead; 78 | } 79 | 80 | auto waitForData() { 81 | std::unique_lock headLock(headMutex); 82 | dataCond.wait(headLock, [this] { return head.get() != getTail(); }); 83 | return headLock; 84 | } 85 | 86 | template <typename Clock, typename Dur> 87 | auto waitForDataUntil(const std::chrono::time_point<Clock, Dur>& timepoint) { 88 | std::unique_lock headLock(headMutex); 89 | dataCond.wait_until(headLock, timepoint, 90 | [this] { return head.get() != getTail(); }); 91 | return headLock; 92 | } 93 | 94 | auto waitPopHead() { 95 | [[maybe_unused]] auto headLock(waitForData()); 96 | return popHead(); 97 | } 98 | 99 | template <typename Clock, typename Dur> 100 | auto waitPopHeadUntil(const std::chrono::time_point<Clock, Dur>& timepoint) { 101 | [[maybe_unused]] auto headLock(waitForDataUntil(timepoint)); 102 | if (head.get() == getTail()) { 103 | return std::unique_ptr<Node>(); 104 | } 105 | return popHead(); 106 | } 107 | }; 108 | } // namespace ec 109 | -------------------------------------------------------------------------------- /include/checker/EquivalenceChecker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "Configuration.hpp" 14 | #include "EquivalenceCriterion.hpp" 15 | #include "ir/QuantumComputation.hpp" 16 | 17 | #include <algorithm> 18 | #include <atomic> 19 | #include <cstddef> 20 | #include <nlohmann/json_fwd.hpp> 21 | #include <utility> 22 | 23 | namespace ec { 24 | class EquivalenceChecker { 25 | public: 26 | EquivalenceChecker(const qc::QuantumComputation& circ1, 27 | const qc::QuantumComputation& circ2, 28 | Configuration config) noexcept 29 | : qc1(&circ1), qc2(&circ2), 30 | nqubits(std::max(qc1->getNqubits(), qc2->getNqubits())), 31 | configuration(std::move(config)) {}; 32 | 33 | virtual ~EquivalenceChecker() = default; 34 | 35 | virtual EquivalenceCriterion run() = 0; 36 | 37 | [[nodiscard]] EquivalenceCriterion getEquivalence() const noexcept { 38 | return equivalence; 39 | } 40 | [[nodiscard]] double getRuntime() const noexcept { return runtime; } 41 | 42 | virtual void json(nlohmann::json& j) const noexcept; 43 | 44 | void signalDone() { done.store(true, std::memory_order_relaxed); } 45 | [[nodiscard]] auto isDone() const { 46 | return done.load(std::memory_order_relaxed); 47 | } 48 | 49 | protected: 50 | qc::QuantumComputation const* qc1; 51 | qc::QuantumComputation const* qc2; 52 | 53 | std::size_t nqubits{}; 54 | 55 | Configuration configuration; 56 | 57 | EquivalenceCriterion equivalence = EquivalenceCriterion::NoInformation; 58 | double runtime{}; 59 | 60 | private: 61 | std::atomic<bool> done{false}; 62 | }; 63 | 64 | } // namespace ec 65 | -------------------------------------------------------------------------------- /include/checker/dd/DDAlternatingChecker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "DDEquivalenceChecker.hpp" 14 | #include "EquivalenceCriterion.hpp" 15 | #include "dd/Node.hpp" 16 | #include "ir/QuantumComputation.hpp" 17 | 18 | #include <nlohmann/json_fwd.hpp> 19 | 20 | namespace qc { 21 | class QuantumComputation; 22 | } 23 | 24 | namespace ec { 25 | class Configuration; 26 | 27 | class DDAlternatingChecker final : public DDEquivalenceChecker<dd::MatrixDD> { 28 | public: 29 | DDAlternatingChecker(const qc::QuantumComputation& circ1, 30 | const qc::QuantumComputation& circ2, 31 | Configuration config); 32 | 33 | void json(nlohmann::json& j) const noexcept override; 34 | 35 | /// a function to determine whether the alternating checker can handle 36 | /// checking both circuits. In particular, it checks whether both circuits 37 | /// contain non-idle ancillaries. 38 | static bool canHandle(const qc::QuantumComputation& qc1, 39 | const qc::QuantumComputation& qc2); 40 | 41 | private: 42 | dd::MatrixDD functionality{}; 43 | 44 | void initialize() override; 45 | void execute() override; 46 | void finish() override; 47 | void postprocess() override; 48 | EquivalenceCriterion checkEquivalence() override; 49 | 50 | // at some point this routine should probably make its way into the QFR 51 | // library 52 | [[nodiscard]] bool gatesAreIdentical() const; 53 | }; 54 | } // namespace ec 55 | -------------------------------------------------------------------------------- /include/checker/dd/DDConstructionChecker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "DDEquivalenceChecker.hpp" 14 | #include "checker/dd/TaskManager.hpp" 15 | #include "dd/Node.hpp" 16 | 17 | #include <nlohmann/json_fwd.hpp> 18 | 19 | namespace qc { 20 | class QuantumComputation; 21 | } 22 | 23 | namespace ec { 24 | class Configuration; 25 | 26 | class DDConstructionChecker final : public DDEquivalenceChecker<dd::MatrixDD> { 27 | public: 28 | DDConstructionChecker(const qc::QuantumComputation& circ1, 29 | const qc::QuantumComputation& circ2, 30 | Configuration config); 31 | 32 | void json(nlohmann::json& j) const noexcept override; 33 | 34 | private: 35 | void initializeTask(TaskManager<dd::MatrixDD>& taskManager) override; 36 | }; 37 | } // namespace ec 38 | -------------------------------------------------------------------------------- /include/checker/dd/DDEquivalenceChecker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "Configuration.hpp" 14 | #include "EquivalenceCriterion.hpp" 15 | #include "TaskManager.hpp" 16 | #include "applicationscheme/ApplicationScheme.hpp" 17 | #include "checker/EquivalenceChecker.hpp" 18 | #include "dd/DDpackageConfig.hpp" 19 | #include "dd/Package.hpp" 20 | #include "ir/QuantumComputation.hpp" 21 | 22 | #include <cstddef> 23 | #include <memory> 24 | #include <nlohmann/json_fwd.hpp> 25 | #include <utility> 26 | 27 | namespace ec { 28 | template <class DDType> class DDEquivalenceChecker : public EquivalenceChecker { 29 | public: 30 | DDEquivalenceChecker( 31 | const qc::QuantumComputation& circ1, const qc::QuantumComputation& circ2, 32 | Configuration config, 33 | const dd::DDPackageConfig& packageConfig = dd::DDPackageConfig{}) 34 | : EquivalenceChecker(circ1, circ2, std::move(config)), 35 | dd(std::make_unique<dd::Package>(nqubits, packageConfig)), 36 | taskManager1(TaskManager<DDType>(circ1, *dd)), 37 | taskManager2(TaskManager<DDType>(circ2, *dd)) {} 38 | 39 | EquivalenceCriterion run() override; 40 | 41 | void json(nlohmann::json& j) const noexcept override; 42 | 43 | protected: 44 | std::unique_ptr<dd::Package> dd; 45 | 46 | TaskManager<DDType> taskManager1; 47 | TaskManager<DDType> taskManager2; 48 | 49 | std::unique_ptr<ApplicationScheme<DDType>> applicationScheme; 50 | 51 | std::size_t maxActiveNodes{}; 52 | 53 | void initializeApplicationScheme(ApplicationSchemeType scheme); 54 | 55 | // at some point this routine should probably make its way into the DD package 56 | // in some form 57 | EquivalenceCriterion equals(const DDType& e, const DDType& f); 58 | 59 | virtual void initializeTask(TaskManager<DDType>& taskManager); 60 | virtual void initialize(); 61 | virtual void execute(); 62 | virtual void finish(); 63 | virtual void postprocessTask(TaskManager<DDType>& task); 64 | virtual void postprocess(); 65 | virtual EquivalenceCriterion checkEquivalence(); 66 | }; 67 | 68 | } // namespace ec 69 | -------------------------------------------------------------------------------- /include/checker/dd/DDPackageConfigs.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "dd/DDpackageConfig.hpp" 14 | 15 | #include <cstddef> 16 | 17 | namespace ec { 18 | struct SimulationDDPackageConfig : public dd::DDPackageConfig { 19 | // simulation requires more resources for vectors. 20 | static constexpr std::size_t UT_VEC_NBUCKET = 65'536U; 21 | static constexpr std::size_t CT_VEC_ADD_NBUCKET = 65'536U; 22 | static constexpr std::size_t CT_MAT_VEC_MULT_NBUCKET = 65'536U; 23 | static constexpr std::size_t CT_VEC_INNER_PROD_NBUCKET = 32'768U; 24 | 25 | // simulation only needs matrices for representing operations. Hence, very 26 | // little is needed here. 27 | static constexpr std::size_t UT_MAT_NBUCKET = 128U; 28 | static constexpr std::size_t UT_MAT_INITIAL_ALLOCATION_SIZE = 32U; 29 | 30 | // simulation needs no matrix addition, conjugate transposition, matrix-matrix 31 | // multiplication, or kronecker products. 32 | static constexpr std::size_t CT_MAT_ADD_NBUCKET = 1U; 33 | static constexpr std::size_t CT_MAT_CONJ_TRANS_NBUCKET = 1U; 34 | static constexpr std::size_t CT_MAT_MAT_MULT_NBUCKET = 1U; 35 | static constexpr std::size_t CT_VEC_KRON_NBUCKET = 1U; 36 | static constexpr std::size_t CT_MAT_KRON_NBUCKET = 1U; 37 | }; 38 | 39 | struct ConstructionDDPackageConfig : public dd::DDPackageConfig { 40 | // construction requires more resources for matrices. 41 | static constexpr std::size_t UT_MAT_NBUCKET = 65'536U; 42 | static constexpr std::size_t CT_MAT_ADD_NBUCKET = 65'536U; 43 | static constexpr std::size_t CT_MAT_MAT_MULT_NBUCKET = 65'536U; 44 | static constexpr std::size_t CT_MAT_CONJ_TRANS_NBUCKET = 32'768U; 45 | 46 | // construction does not need any vector nodes 47 | static constexpr std::size_t UT_VEC_NBUCKET = 1U; 48 | static constexpr std::size_t UT_VEC_INITIAL_ALLOCATION_SIZE = 1U; 49 | 50 | // construction needs no vector addition, matrix-vector multiplication, 51 | // kronecker products, or inner products. 52 | static constexpr std::size_t CT_VEC_ADD_NBUCKET = 1U; 53 | static constexpr std::size_t CT_MAT_VEC_MULT_NBUCKET = 1U; 54 | static constexpr std::size_t CT_VEC_KRON_NBUCKET = 1U; 55 | static constexpr std::size_t CT_MAT_KRON_NBUCKET = 1U; 56 | static constexpr std::size_t CT_VEC_INNER_PROD_NBUCKET = 1U; 57 | }; 58 | 59 | struct AlternatingDDPackageConfig : public dd::DDPackageConfig { 60 | // The alternating checker requires more resources for matrices. 61 | static constexpr std::size_t UT_MAT_NBUCKET = 65'536U; 62 | static constexpr std::size_t CT_MAT_ADD_NBUCKET = 65'536U; 63 | static constexpr std::size_t CT_MAT_MAT_MULT_NBUCKET = 65'536U; 64 | 65 | // The alternating checker does not need any vector nodes 66 | static constexpr std::size_t UT_VEC_NBUCKET = 1U; 67 | static constexpr std::size_t UT_VEC_INITIAL_ALLOCATION_SIZE = 1U; 68 | 69 | // The alternating needs no vector addition, matrix-vector multiplication, 70 | // kronecker products, or inner products. 71 | static constexpr std::size_t CT_VEC_ADD_NBUCKET = 1U; 72 | static constexpr std::size_t CT_MAT_VEC_MULT_NBUCKET = 1U; 73 | static constexpr std::size_t CT_VEC_KRON_NBUCKET = 1U; 74 | static constexpr std::size_t CT_MAT_KRON_NBUCKET = 1U; 75 | static constexpr std::size_t CT_VEC_INNER_PROD_NBUCKET = 1U; 76 | }; 77 | } // namespace ec 78 | -------------------------------------------------------------------------------- /include/checker/dd/DDSimulationChecker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "DDEquivalenceChecker.hpp" 14 | #include "EquivalenceCriterion.hpp" 15 | #include "checker/dd/TaskManager.hpp" 16 | #include "dd/Node.hpp" 17 | 18 | #include <nlohmann/json_fwd.hpp> 19 | 20 | namespace qc { 21 | class QuantumComputation; 22 | } 23 | 24 | namespace ec { 25 | class Configuration; 26 | class StateGenerator; 27 | 28 | class DDSimulationChecker final : public DDEquivalenceChecker<dd::VectorDD> { 29 | public: 30 | DDSimulationChecker(const qc::QuantumComputation& circ1, 31 | const qc::QuantumComputation& circ2, 32 | Configuration config); 33 | 34 | void setRandomInitialState(StateGenerator& generator); 35 | 36 | /// Returns the initial state used for simulation 37 | [[nodiscard]] auto getInitialState() const -> const auto& { 38 | return initialState; 39 | } 40 | /// Returns the internal state of the first task manager 41 | [[nodiscard]] auto getInternalState1() const -> const auto& { 42 | return taskManager1.getInternalState(); 43 | } 44 | 45 | /// Returns the internal state of the second task manager 46 | [[nodiscard]] auto getInternalState2() const -> const auto& { 47 | return taskManager2.getInternalState(); 48 | } 49 | 50 | void json(nlohmann::basic_json<>& j) const noexcept override; 51 | 52 | private: 53 | // the initial state used for simulation. defaults to the all-zero state 54 | // |0...0> 55 | dd::VectorDD initialState{}; 56 | 57 | void initializeTask(TaskManager<dd::VectorDD>& taskManager) override; 58 | EquivalenceCriterion checkEquivalence() override; 59 | }; 60 | } // namespace ec 61 | -------------------------------------------------------------------------------- /include/checker/dd/applicationscheme/ApplicationScheme.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "checker/dd/TaskManager.hpp" 14 | 15 | #include <cstddef> 16 | #include <cstdint> 17 | #include <iostream> 18 | #include <string> 19 | #include <utility> 20 | 21 | namespace ec { 22 | // A list of application schemes that implement the below interface 23 | enum class ApplicationSchemeType : std::uint8_t { 24 | Sequential = 0, 25 | OneToOne = 1, 26 | Lookahead = 2, 27 | GateCost = 3, 28 | Proportional = 4 29 | }; 30 | 31 | inline std::string 32 | toString(const ApplicationSchemeType& applicationScheme) noexcept { 33 | switch (applicationScheme) { 34 | case ApplicationSchemeType::Sequential: 35 | return "sequential"; 36 | case ApplicationSchemeType::OneToOne: 37 | return "one_to_one"; 38 | case ApplicationSchemeType::Lookahead: 39 | return "lookahead"; 40 | case ApplicationSchemeType::GateCost: 41 | return "gate_cost"; 42 | default: 43 | return "proportional"; 44 | } 45 | } 46 | 47 | inline ApplicationSchemeType 48 | applicationSchemeFromString(const std::string& applicationScheme) noexcept { 49 | if ((applicationScheme == "sequential") || (applicationScheme == "0") || 50 | (applicationScheme == "reference")) { 51 | return ApplicationSchemeType::Sequential; 52 | } 53 | if ((applicationScheme == "one_to_one") || (applicationScheme == "1") || 54 | (applicationScheme == "naive")) { 55 | return ApplicationSchemeType::OneToOne; 56 | } 57 | if ((applicationScheme == "lookahead") || (applicationScheme == "2")) { 58 | return ApplicationSchemeType::Lookahead; 59 | } 60 | if ((applicationScheme == "gate_cost") || (applicationScheme == "3") || 61 | (applicationScheme == "compilation_flow")) { 62 | return ApplicationSchemeType::GateCost; 63 | } 64 | if ((applicationScheme == "proportional") || (applicationScheme == "4")) { 65 | return ApplicationSchemeType::Proportional; 66 | } 67 | std::cerr << "Unknown application scheme: " << applicationScheme 68 | << ". Defaulting to proportional!\n"; 69 | return ApplicationSchemeType::Proportional; 70 | } 71 | 72 | inline std::istream& operator>>(std::istream& in, 73 | ApplicationSchemeType& applicationScheme) { 74 | std::string token; 75 | in >> token; 76 | 77 | if (token.empty()) { 78 | in.setstate(std::istream::failbit); 79 | return in; 80 | } 81 | 82 | applicationScheme = applicationSchemeFromString(token); 83 | return in; 84 | } 85 | 86 | inline std::ostream& 87 | operator<<(std::ostream& out, const ApplicationSchemeType& applicationScheme) { 88 | out << toString(applicationScheme); 89 | return out; 90 | } 91 | 92 | // Interface for describing an application scheme 93 | // Given the current state of the check (tracked by two task managers), an 94 | // application scheme describes how to proceed with the check, i.e., how many 95 | // operations to apply from either circuit. 96 | template <class DDType> class ApplicationScheme { 97 | protected: 98 | using TM = TaskManager<DDType>; 99 | 100 | public: 101 | ApplicationScheme(TM& tm1, TM& tm2) noexcept 102 | : taskManager1(&tm1), taskManager2(&tm2) {}; 103 | 104 | virtual ~ApplicationScheme() = default; 105 | 106 | // get how many gates from either circuit shall be applied next 107 | virtual std::pair<std::size_t, std::size_t> operator()() = 0; 108 | 109 | protected: 110 | TM* taskManager1; 111 | TM* taskManager2; 112 | }; 113 | 114 | } // namespace ec 115 | -------------------------------------------------------------------------------- /include/checker/dd/applicationscheme/GateCostApplicationScheme.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "ApplicationScheme.hpp" 14 | #include "checker/dd/TaskManager.hpp" 15 | #include "ir/QuantumComputation.hpp" 16 | #include "ir/operations/OpType.hpp" 17 | 18 | #include <cstddef> 19 | #include <fstream> 20 | #include <functional> 21 | #include <istream> 22 | #include <sstream> 23 | #include <stdexcept> 24 | #include <string> 25 | #include <unordered_map> 26 | #include <utility> 27 | 28 | template <> struct std::hash<std::pair<qc::OpType, std::size_t>> { 29 | std::size_t 30 | operator()(pair<qc::OpType, std::size_t> const& key) const noexcept { 31 | const std::size_t h1 = hash<decltype(key.first)>{}(key.first); 32 | const std::size_t h2 = hash<decltype(key.second)>{}(key.second); 33 | return h1 ^ (h2 << 1); 34 | } 35 | }; // namespace std 36 | 37 | namespace ec { 38 | using GateCostLookupTableKeyType = std::pair<qc::OpType, std::size_t>; 39 | using GateCostLookupTable = 40 | std::unordered_map<GateCostLookupTableKeyType, std::size_t>; 41 | using CostFunction = 42 | std::function<std::size_t(const GateCostLookupTableKeyType&)>; 43 | 44 | template <class DDType> 45 | class GateCostApplicationScheme final : public ApplicationScheme<DDType> { 46 | public: 47 | GateCostApplicationScheme(TaskManager<DDType>& tm1, TaskManager<DDType>& tm2, 48 | const CostFunction& costFunction, 49 | const bool singleQubitGateFusion) 50 | : ApplicationScheme<DDType>(tm1, tm2), 51 | singleQubitGateFusionEnabled(singleQubitGateFusion) { 52 | populateLookupTable(costFunction, tm1.getCircuit()); 53 | populateLookupTable(costFunction, tm2.getCircuit()); 54 | } 55 | 56 | GateCostApplicationScheme(TaskManager<DDType>& tm1, TaskManager<DDType>& tm2, 57 | const std::string& filename, 58 | const bool singleQubitGateFusion) 59 | : ApplicationScheme<DDType>(tm1, tm2), 60 | singleQubitGateFusionEnabled(singleQubitGateFusion) { 61 | populateLookupTable(filename); 62 | } 63 | 64 | std::pair<size_t, size_t> operator()() override { 65 | if (gateCostLookupTable.empty()) { 66 | return {1U, 1U}; 67 | } 68 | 69 | const auto& op = (*this->taskManager1)(); 70 | if (singleQubitGateFusionEnabled && op->getUsedQubits().size() == 1U) { 71 | // when single qubit gates are fused, any single-qubit gate should have a 72 | // single (compound) gate in the other circuit as a counterpart. 73 | return {1U, 1U}; 74 | } 75 | 76 | const auto key = 77 | GateCostLookupTableKeyType{op->getType(), op->getNcontrols()}; 78 | std::size_t cost = 1U; 79 | if (const auto it = gateCostLookupTable.find(key); 80 | it != gateCostLookupTable.end()) { 81 | cost = it->second; 82 | } 83 | return {1U, cost}; 84 | } 85 | 86 | private: 87 | GateCostLookupTable gateCostLookupTable; 88 | bool singleQubitGateFusionEnabled; 89 | 90 | template <class CostFun> 91 | void populateLookupTable(CostFun costFunction, 92 | const qc::QuantumComputation* qc) { 93 | for (const auto& op : *qc) { 94 | const auto type = op->getType(); 95 | const auto nControls = op->getNcontrols(); 96 | const auto key = GateCostLookupTableKeyType{type, nControls}; 97 | if (const auto it = gateCostLookupTable.find(key); 98 | it == gateCostLookupTable.end()) { 99 | const auto cost = costFunction(key); 100 | gateCostLookupTable.emplace(key, cost); 101 | } 102 | } 103 | } 104 | 105 | // read gate cost LUT from file 106 | // simple file format: 107 | // each line consists of 108 | // <identifier> <controls> <cost> 109 | void populateLookupTable(const std::string& filename) { 110 | std::ifstream ifs(filename); 111 | if (!ifs.good()) { 112 | throw std::invalid_argument("Error opening LUT file: " + filename); 113 | } 114 | populateLookupTable(ifs); 115 | } 116 | void populateLookupTable(std::istream& is) { 117 | qc::OpType opType = qc::OpType::None; 118 | std::size_t nControls = 0U; 119 | std::size_t cost = 1U; 120 | 121 | std::string line; 122 | while (std::getline(is, line)) { 123 | if (line.empty() || line[0] == '#') { 124 | continue; 125 | } 126 | std::istringstream iss(line); 127 | if (iss >> opType >> nControls >> cost) { 128 | gateCostLookupTable.emplace(std::pair{opType, nControls}, cost); 129 | } 130 | } 131 | } 132 | }; 133 | } // namespace ec 134 | -------------------------------------------------------------------------------- /include/checker/dd/applicationscheme/LookaheadApplicationScheme.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "ApplicationScheme.hpp" 14 | #include "checker/dd/TaskManager.hpp" 15 | #include "dd/Node.hpp" 16 | #include "dd/Package.hpp" 17 | 18 | #include <cstddef> 19 | #include <utility> 20 | 21 | namespace ec { 22 | class LookaheadApplicationScheme final 23 | : public ApplicationScheme<dd::MatrixDD> { 24 | public: 25 | LookaheadApplicationScheme(TaskManager<dd::MatrixDD>& tm1, 26 | TaskManager<dd::MatrixDD>& tm2) noexcept; 27 | 28 | void setInternalState(dd::MatrixDD& state) noexcept; 29 | void setPackage(dd::Package* dd) noexcept; 30 | 31 | // in general, the lookup application scheme will apply a single operation of 32 | // either circuit for every invocation. manipulation of the state is handled 33 | // directly by the application scheme. Thus, the return value is always {0,0}. 34 | std::pair<size_t, size_t> operator()() override; 35 | 36 | private: 37 | dd::MatrixDD op1{}; 38 | bool cached1 = false; 39 | 40 | dd::MatrixDD op2{}; 41 | bool cached2 = false; 42 | 43 | // the lookahead application scheme maintains links to an internal state to 44 | // manipulate and a package to use 45 | dd::MatrixDD* internalState{}; 46 | dd::Package* package{}; 47 | }; 48 | } // namespace ec 49 | -------------------------------------------------------------------------------- /include/checker/dd/applicationscheme/OneToOneApplicationScheme.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "ApplicationScheme.hpp" 14 | #include "checker/dd/TaskManager.hpp" 15 | 16 | #include <cstddef> 17 | #include <utility> 18 | 19 | namespace ec { 20 | template <class DDType> 21 | class OneToOneApplicationScheme final : public ApplicationScheme<DDType> { 22 | public: 23 | OneToOneApplicationScheme(TaskManager<DDType>& tm1, 24 | TaskManager<DDType>& tm2) noexcept 25 | : ApplicationScheme<DDType>(tm1, tm2) {} 26 | 27 | std::pair<size_t, size_t> operator()() noexcept override { return {1U, 1U}; } 28 | }; 29 | } // namespace ec 30 | -------------------------------------------------------------------------------- /include/checker/dd/applicationscheme/ProportionalApplicationScheme.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "ApplicationScheme.hpp" 14 | #include "checker/dd/TaskManager.hpp" 15 | 16 | #include <algorithm> 17 | #include <cassert> 18 | #include <cstddef> 19 | #include <utility> 20 | 21 | namespace ec { 22 | template <class DDType> 23 | class ProportionalApplicationScheme final : public ApplicationScheme<DDType> { 24 | public: 25 | ProportionalApplicationScheme(TaskManager<DDType>& tm1, 26 | TaskManager<DDType>& tm2, 27 | const bool singleQubitGateFusion) noexcept 28 | : ApplicationScheme<DDType>(tm1, tm2), 29 | singleQubitGateFusionEnabled(singleQubitGateFusion) {} 30 | 31 | std::pair<size_t, size_t> operator()() noexcept override { 32 | // compute the remaining size of the circuits 33 | const auto size1 = static_cast<std::size_t>( 34 | std::distance(this->taskManager1->getIterator(), 35 | this->taskManager1->getCircuit()->cend())); 36 | const auto size2 = static_cast<std::size_t>( 37 | std::distance(this->taskManager2->getIterator(), 38 | this->taskManager2->getCircuit()->cend())); 39 | assert(size1 > 0U && size2 > 0U); 40 | 41 | if (singleQubitGateFusionEnabled) { 42 | // when single qubit gates are fused, any single-qubit gate should have a 43 | // single (compound) gate in the other circuit as a counterpart. 44 | if (const auto& op = (*this->taskManager1)(); 45 | op->getUsedQubits().size() == 1U) { 46 | return {1U, 1U}; 47 | } 48 | } 49 | 50 | const auto [min, max] = std::minmax(size1, size2); 51 | const auto gateRatio = 52 | std::max((max + (min / 2U)) / min, static_cast<std::size_t>(1U)); 53 | if (size1 >= size2) { 54 | return {gateRatio, 1U}; 55 | } 56 | return {1U, gateRatio}; 57 | } 58 | 59 | private: 60 | bool singleQubitGateFusionEnabled; 61 | }; 62 | } // namespace ec 63 | -------------------------------------------------------------------------------- /include/checker/dd/applicationscheme/SequentialApplicationScheme.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "ApplicationScheme.hpp" 14 | #include "checker/dd/TaskManager.hpp" 15 | 16 | #include <cstddef> 17 | #include <utility> 18 | 19 | namespace ec { 20 | template <class DDType> 21 | class SequentialApplicationScheme final : public ApplicationScheme<DDType> { 22 | public: 23 | SequentialApplicationScheme(TaskManager<DDType>& tm1, 24 | TaskManager<DDType>& tm2) noexcept 25 | : ApplicationScheme<DDType>(tm1, tm2), 26 | gates1(tm1.getCircuit()->getNops()), 27 | gates2(tm2.getCircuit()->getNops()) {} 28 | 29 | std::pair<size_t, size_t> operator()() noexcept override { 30 | return {gates1, gates2}; 31 | } 32 | 33 | private: 34 | std::size_t gates1; 35 | std::size_t gates2; 36 | }; 37 | } // namespace ec 38 | -------------------------------------------------------------------------------- /include/checker/dd/simulation/StateGenerator.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "StateType.hpp" 14 | #include "dd/Package_fwd.hpp" 15 | 16 | #include <cstddef> 17 | #include <random> 18 | #include <unordered_set> 19 | 20 | namespace ec { 21 | class StateGenerator { 22 | public: 23 | explicit StateGenerator(const std::size_t s) : seed(s) { 24 | seedGenerator(seed); 25 | } 26 | StateGenerator() : StateGenerator(0U) {} 27 | 28 | dd::VectorDD 29 | generateRandomState(dd::Package& dd, std::size_t totalQubits, 30 | std::size_t ancillaryQubits = 0U, 31 | StateType type = StateType::ComputationalBasis); 32 | 33 | dd::VectorDD 34 | generateRandomComputationalBasisState(dd::Package& dd, 35 | std::size_t totalQubits, 36 | std::size_t ancillaryQubits = 0U); 37 | 38 | dd::VectorDD generateRandom1QBasisState(dd::Package& dd, 39 | std::size_t totalQubits, 40 | std::size_t ancillaryQubits = 0U); 41 | 42 | dd::VectorDD generateRandomStabilizerState(dd::Package& dd, 43 | std::size_t totalQubits, 44 | std::size_t ancillaryQubits = 0U); 45 | 46 | void seedGenerator(std::size_t s); 47 | 48 | void clear() { generatedComputationalBasisStates.clear(); } 49 | 50 | private: 51 | std::size_t seed = 0U; 52 | std::mt19937_64 mt; 53 | 54 | std::unordered_set<std::size_t> generatedComputationalBasisStates; 55 | constexpr static std::size_t ONE_QUBIT_BASE_ELEMENTS = 6U; 56 | // this generator produces random bases from the set { |0>, |1>, |+>, |->, 57 | // |L>, |R> } 58 | std::uniform_int_distribution<std::size_t> random1QBasisDistribution = 59 | std::uniform_int_distribution<std::size_t>(0U, 60 | ONE_QUBIT_BASE_ELEMENTS - 1U); 61 | }; 62 | } // namespace ec 63 | -------------------------------------------------------------------------------- /include/checker/dd/simulation/StateType.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include <cstdint> 14 | #include <iostream> 15 | #include <string> 16 | 17 | namespace ec { 18 | enum class StateType : std::uint8_t { 19 | ComputationalBasis = 0, 20 | Random1QBasis = 1, 21 | Stabilizer = 2 22 | }; 23 | 24 | inline std::string toString(const StateType& type) noexcept { 25 | switch (type) { 26 | case StateType::Random1QBasis: 27 | return "random_1Q_basis"; 28 | case StateType::Stabilizer: 29 | return "stabilizer"; 30 | default: 31 | return "computational_basis"; 32 | } 33 | } 34 | 35 | inline StateType stateTypeFromString(const std::string& type) noexcept { 36 | if ((type == "computational_basis") || (type == "0") || 37 | (type == "classical")) { 38 | return StateType::ComputationalBasis; 39 | } 40 | if ((type == "random_1Q_basis") || (type == "1") || 41 | (type == "local_quantum")) { 42 | return StateType::Random1QBasis; 43 | } 44 | if ((type == "stabilizer") || (type == "2") || (type == "global_quantum")) { 45 | return StateType::Stabilizer; 46 | } 47 | std::cerr << "Unknown state type: " << type 48 | << ". Defaulting to computational basis states.\n"; 49 | return StateType::ComputationalBasis; 50 | } 51 | 52 | inline std::istream& operator>>(std::istream& in, StateType& type) { 53 | std::string token; 54 | in >> token; 55 | 56 | if (token.empty()) { 57 | in.setstate(std::istream::failbit); 58 | return in; 59 | } 60 | 61 | type = stateTypeFromString(token); 62 | return in; 63 | } 64 | 65 | inline std::ostream& operator<<(std::ostream& out, const StateType& type) { 66 | out << toString(type); 67 | return out; 68 | } 69 | } // namespace ec 70 | -------------------------------------------------------------------------------- /include/checker/zx/ZXChecker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "Configuration.hpp" 14 | #include "EquivalenceCriterion.hpp" 15 | #include "checker/EquivalenceChecker.hpp" 16 | #include "ir/Permutation.hpp" 17 | #include "ir/QuantumComputation.hpp" 18 | #include "zx/Rules.hpp" 19 | #include "zx/ZXDefinitions.hpp" 20 | #include "zx/ZXDiagram.hpp" 21 | 22 | #include <cstddef> 23 | #include <nlohmann/json.hpp> 24 | 25 | namespace ec { 26 | class ZXEquivalenceChecker : public EquivalenceChecker { 27 | public: 28 | ZXEquivalenceChecker(const qc::QuantumComputation& circ1, 29 | const qc::QuantumComputation& circ2, 30 | Configuration config) noexcept; 31 | 32 | EquivalenceCriterion run() override; 33 | 34 | void json(nlohmann::basic_json<>& j) const noexcept override { 35 | EquivalenceChecker::json(j); 36 | j["checker"] = "zx"; 37 | } 38 | 39 | private: 40 | zx::ZXDiagram miter; 41 | zx::fp tolerance; 42 | bool ancilla = false; 43 | 44 | // the following methods are adaptations of the core ZX simplification 45 | // routines that additionally check a criterion for early termination of the 46 | // simplification. 47 | bool fullReduceApproximate(); 48 | bool fullReduce(); 49 | 50 | bool gadgetSimp(); 51 | bool interiorCliffordSimp(); 52 | bool cliffordSimp(); 53 | 54 | bool idSimp() { return simplifyVertices(zx::checkIdSimp, zx::removeId); } 55 | 56 | bool spiderSimp() { 57 | return simplifyEdges(zx::checkSpiderFusion, zx::fuseSpiders); 58 | } 59 | 60 | bool localCompSimp() { 61 | return simplifyVertices(zx::checkLocalComp, zx::localComp); 62 | } 63 | 64 | bool pivotPauliSimp() { 65 | return simplifyEdges(zx::checkPivotPauli, zx::pivotPauli); 66 | } 67 | 68 | bool pivotSimp() { return simplifyEdges(zx::checkPivot, zx::pivot); } 69 | 70 | bool pivotGadgetSimp() { 71 | return simplifyEdges(zx::checkPivotGadget, zx::pivotGadget); 72 | } 73 | 74 | template <class CheckFun, class RuleFun> 75 | bool simplifyVertices(CheckFun check, RuleFun rule) { 76 | auto simplified = false; 77 | while (!isDone()) { 78 | auto moreSimplified = false; 79 | for (const auto& [v, _] : miter.getVertices()) { 80 | if (isDone() || !check(miter, v)) { 81 | continue; 82 | } 83 | rule(miter, v); 84 | moreSimplified = true; 85 | } 86 | if (!moreSimplified) { 87 | break; 88 | } 89 | simplified = true; 90 | } 91 | return simplified; 92 | } 93 | 94 | template <class CheckFun, class RuleFun> 95 | bool simplifyEdges(CheckFun check, RuleFun rule) { 96 | auto simplified = false; 97 | while (!isDone()) { 98 | auto moreSimplified = false; 99 | for (const auto& [v0, v1] : miter.getEdges()) { 100 | if (isDone() || miter.isDeleted(v0) || miter.isDeleted(v1) || 101 | !check(miter, v0, v1)) { 102 | continue; 103 | } 104 | rule(miter, v0, v1); 105 | moreSimplified = true; 106 | } 107 | if (!moreSimplified) { 108 | break; 109 | } 110 | simplified = true; 111 | } 112 | return simplified; 113 | } 114 | }; 115 | 116 | qc::Permutation complete(const qc::Permutation& p, std::size_t n); 117 | qc::Permutation concat(const qc::Permutation& p1, const qc::Permutation& p2); 118 | qc::Permutation invert(const qc::Permutation& p); 119 | qc::Permutation invertPermutations(const qc::QuantumComputation& qc); 120 | } // namespace ec 121 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | if(NOT TARGET MQT::QCEC) 10 | # collect headers and source files 11 | file(GLOB_RECURSE QCEC_HEADERS ${MQT_QCEC_INCLUDE_BUILD_DIR}/*.hpp) 12 | file(GLOB_RECURSE QCEC_SOURCES **.cpp) 13 | list(FILTER QCEC_SOURCES EXCLUDE REGEX ".*/python/.*$") 14 | 15 | # add QCEC Package library 16 | add_library(${PROJECT_NAME} ${QCEC_HEADERS} ${QCEC_SOURCES}) 17 | 18 | # set include directories 19 | target_include_directories(${PROJECT_NAME} 20 | PUBLIC $<BUILD_INTERFACE:${MQT_QCEC_INCLUDE_BUILD_DIR}>) 21 | 22 | # link to the MQT::Core libraries 23 | target_link_libraries( 24 | ${PROJECT_NAME} 25 | PUBLIC MQT::CoreDD MQT::CoreZX 26 | PRIVATE MQT::CoreCircuitOptimizer MQT::CoreAlgorithms MQT::ProjectWarnings MQT::ProjectOptions) 27 | 28 | # add MQT alias 29 | add_library(MQT::QCEC ALIAS ${PROJECT_NAME}) 30 | endif() 31 | 32 | if(BUILD_MQT_QCEC_BINDINGS) 33 | add_subdirectory(python) 34 | endif() 35 | -------------------------------------------------------------------------------- /src/Configuration.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #include "Configuration.hpp" 12 | 13 | #include "checker/dd/applicationscheme/ApplicationScheme.hpp" 14 | #include "checker/dd/simulation/StateType.hpp" 15 | 16 | #include <nlohmann/json.hpp> 17 | #include <ostream> 18 | 19 | namespace ec { 20 | bool Configuration::anythingToExecute() const noexcept { 21 | return (execution.runSimulationChecker && simulation.maxSims > 0U) || 22 | execution.runAlternatingChecker || execution.runConstructionChecker || 23 | execution.runZXChecker; 24 | } 25 | 26 | bool Configuration::onlySingleTask() const noexcept { 27 | // only a single simulation shall be performed 28 | if (execution.runSimulationChecker && (simulation.maxSims == 1U) && 29 | !execution.runAlternatingChecker && !execution.runConstructionChecker && 30 | !execution.runZXChecker) { 31 | return true; 32 | } 33 | 34 | // no simulations and only one of the other checks shall be performed 35 | if (!execution.runSimulationChecker && 36 | ((execution.runAlternatingChecker && !execution.runConstructionChecker && 37 | !execution.runZXChecker) || 38 | (!execution.runAlternatingChecker && execution.runConstructionChecker && 39 | !execution.runZXChecker) || 40 | (!execution.runAlternatingChecker && !execution.runConstructionChecker && 41 | execution.runZXChecker))) { 42 | return true; 43 | } 44 | 45 | return false; 46 | } 47 | 48 | bool Configuration::onlyZXCheckerConfigured() const noexcept { 49 | return !execution.runConstructionChecker && !execution.runSimulationChecker && 50 | !execution.runAlternatingChecker && execution.runZXChecker; 51 | } 52 | 53 | bool Configuration::onlySimulationCheckerConfigured() const noexcept { 54 | return !execution.runConstructionChecker && execution.runSimulationChecker && 55 | !execution.runAlternatingChecker && !execution.runZXChecker; 56 | } 57 | 58 | nlohmann::basic_json<> Configuration::json() const { 59 | nlohmann::basic_json<> config{}; 60 | auto& exe = config["execution"]; 61 | exe["tolerance"] = execution.numericalTolerance; 62 | exe["parallel"] = execution.parallel; 63 | exe["nthreads"] = execution.nthreads; 64 | exe["run_construction_checker"] = execution.runConstructionChecker; 65 | exe["run_simulation_checker"] = execution.runSimulationChecker; 66 | exe["run_alternating_checker"] = execution.runAlternatingChecker; 67 | exe["run_zx_checker"] = execution.runZXChecker; 68 | exe["timeout"] = execution.timeout; 69 | 70 | auto& opt = config["optimizations"]; 71 | opt["fuse_consecutive_single_qubit_gates"] = 72 | optimizations.fuseSingleQubitGates; 73 | opt["reconstruct_swaps"] = optimizations.reconstructSWAPs; 74 | opt["remove_diagonal_gates_before_measure"] = 75 | optimizations.removeDiagonalGatesBeforeMeasure; 76 | opt["transform_dynamic_circuit"] = optimizations.transformDynamicCircuit; 77 | opt["reorder_operations"] = optimizations.reorderOperations; 78 | opt["backpropagate_output_permutation"] = 79 | optimizations.backpropagateOutputPermutation; 80 | opt["elide_permutations"] = optimizations.elidePermutations; 81 | 82 | auto& app = config["application"]; 83 | app["construction"] = ec::toString(application.constructionScheme); 84 | app["simulation"] = ec::toString(application.simulationScheme); 85 | app["alternating"] = ec::toString(application.alternatingScheme); 86 | if (!application.profile.empty()) { 87 | app["profile"] = application.profile; 88 | } else { 89 | app["profile"] = "cost_function"; 90 | } 91 | 92 | auto& par = config["parameterized"]; 93 | par["tolerance"] = parameterized.parameterizedTol; 94 | par["additional_instantiations"] = parameterized.nAdditionalInstantiations; 95 | 96 | auto& fun = config["functionality"]; 97 | fun["trace_threshold"] = functionality.traceThreshold; 98 | fun["check_partial_equivalence"] = functionality.checkPartialEquivalence; 99 | 100 | auto& sim = config["simulation"]; 101 | sim["fidelity_threshold"] = simulation.fidelityThreshold; 102 | sim["max_sims"] = simulation.maxSims; 103 | sim["state_type"] = ec::toString(simulation.stateType); 104 | sim["seed"] = simulation.seed; 105 | 106 | return config; 107 | } 108 | 109 | std::string Configuration::toString() const { 110 | constexpr auto indent = 2; 111 | return json().dump(indent); 112 | } 113 | 114 | std::ostream& operator<<(std::ostream& os, const Configuration& config) { 115 | return os << config.toString(); 116 | } 117 | } // namespace ec 118 | -------------------------------------------------------------------------------- /src/checker/EquivalenceChecker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #include "checker/EquivalenceChecker.hpp" 12 | 13 | #include "EquivalenceCriterion.hpp" 14 | 15 | #include <nlohmann/json.hpp> 16 | 17 | // this function is mainly placed here in order to have an out-of-line 18 | // virtual method definition which avoids emitting the classes' vtable in 19 | // every translation unit. 20 | void ec::EquivalenceChecker::json(nlohmann::basic_json<>& j) const noexcept { 21 | j["equivalence"] = toString(equivalence); 22 | j["runtime"] = getRuntime(); 23 | } 24 | -------------------------------------------------------------------------------- /src/checker/dd/DDConstructionChecker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #include "checker/dd/DDConstructionChecker.hpp" 12 | 13 | #include "Configuration.hpp" 14 | #include "checker/dd/DDEquivalenceChecker.hpp" 15 | #include "checker/dd/DDPackageConfigs.hpp" 16 | #include "checker/dd/TaskManager.hpp" 17 | #include "checker/dd/applicationscheme/ApplicationScheme.hpp" 18 | #include "dd/Node.hpp" 19 | #include "dd/Package.hpp" 20 | #include "ir/QuantumComputation.hpp" 21 | 22 | #include <nlohmann/json.hpp> 23 | #include <stdexcept> 24 | #include <utility> 25 | 26 | ec::DDConstructionChecker::DDConstructionChecker( 27 | const qc::QuantumComputation& circ1, const qc::QuantumComputation& circ2, 28 | Configuration config) 29 | : DDEquivalenceChecker(circ1, circ2, std::move(config), 30 | ConstructionDDPackageConfig{}) { 31 | if (configuration.application.constructionScheme == 32 | ApplicationSchemeType::Lookahead) { 33 | throw std::invalid_argument("Lookahead application scheme must not be " 34 | "used with DD construction checker."); 35 | } 36 | initializeApplicationScheme(configuration.application.constructionScheme); 37 | } 38 | 39 | // this function is mainly placed here in order to have an out-of-line 40 | // virtual method definition which avoids emitting the classes' vtable in 41 | // every translation unit. 42 | void ec::DDConstructionChecker::json(nlohmann::basic_json<>& j) const noexcept { 43 | DDEquivalenceChecker::json(j); 44 | j["checker"] = "decision_diagram_construction"; 45 | } 46 | 47 | void ec::DDConstructionChecker::initializeTask( 48 | TaskManager<dd::MatrixDD>& taskManager) { 49 | DDEquivalenceChecker::initializeTask(taskManager); 50 | const auto initial = dd::Package::makeIdent(); 51 | taskManager.setInternalState(initial); 52 | taskManager.incRef(); 53 | taskManager.reduceAncillae(); 54 | } 55 | -------------------------------------------------------------------------------- /src/checker/dd/DDSimulationChecker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #include "checker/dd/DDSimulationChecker.hpp" 12 | 13 | #include "Configuration.hpp" 14 | #include "EquivalenceCriterion.hpp" 15 | #include "checker/dd/DDEquivalenceChecker.hpp" 16 | #include "checker/dd/DDPackageConfigs.hpp" 17 | #include "checker/dd/TaskManager.hpp" 18 | #include "checker/dd/simulation/StateGenerator.hpp" 19 | #include "dd/StateGeneration.hpp" 20 | #include "ir/QuantumComputation.hpp" 21 | 22 | #include <nlohmann/json.hpp> 23 | #include <utility> 24 | 25 | namespace ec { 26 | DDSimulationChecker::DDSimulationChecker(const qc::QuantumComputation& circ1, 27 | const qc::QuantumComputation& circ2, 28 | Configuration config) 29 | : DDEquivalenceChecker(circ1, circ2, std::move(config), 30 | SimulationDDPackageConfig{}) { 31 | initialState = dd::makeZeroState(nqubits, *dd); 32 | initializeApplicationScheme(configuration.application.simulationScheme); 33 | } 34 | 35 | void DDSimulationChecker::initializeTask( 36 | TaskManager<dd::VectorDD>& taskManager) { 37 | DDEquivalenceChecker::initializeTask(taskManager); 38 | taskManager.setInternalState(initialState); 39 | taskManager.incRef(); 40 | } 41 | 42 | EquivalenceCriterion DDSimulationChecker::checkEquivalence() { 43 | equivalence = DDEquivalenceChecker::checkEquivalence(); 44 | 45 | // adjust reference counts to facilitate reuse of the simulation checker 46 | taskManager1.decRef(); 47 | taskManager2.decRef(); 48 | dd->decRef(initialState); 49 | 50 | return equivalence; 51 | } 52 | 53 | void DDSimulationChecker::setRandomInitialState(StateGenerator& generator) { 54 | const auto nancillary = nqubits - qc1->getNqubitsWithoutAncillae(); 55 | const auto stateType = configuration.simulation.stateType; 56 | 57 | initialState = 58 | generator.generateRandomState(*dd, nqubits, nancillary, stateType); 59 | } 60 | 61 | void DDSimulationChecker::json(nlohmann::basic_json<>& j) const noexcept { 62 | DDEquivalenceChecker::json(j); 63 | j["checker"] = "decision_diagram_simulation"; 64 | } 65 | 66 | } // namespace ec 67 | -------------------------------------------------------------------------------- /src/checker/dd/applicationscheme/LookaheadApplicationScheme.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #include "checker/dd/applicationscheme/LookaheadApplicationScheme.hpp" 12 | 13 | #include "checker/dd/TaskManager.hpp" 14 | #include "checker/dd/applicationscheme/ApplicationScheme.hpp" 15 | #include "dd/Node.hpp" 16 | #include "dd/Package.hpp" 17 | 18 | #include <cassert> 19 | #include <cstddef> 20 | #include <utility> 21 | 22 | namespace ec { 23 | 24 | LookaheadApplicationScheme::LookaheadApplicationScheme( 25 | TaskManager<dd::MatrixDD>& tm1, TaskManager<dd::MatrixDD>& tm2) noexcept 26 | : ApplicationScheme(tm1, tm2) {} 27 | void LookaheadApplicationScheme::setInternalState( 28 | dd::MatrixDD& state) noexcept { 29 | internalState = &state; 30 | } 31 | void LookaheadApplicationScheme::setPackage(dd::Package* dd) noexcept { 32 | package = dd; 33 | } 34 | std::pair<size_t, size_t> LookaheadApplicationScheme::operator()() { 35 | assert(internalState != nullptr); 36 | assert(package != nullptr); 37 | 38 | if (!cached1) { 39 | // cache the current operation 40 | op1 = taskManager1->getDD(); 41 | package->incRef(op1); 42 | cached1 = true; 43 | } 44 | 45 | if (!cached2) { 46 | // cache the current operation 47 | op2 = taskManager2->getInverseDD(); 48 | package->incRef(op2); 49 | cached2 = true; 50 | } 51 | 52 | // compute both possible applications and measure the resulting size 53 | auto saved = *internalState; 54 | const auto dd1 = package->multiply(op1, saved); 55 | const auto size1 = dd1.size(); 56 | const auto dd2 = package->multiply(saved, op2); 57 | 58 | // greedily chose the smaller resulting decision diagram 59 | if (const auto size2 = dd2.size(); size1 <= size2) { 60 | assert(!taskManager1->finished()); 61 | *internalState = dd1; 62 | package->decRef(op1); 63 | cached1 = false; 64 | taskManager1->advanceIterator(); 65 | } else { 66 | assert(!taskManager2->finished()); 67 | *internalState = dd2; 68 | package->decRef(op2); 69 | cached2 = false; 70 | taskManager2->advanceIterator(); 71 | } 72 | 73 | // properly track reference counts 74 | package->incRef(*internalState); 75 | package->decRef(saved); 76 | package->garbageCollect(); 77 | 78 | // no operations shall be applied by the outer loop in which the application 79 | // scheme is invoked 80 | return {0U, 0U}; 81 | } 82 | } // namespace ec 83 | -------------------------------------------------------------------------------- /src/mqt/qcec/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """MQT QCEC library. 10 | 11 | This file is part of the MQT QCEC library released under the MIT license. 12 | See README.md or go to https://github.com/cda-tum/qcec for more information. 13 | """ 14 | 15 | from __future__ import annotations 16 | 17 | import sys 18 | 19 | # under Windows, make sure to add the appropriate DLL directory to the PATH 20 | if sys.platform == "win32": 21 | 22 | def _dll_patch() -> None: 23 | """Add the DLL directory to the PATH.""" 24 | import os 25 | import sysconfig 26 | from pathlib import Path 27 | 28 | bin_dir = Path(sysconfig.get_paths()["purelib"]) / "mqt" / "core" / "bin" 29 | os.add_dll_directory(str(bin_dir)) 30 | 31 | _dll_patch() 32 | del _dll_patch 33 | 34 | from ._version import version as __version__ 35 | from .verify import verify 36 | from .verify_compilation_flow import verify_compilation 37 | 38 | __all__ = [ 39 | "__version__", 40 | "verify", 41 | "verify_compilation", 42 | ] 43 | -------------------------------------------------------------------------------- /src/mqt/qcec/_compat/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | from __future__ import annotations 10 | 11 | __all__: list[str] = [] 12 | -------------------------------------------------------------------------------- /src/mqt/qcec/_compat/importlib/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | from __future__ import annotations 10 | 11 | __all__: list[str] = [] 12 | -------------------------------------------------------------------------------- /src/mqt/qcec/_compat/importlib/resources.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | from __future__ import annotations 10 | 11 | import sys 12 | 13 | if sys.version_info >= (3, 10): 14 | from importlib.resources import as_file, files 15 | else: 16 | from importlib_resources import as_file, files 17 | 18 | __all__ = ["as_file", "files"] 19 | 20 | 21 | def __dir__() -> list[str]: 22 | return __all__ 23 | -------------------------------------------------------------------------------- /src/mqt/qcec/_compat/optional.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Optional dependency tester. 10 | 11 | Inspired by Qiskit's `LazyDependencyManager <https://github.com/Qiskit/qiskit/blob/f13673b05edf98263f80a174d2e13a118b4acda7/qiskit/utils/lazy_tester.py#L44>`_. 12 | """ 13 | 14 | from __future__ import annotations 15 | 16 | import contextlib 17 | import importlib 18 | import typing 19 | import warnings 20 | 21 | __all__ = ["HAS_QISKIT", "OptionalDependencyTester"] 22 | 23 | 24 | def __dir__() -> list[str]: 25 | return __all__ 26 | 27 | 28 | class OptionalDependencyTester: 29 | """A manager for optional dependencies to assert their availability. 30 | 31 | This class is used to lazily test for the availability of optional dependencies. 32 | It can be used in Boolean contexts to check if the dependency is available. 33 | """ 34 | 35 | def __init__(self, module: str, *, msg: str | None = None) -> None: 36 | """Construct a new optional dependency tester. 37 | 38 | Args: 39 | module: the name of the module to test for. 40 | msg: an extra message to include in the error raised if this is required. 41 | """ 42 | self._module = module 43 | self._bool: bool | None = None 44 | self._msg = msg 45 | 46 | def _is_available(self) -> bool: 47 | """Test the availability of the module. 48 | 49 | Returns: 50 | ``True`` if the module is available, ``False`` otherwise. 51 | """ 52 | try: 53 | importlib.import_module(self._module) 54 | except ImportError as exc: # pragma: no cover 55 | warnings.warn( 56 | f"Module '{self._module}' failed to import with: {exc!r}", 57 | category=UserWarning, 58 | stacklevel=2, 59 | ) 60 | return False 61 | else: 62 | return True 63 | 64 | def __bool__(self) -> bool: 65 | """Check if the dependency is available. 66 | 67 | Returns: 68 | ``True`` if the dependency is available, ``False`` otherwise. 69 | """ 70 | if self._bool is None: 71 | self._bool = self._is_available() 72 | return self._bool 73 | 74 | def require_now(self, feature: str) -> None: 75 | """Eagerly attempt to import the dependency and raise an exception if it cannot be imported. 76 | 77 | Args: 78 | feature: the feature that is requiring this dependency. 79 | 80 | Raises: 81 | ImportError: if the dependency cannot be imported. 82 | """ 83 | if self: 84 | return 85 | message = f"The '{self._module}' library is required to {feature}." 86 | if self._msg: 87 | message += f" {self._msg}." 88 | raise ImportError(message) 89 | 90 | @contextlib.contextmanager 91 | def disable_locally(self) -> typing.Generator[None, None, None]: 92 | """Create a context during which the value of the dependency manager will be ``False``. 93 | 94 | Yields: 95 | None 96 | """ 97 | previous = self._bool 98 | self._bool = False 99 | try: 100 | yield 101 | finally: 102 | self._bool = previous 103 | 104 | 105 | HAS_QISKIT = OptionalDependencyTester( 106 | "qiskit", 107 | msg="Please install the `mqt.qcec[qiskit]` extra or a compatible version of Qiskit to use functionality related to its functionality.", 108 | ) 109 | -------------------------------------------------------------------------------- /src/mqt/qcec/_compat/typing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | from __future__ import annotations 10 | 11 | import sys 12 | 13 | if sys.version_info >= (3, 11): 14 | from typing import Unpack 15 | else: 16 | from typing_extensions import Unpack 17 | 18 | __all__ = ["Unpack"] 19 | 20 | 21 | def __dir__() -> list[str]: 22 | return __all__ 23 | -------------------------------------------------------------------------------- /src/mqt/qcec/_version.pyi: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | __version__: str 10 | version: str 11 | __version_tuple__: tuple[int, int, int, str, str] | tuple[int, int, int] 12 | version_tuple: tuple[int, int, int, str, str] | tuple[int, int, int] 13 | -------------------------------------------------------------------------------- /src/mqt/qcec/configuration.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Configuration options for the equivalence checking manager.""" 10 | 11 | from __future__ import annotations 12 | 13 | from typing import TYPE_CHECKING, TypedDict 14 | 15 | if TYPE_CHECKING: 16 | from .pyqcec import ApplicationScheme, Configuration, StateType 17 | 18 | __all__ = ["ConfigurationOptions", "augment_config_from_kwargs"] 19 | 20 | 21 | def __dir__() -> list[str]: 22 | return __all__ 23 | 24 | 25 | class ConfigurationOptions(TypedDict, total=False): 26 | """A dictionary of configuration options. 27 | 28 | The keys of this dictionary are the names of the configuration options. 29 | The values are the values of the configuration options. 30 | """ 31 | 32 | # Application 33 | alternating_scheme: ApplicationScheme | str 34 | construction_scheme: ApplicationScheme | str 35 | simulation_scheme: ApplicationScheme | str 36 | profile: str 37 | # Execution 38 | nthreads: int 39 | numerical_tolerance: float 40 | parallel: bool 41 | run_alternating_checker: bool 42 | run_construction_checker: bool 43 | run_simulation_checker: bool 44 | run_zx_checker: bool 45 | timeout: float 46 | # Functionality 47 | trace_threshold: float 48 | check_partial_equivalence: bool 49 | # Optimizations 50 | backpropagate_output_permutation: bool 51 | elide_permutations: bool 52 | fuse_single_qubit_gates: bool 53 | reconstruct_swaps: bool 54 | remove_diagonal_gates_before_measure: bool 55 | reorder_operations: bool 56 | transform_dynamic_circuit: bool 57 | # Parameterized 58 | additional_instantiations: int 59 | parameterized_tolerance: float 60 | # Simulation 61 | fidelity_threshold: float 62 | max_sims: int 63 | seed: int 64 | state_type: StateType | str 65 | 66 | 67 | def augment_config_from_kwargs(config: Configuration, kwargs: ConfigurationOptions) -> None: 68 | """Augment an existing :class:`.Configuration` with options from a collection of keyword arguments. 69 | 70 | Args: 71 | config: The configuration to augment. 72 | kwargs: The arguments to build the configuration from. 73 | """ 74 | for key, value in kwargs.items(): 75 | if hasattr(config.application, key): 76 | setattr(config.application, key, value) 77 | elif hasattr(config.execution, key): 78 | setattr(config.execution, key, value) 79 | elif hasattr(config.functionality, key): 80 | setattr(config.functionality, key, value) 81 | elif hasattr(config.optimizations, key): 82 | setattr(config.optimizations, key, value) 83 | elif hasattr(config.parameterized, key): 84 | setattr(config.parameterized, key, value) 85 | elif hasattr(config.simulation, key): 86 | setattr(config.simulation, key, value) 87 | else: # pragma: no cover 88 | msg = f"Invalid keyword argument: {key}" 89 | raise ValueError(msg) 90 | -------------------------------------------------------------------------------- /src/mqt/qcec/py.typed: -------------------------------------------------------------------------------- 1 | # Instruct type checkers to look for inline type annotations in this package. 2 | # See PEP 561. 3 | -------------------------------------------------------------------------------- /src/mqt/qcec/verify.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """The main entry point for the QCEC package.""" 10 | 11 | from __future__ import annotations 12 | 13 | from typing import TYPE_CHECKING 14 | 15 | from mqt.core import load 16 | 17 | from .configuration import augment_config_from_kwargs 18 | from .parameterized import check_parameterized 19 | from .pyqcec import Configuration, EquivalenceCheckingManager 20 | 21 | if TYPE_CHECKING: 22 | import os 23 | 24 | from mqt.core.ir import QuantumComputation 25 | from qiskit.circuit import QuantumCircuit 26 | 27 | from ._compat.typing import Unpack 28 | from .configuration import ConfigurationOptions 29 | 30 | __all__ = ["verify"] 31 | 32 | 33 | def __dir__() -> list[str]: 34 | return __all__ 35 | 36 | 37 | def verify( 38 | circ1: QuantumComputation | str | os.PathLike[str] | QuantumCircuit, 39 | circ2: QuantumComputation | str | os.PathLike[str] | QuantumCircuit, 40 | configuration: Configuration | None = None, 41 | **kwargs: Unpack[ConfigurationOptions], 42 | ) -> EquivalenceCheckingManager.Results: 43 | """Verify that ``circ1`` and ``circ2`` are equivalent. 44 | 45 | Wraps creating an instance of :class:`EquivalenceCheckingManager <.EquivalenceCheckingManager>`, 46 | calling :meth:`.EquivalenceCheckingManager.run`, 47 | and returning :attr:`.EquivalenceCheckingManager.results`. 48 | 49 | There are two (non-exclusive) ways of configuring the equivalence checking process: 50 | 51 | 1. Pass a :class:`.Configuration` instance as the ``configuration`` argument. 52 | 53 | 2. Pass keyword arguments to this function. These are directly incorporated into the :class:`.Configuration`. 54 | Any existing configuration is overridden by keyword arguments. 55 | 56 | Args: 57 | circ1: The first circuit. 58 | circ2: The second circuit. 59 | configuration: The configuration to use for the equivalence checking process. 60 | **kwargs: Keyword arguments to configure the equivalence checking process. 61 | 62 | Returns: 63 | The results of the equivalence checking process. 64 | """ 65 | if configuration is None: 66 | configuration = Configuration() 67 | 68 | # prepare the configuration 69 | augment_config_from_kwargs(configuration, kwargs) 70 | 71 | # load the circuits 72 | qc1 = load(circ1) 73 | qc2 = load(circ2) 74 | 75 | if not qc1.is_variable_free() or not qc2.is_variable_free(): 76 | return check_parameterized(qc1, qc2, configuration) 77 | 78 | # create the equivalence checker from configuration 79 | ecm = EquivalenceCheckingManager(qc1, qc2, configuration) 80 | 81 | # execute the check 82 | ecm.run() 83 | 84 | # obtain the result 85 | return ecm.results 86 | -------------------------------------------------------------------------------- /src/mqt/qcec/verify_compilation_flow.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Verify compilation flow results.""" 10 | 11 | from __future__ import annotations 12 | 13 | import warnings 14 | from typing import TYPE_CHECKING 15 | 16 | from mqt.core import load 17 | 18 | from ._compat.importlib import resources 19 | from .compilation_flow_profiles import AncillaMode, generate_profile_name 20 | from .configuration import augment_config_from_kwargs 21 | from .pyqcec import ApplicationScheme, Configuration, EquivalenceCheckingManager 22 | from .verify import verify 23 | 24 | if TYPE_CHECKING: 25 | import os 26 | 27 | from mqt.core.ir import QuantumComputation 28 | from qiskit.circuit import QuantumCircuit 29 | 30 | from ._compat.typing import Unpack 31 | from .configuration import ConfigurationOptions 32 | 33 | __all__ = ["verify_compilation"] 34 | 35 | 36 | def __dir__() -> list[str]: 37 | return __all__ 38 | 39 | 40 | def __check_if_circuit_contains_measurements(circuit: QuantumComputation) -> None: 41 | """Check if the circuit contains measurements and emits a warning if it does not. 42 | 43 | Args: 44 | circuit: The circuit to check. 45 | """ 46 | for op in circuit: 47 | if op.name == "measure": 48 | return 49 | 50 | warnings.warn( 51 | UserWarning( 52 | "One of the circuits does not contain any measurements. " 53 | "This may lead to unexpected results since the measurements are used " 54 | "to infer the output qubit permutation at the end of the circuit. " 55 | "Please consider adding measurements to the circuit _before_ compilation." 56 | ), 57 | stacklevel=2, 58 | ) 59 | 60 | 61 | def verify_compilation( 62 | original_circuit: QuantumComputation | str | os.PathLike[str] | QuantumCircuit, 63 | compiled_circuit: QuantumComputation | str | os.PathLike[str] | QuantumCircuit, 64 | optimization_level: int = 1, 65 | ancilla_mode: AncillaMode = AncillaMode.NO_ANCILLA, 66 | configuration: Configuration | None = None, 67 | **kwargs: Unpack[ConfigurationOptions], 68 | ) -> EquivalenceCheckingManager.Results: 69 | """Verify compilation flow results. 70 | 71 | Similar to :func:`verify <.verify>`, but uses a dedicated compilation flow profile to guide the equivalence checking process. 72 | The compilation flow profile is determined by the ``optimization_level`` and ``ancilla_mode`` arguments. 73 | 74 | There are two (non-exclusive) ways of configuring the equivalence checking process: 75 | 76 | 1. Pass a :class:`Configuration <.Configuration>` instance as the ``configuration`` argument. 77 | 78 | 2. Pass keyword arguments to this function. These are directly incorporated into the :class:`Configuration <.Configuration>`. 79 | Any existing configuration is overridden by keyword arguments. 80 | 81 | Args: 82 | original_circuit: The original circuit. 83 | compiled_circuit: The compiled circuit. 84 | optimization_level: The optimization level used for compiling the circuit (0, 1, 2, or 3). Defaults to 1. 85 | ancilla_mode: 86 | The :class:`ancilla mode <.AncillaMode>` used for realizing multi-controlled Toffoli gates, as available in Qiskit. 87 | Defaults to :attr:`.AncillaMode.NO_ANCILLA`. 88 | configuration: The configuration to use for the equivalence checking process. 89 | **kwargs: Keyword arguments to configure the equivalence checking process. 90 | 91 | Returns: 92 | The results of the equivalence checking process. 93 | """ 94 | if configuration is None: 95 | configuration = Configuration() 96 | 97 | # prepare the configuration 98 | augment_config_from_kwargs(configuration, kwargs) 99 | 100 | # load the circuits 101 | qc1 = load(original_circuit) 102 | __check_if_circuit_contains_measurements(qc1) 103 | qc2 = load(compiled_circuit) 104 | __check_if_circuit_contains_measurements(qc2) 105 | 106 | # use the gate_cost scheme for the verification 107 | configuration.application.construction_scheme = ApplicationScheme.gate_cost 108 | configuration.application.simulation_scheme = ApplicationScheme.gate_cost 109 | configuration.application.alternating_scheme = ApplicationScheme.gate_cost 110 | 111 | # get the pre-defined profile for the gate_cost scheme 112 | profile_name = generate_profile_name(optimization_level=optimization_level, mode=ancilla_mode) 113 | ref = resources.files("mqt.qcec") / "profiles" / profile_name 114 | with resources.as_file(ref) as path: 115 | configuration.application.profile = str(path) 116 | 117 | return verify(qc1, qc2, configuration=configuration) 118 | -------------------------------------------------------------------------------- /src/python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | if(APPLE) 10 | set(BASEPOINT @loader_path) 11 | else() 12 | set(BASEPOINT $ORIGIN) 13 | endif() 14 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 15 | set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) 16 | list( 17 | APPEND 18 | CMAKE_INSTALL_RPATH 19 | ${BASEPOINT} 20 | ${BASEPOINT}/${CMAKE_INSTALL_LIBDIR} 21 | ${BASEPOINT}/../core/${CMAKE_INSTALL_LIBDIR} 22 | ${BASEPOINT}/../core/lib 23 | ${BASEPOINT}/../core/lib64 24 | ${BASEPOINT}/../../core/${CMAKE_INSTALL_LIBDIR} 25 | ${BASEPOINT}/../../core/lib 26 | ${BASEPOINT}/../../core/lib64) 27 | 28 | pybind11_add_module( 29 | pyqcec 30 | # Prefer thin LTO if available 31 | THIN_LTO 32 | # Optimize the bindings for size 33 | OPT_SIZE 34 | # Source code goes here 35 | bindings.cpp) 36 | target_link_libraries(pyqcec PRIVATE MQT::QCEC pybind11_json MQT::ProjectOptions 37 | MQT::ProjectWarnings) 38 | 39 | # Install directive for scikit-build-core 40 | install( 41 | TARGETS pyqcec 42 | DESTINATION . 43 | COMPONENT mqt-qcec_Python) 44 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | # collect all test files 10 | file(GLOB_RECURSE TEST_FILES "*.cpp") 11 | 12 | # add test executable 13 | package_add_test(mqt-qcec-test MQT::QCEC ${TEST_FILES}) 14 | 15 | # link to MQT::CoreAlgorithms library for dynamic circuit tests 16 | target_link_libraries(mqt-qcec-test PRIVATE MQT::CoreAlgorithms MQT::CoreQASM) 17 | -------------------------------------------------------------------------------- /test/circuits/original/5xp1_194.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[17] q; 6 | cx q[10], q[9]; 7 | cx q[10], q[8]; 8 | cx q[10], q[7]; 9 | cx q[10], q[5]; 10 | cx q[11], q[8]; 11 | cx q[11], q[6]; 12 | cx q[15], q[7]; 13 | cx q[15], q[6]; 14 | cx q[15], q[5]; 15 | cx q[15], q[3]; 16 | cx q[16], q[6]; 17 | cx q[16], q[4]; 18 | ccx q[14], q[16], q[5]; 19 | ctrl(3) @ x q[10], q[11], q[12], q[9]; 20 | ctrl(3) @ x q[10], q[11], q[12], q[7]; 21 | ctrl(3) @ x q[10], q[11], q[12], q[0]; 22 | x q[13]; 23 | cx q[13], q[2]; 24 | cx q[13], q[1]; 25 | ccx q[13], q[14], q[4]; 26 | x q[14]; 27 | x q[13]; 28 | ccx q[13], q[14], q[3]; 29 | x q[10]; 30 | ctrl(4) @ x q[10], q[11], q[12], q[16], q[9]; 31 | ctrl(4) @ x q[10], q[11], q[12], q[16], q[8]; 32 | ctrl(4) @ x q[10], q[11], q[12], q[16], q[0]; 33 | ccx q[10], q[12], q[9]; 34 | ccx q[10], q[12], q[7]; 35 | cx q[14], q[2]; 36 | ctrl(3) @ x q[13], q[14], q[15], q[5]; 37 | ctrl(3) @ x q[13], q[14], q[15], q[4]; 38 | x q[13]; 39 | ctrl(5) @ x q[10], q[13], q[14], q[15], q[16], q[6]; 40 | x q[10]; 41 | x q[11]; 42 | ctrl(4) @ x q[10], q[11], q[15], q[16], q[8]; 43 | ctrl(4) @ x q[10], q[11], q[15], q[16], q[7]; 44 | ctrl(4) @ x q[11], q[12], q[15], q[16], q[8]; 45 | x q[10]; 46 | ctrl(6) @ x q[10], q[11], q[13], q[14], q[15], q[16], q[8]; 47 | ctrl(6) @ x q[10], q[11], q[13], q[14], q[15], q[16], q[7]; 48 | x q[10]; 49 | x q[12]; 50 | ctrl(3) @ x q[10], q[11], q[12], q[9]; 51 | ctrl(3) @ x q[10], q[11], q[12], q[8]; 52 | ctrl(3) @ x q[10], q[11], q[12], q[7]; 53 | x q[10]; 54 | ctrl(7) @ x q[10], q[11], q[12], q[13], q[14], q[15], q[16], q[8]; 55 | x q[11]; 56 | x q[13]; 57 | x q[14]; 58 | x q[12]; 59 | x q[16]; 60 | ctrl(3) @ x q[13], q[15], q[16], q[5]; 61 | ctrl(4) @ x q[10], q[13], q[14], q[16], q[6]; 62 | ctrl(3) @ x q[10], q[15], q[16], q[7]; 63 | ctrl(3) @ x q[10], q[15], q[16], q[6]; 64 | ctrl(7) @ x q[10], q[11], q[12], q[13], q[14], q[15], q[16], q[9]; 65 | ctrl(7) @ x q[10], q[11], q[12], q[13], q[14], q[15], q[16], q[8]; 66 | ctrl(7) @ x q[10], q[11], q[12], q[13], q[14], q[15], q[16], q[0]; 67 | ctrl(6) @ x q[10], q[11], q[13], q[14], q[15], q[16], q[7]; 68 | x q[15]; 69 | ctrl(5) @ x q[10], q[13], q[14], q[15], q[16], q[7]; 70 | x q[10]; 71 | x q[16]; 72 | ctrl(3) @ x q[11], q[15], q[16], q[7]; 73 | ctrl(4) @ x q[10], q[14], q[15], q[16], q[6]; 74 | x q[12]; 75 | ctrl(6) @ x q[10], q[11], q[12], q[14], q[15], q[16], q[8]; 76 | ctrl(5) @ x q[10], q[12], q[14], q[15], q[16], q[8]; 77 | x q[16]; 78 | ctrl(4) @ x q[13], q[14], q[15], q[16], q[7]; 79 | ctrl(4) @ x q[13], q[14], q[15], q[16], q[6]; 80 | ctrl(4) @ x q[13], q[14], q[15], q[16], q[5]; 81 | x q[13]; 82 | ctrl(7) @ x q[10], q[11], q[12], q[13], q[14], q[15], q[16], q[9]; 83 | ctrl(7) @ x q[10], q[11], q[12], q[13], q[14], q[15], q[16], q[8]; 84 | ctrl(6) @ x q[10], q[11], q[13], q[14], q[15], q[16], q[7]; 85 | ctrl(5) @ x q[10], q[13], q[14], q[15], q[16], q[7]; 86 | x q[14]; 87 | ctrl(6) @ x q[10], q[11], q[12], q[14], q[15], q[16], q[9]; 88 | ctrl(6) @ x q[10], q[11], q[12], q[14], q[15], q[16], q[8]; 89 | x q[11]; 90 | ctrl(4) @ x q[10], q[11], q[14], q[15], q[7]; 91 | -------------------------------------------------------------------------------- /test/circuits/original/C7552_205.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[21] q; 6 | ccx q[16], q[19], q[6]; 7 | ccx q[16], q[19], q[2]; 8 | cx q[16], q[2]; 9 | ctrl(4) @ x q[16], q[17], q[18], q[20], q[15]; 10 | ctrl(4) @ x q[16], q[17], q[18], q[20], q[14]; 11 | ctrl(4) @ x q[16], q[17], q[18], q[20], q[7]; 12 | ctrl(4) @ x q[16], q[17], q[18], q[20], q[6]; 13 | ccx q[16], q[20], q[15]; 14 | ccx q[16], q[20], q[14]; 15 | ccx q[16], q[20], q[11]; 16 | ccx q[16], q[20], q[7]; 17 | ccx q[16], q[20], q[6]; 18 | ccx q[16], q[20], q[3]; 19 | ccx q[16], q[17], q[7]; 20 | ccx q[16], q[17], q[6]; 21 | ctrl(4) @ x q[16], q[18], q[19], q[20], q[15]; 22 | ctrl(4) @ x q[16], q[18], q[19], q[20], q[11]; 23 | ctrl(4) @ x q[16], q[18], q[19], q[20], q[7]; 24 | ctrl(4) @ x q[16], q[18], q[19], q[20], q[3]; 25 | x q[18]; 26 | ctrl(4) @ x q[16], q[18], q[19], q[20], q[13]; 27 | ctrl(4) @ x q[16], q[18], q[19], q[20], q[9]; 28 | ctrl(4) @ x q[16], q[18], q[19], q[20], q[5]; 29 | ctrl(4) @ x q[16], q[18], q[19], q[20], q[1]; 30 | ctrl(4) @ x q[16], q[17], q[18], q[20], q[13]; 31 | ctrl(4) @ x q[16], q[17], q[18], q[20], q[12]; 32 | ctrl(4) @ x q[16], q[17], q[18], q[20], q[5]; 33 | ctrl(4) @ x q[16], q[17], q[18], q[20], q[4]; 34 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[7]; 35 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[6]; 36 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[5]; 37 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[4]; 38 | ctrl(3) @ x q[16], q[18], q[19], q[6]; 39 | ctrl(3) @ x q[16], q[18], q[19], q[4]; 40 | ctrl(3) @ x q[16], q[18], q[20], q[15]; 41 | ctrl(3) @ x q[16], q[18], q[20], q[14]; 42 | ctrl(3) @ x q[16], q[18], q[20], q[13]; 43 | ctrl(3) @ x q[16], q[18], q[20], q[12]; 44 | ctrl(3) @ x q[16], q[18], q[20], q[11]; 45 | ctrl(3) @ x q[16], q[18], q[20], q[9]; 46 | ctrl(3) @ x q[16], q[18], q[20], q[7]; 47 | ctrl(3) @ x q[16], q[18], q[20], q[6]; 48 | ctrl(3) @ x q[16], q[18], q[20], q[5]; 49 | ctrl(3) @ x q[16], q[18], q[20], q[4]; 50 | ctrl(3) @ x q[16], q[18], q[20], q[3]; 51 | ctrl(3) @ x q[16], q[18], q[20], q[1]; 52 | x q[19]; 53 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[3]; 54 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[1]; 55 | ctrl(3) @ x q[16], q[17], q[19], q[7]; 56 | ctrl(3) @ x q[16], q[17], q[19], q[6]; 57 | ctrl(3) @ x q[16], q[17], q[19], q[3]; 58 | ctrl(3) @ x q[16], q[17], q[19], q[2]; 59 | x q[17]; 60 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[2]; 61 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[0]; 62 | ctrl(4) @ x q[16], q[17], q[19], q[20], q[15]; 63 | ctrl(4) @ x q[16], q[17], q[19], q[20], q[14]; 64 | ctrl(4) @ x q[16], q[17], q[19], q[20], q[11]; 65 | ctrl(4) @ x q[16], q[17], q[19], q[20], q[10]; 66 | ctrl(4) @ x q[16], q[17], q[19], q[20], q[7]; 67 | ctrl(4) @ x q[16], q[17], q[19], q[20], q[6]; 68 | ctrl(4) @ x q[16], q[17], q[19], q[20], q[3]; 69 | ctrl(4) @ x q[16], q[17], q[19], q[20], q[2]; 70 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[15]; 71 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[14]; 72 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[13]; 73 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[12]; 74 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[11]; 75 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[10]; 76 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[9]; 77 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[8]; 78 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[7]; 79 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[6]; 80 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[5]; 81 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[4]; 82 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[3]; 83 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[2]; 84 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[1]; 85 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[20], q[0]; 86 | -------------------------------------------------------------------------------- /test/circuits/original/alu1_198.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[20] q; 6 | ctrl(3) @ x q[8], q[12], q[16], q[4]; 7 | x q[7]; 8 | x q[6]; 9 | x q[5]; 10 | x q[4]; 11 | ctrl(3) @ x q[8], q[13], q[17], q[5]; 12 | ctrl(3) @ x q[8], q[14], q[18], q[6]; 13 | ctrl(3) @ x q[8], q[15], q[19], q[7]; 14 | ctrl(3) @ x q[9], q[12], q[16], q[4]; 15 | ccx q[9], q[16], q[4]; 16 | ctrl(3) @ x q[9], q[13], q[17], q[5]; 17 | ccx q[9], q[17], q[5]; 18 | ctrl(3) @ x q[9], q[14], q[18], q[6]; 19 | ccx q[9], q[18], q[6]; 20 | ctrl(3) @ x q[9], q[15], q[19], q[7]; 21 | ccx q[9], q[19], q[7]; 22 | x q[17]; 23 | x q[11]; 24 | ctrl(3) @ x q[11], q[13], q[17], q[1]; 25 | x q[13]; 26 | x q[10]; 27 | ctrl(3) @ x q[10], q[13], q[17], q[1]; 28 | x q[18]; 29 | ctrl(3) @ x q[11], q[14], q[18], q[2]; 30 | x q[14]; 31 | ctrl(3) @ x q[10], q[14], q[18], q[2]; 32 | x q[19]; 33 | ctrl(3) @ x q[11], q[15], q[19], q[3]; 34 | x q[15]; 35 | ctrl(3) @ x q[10], q[15], q[19], q[3]; 36 | x q[16]; 37 | ctrl(3) @ x q[11], q[12], q[16], q[0]; 38 | -------------------------------------------------------------------------------- /test/circuits/original/apla_203.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[22] q; 6 | ctrl(3) @ x q[13], q[14], q[20], q[11]; 7 | ctrl(3) @ x q[13], q[14], q[20], q[0]; 8 | ctrl(3) @ x q[13], q[14], q[18], q[7]; 9 | ctrl(3) @ x q[13], q[14], q[18], q[4]; 10 | ctrl(3) @ x q[13], q[14], q[18], q[2]; 11 | ctrl(4) @ x q[12], q[13], q[14], q[20], q[11]; 12 | ctrl(4) @ x q[12], q[13], q[14], q[20], q[10]; 13 | ctrl(4) @ x q[12], q[13], q[14], q[18], q[7]; 14 | ctrl(4) @ x q[12], q[13], q[14], q[18], q[5]; 15 | ctrl(4) @ x q[12], q[13], q[14], q[18], q[2]; 16 | x q[20]; 17 | x q[21]; 18 | x q[19]; 19 | x q[18]; 20 | ctrl(6) @ x q[12], q[13], q[18], q[19], q[20], q[21], q[2]; 21 | ctrl(5) @ x q[13], q[18], q[19], q[20], q[21], q[10]; 22 | ctrl(5) @ x q[13], q[18], q[19], q[20], q[21], q[4]; 23 | ctrl(5) @ x q[13], q[18], q[19], q[20], q[21], q[0]; 24 | x q[17]; 25 | x q[16]; 26 | x q[15]; 27 | ctrl(6) @ x q[13], q[15], q[16], q[17], q[18], q[20], q[6]; 28 | ctrl(6) @ x q[13], q[15], q[16], q[17], q[18], q[20], q[3]; 29 | x q[16]; 30 | x q[13]; 31 | ctrl(3) @ x q[13], q[14], q[16], q[2]; 32 | ctrl(6) @ x q[12], q[13], q[15], q[18], q[19], q[21], q[11]; 33 | ctrl(6) @ x q[12], q[13], q[15], q[18], q[19], q[21], q[10]; 34 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[18], q[19], q[21], q[11]; 35 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[18], q[19], q[21], q[10]; 36 | ctrl(8) @ x q[12], q[13], q[14], q[16], q[17], q[18], q[20], q[21], q[7]; 37 | ctrl(8) @ x q[12], q[13], q[14], q[16], q[17], q[18], q[20], q[21], q[4]; 38 | x q[16]; 39 | ctrl(5) @ x q[12], q[13], q[16], q[17], q[20], q[7]; 40 | ctrl(5) @ x q[12], q[13], q[16], q[17], q[20], q[1]; 41 | ctrl(6) @ x q[13], q[16], q[17], q[18], q[20], q[21], q[4]; 42 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[18], q[19], q[21], q[10]; 43 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[18], q[19], q[21], q[2]; 44 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[18], q[19], q[21], q[0]; 45 | x q[13]; 46 | x q[12]; 47 | ctrl(7) @ x q[12], q[13], q[15], q[16], q[17], q[18], q[20], q[9]; 48 | ctrl(7) @ x q[12], q[13], q[15], q[16], q[17], q[18], q[20], q[8]; 49 | ctrl(7) @ x q[12], q[14], q[15], q[16], q[17], q[18], q[20], q[9]; 50 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[20], q[8]; 51 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[20], q[7]; 52 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[20], q[6]; 53 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[20], q[1]; 54 | x q[13]; 55 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[20], q[3]; 56 | ctrl(8) @ x q[12], q[13], q[14], q[16], q[17], q[18], q[20], q[21], q[4]; 57 | ctrl(7) @ x q[12], q[13], q[14], q[17], q[19], q[20], q[21], q[9]; 58 | ctrl(7) @ x q[12], q[13], q[14], q[17], q[19], q[20], q[21], q[4]; 59 | ctrl(8) @ x q[12], q[13], q[14], q[16], q[17], q[19], q[20], q[21], q[2]; 60 | ctrl(9) @ x q[12], q[13], q[15], q[16], q[17], q[18], q[19], q[20], q[21], q[9]; 61 | ctrl(9) @ x q[12], q[13], q[15], q[16], q[17], q[18], q[19], q[20], q[21], q[2]; 62 | x q[13]; 63 | x q[14]; 64 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[17], q[18], q[20], q[8]; 65 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[17], q[18], q[20], q[6]; 66 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[17], q[18], q[20], q[1]; 67 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[17], q[19], q[21], q[7]; 68 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[17], q[19], q[21], q[2]; 69 | ctrl(6) @ x q[13], q[14], q[18], q[19], q[20], q[21], q[11]; 70 | ctrl(6) @ x q[13], q[14], q[18], q[19], q[20], q[21], q[10]; 71 | ctrl(9) @ x q[13], q[14], q[15], q[16], q[17], q[18], q[19], q[20], q[21], q[2]; 72 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[17], q[19], q[21], q[9]; 73 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[17], q[19], q[21], q[7]; 74 | ctrl(9) @ x q[12], q[14], q[15], q[16], q[17], q[18], q[19], q[20], q[21], q[9]; 75 | ctrl(9) @ x q[12], q[14], q[15], q[16], q[17], q[18], q[19], q[20], q[21], q[2]; 76 | x q[13]; 77 | ctrl(5) @ x q[13], q[14], q[16], q[17], q[20], q[8]; 78 | ctrl(5) @ x q[13], q[14], q[16], q[17], q[20], q[7]; 79 | ctrl(6) @ x q[12], q[13], q[14], q[16], q[17], q[20], q[9]; 80 | ctrl(6) @ x q[12], q[13], q[14], q[16], q[17], q[20], q[8]; 81 | ctrl(6) @ x q[12], q[13], q[14], q[16], q[17], q[20], q[7]; 82 | ctrl(6) @ x q[12], q[13], q[14], q[16], q[17], q[20], q[1]; 83 | ctrl(6) @ x q[13], q[14], q[15], q[18], q[19], q[21], q[11]; 84 | ctrl(6) @ x q[13], q[14], q[15], q[18], q[19], q[21], q[3]; 85 | ctrl(6) @ x q[13], q[14], q[15], q[18], q[19], q[21], q[0]; 86 | -------------------------------------------------------------------------------- /test/circuits/original/c2_181.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[35] q; 6 | ccx q[0], q[1], q[2]; 7 | ccx q[3], q[4], q[5]; 8 | ccx q[6], q[7], q[9]; 9 | ccx q[10], q[11], q[12]; 10 | ccx q[13], q[14], q[16]; 11 | ccx q[17], q[18], q[20]; 12 | ccx q[21], q[22], q[24]; 13 | ccx q[25], q[26], q[27]; 14 | ccx q[28], q[29], q[31]; 15 | ccx q[32], q[33], q[34]; 16 | cx q[0], q[1]; 17 | cx q[3], q[4]; 18 | cx q[6], q[7]; 19 | cx q[10], q[11]; 20 | cx q[13], q[14]; 21 | cx q[17], q[18]; 22 | cx q[21], q[22]; 23 | cx q[25], q[26]; 24 | cx q[28], q[29]; 25 | cx q[32], q[33]; 26 | ccx q[7], q[11], q[8]; 27 | ccx q[14], q[18], q[15]; 28 | ccx q[22], q[26], q[23]; 29 | ccx q[29], q[33], q[30]; 30 | ccx q[15], q[23], q[19]; 31 | ccx q[2], q[4], q[5]; 32 | ccx q[9], q[11], q[12]; 33 | ccx q[16], q[18], q[20]; 34 | ccx q[24], q[26], q[27]; 35 | ccx q[31], q[33], q[34]; 36 | ccx q[5], q[8], q[12]; 37 | ccx q[20], q[23], q[27]; 38 | ccx q[12], q[19], q[27]; 39 | ccx q[12], q[15], q[20]; 40 | ccx q[27], q[30], q[34]; 41 | ccx q[5], q[7], q[9]; 42 | ccx q[12], q[14], q[16]; 43 | ccx q[20], q[22], q[24]; 44 | ccx q[27], q[29], q[31]; 45 | ccx q[15], q[23], q[19]; 46 | ccx q[7], q[11], q[8]; 47 | ccx q[14], q[18], q[15]; 48 | ccx q[22], q[26], q[23]; 49 | ccx q[29], q[33], q[30]; 50 | cx q[2], q[4]; 51 | cx q[5], q[7]; 52 | cx q[9], q[11]; 53 | cx q[12], q[14]; 54 | cx q[16], q[18]; 55 | cx q[20], q[22]; 56 | cx q[24], q[26]; 57 | cx q[27], q[29]; 58 | cx q[31], q[33]; 59 | x q[1]; 60 | x q[4]; 61 | x q[7]; 62 | x q[11]; 63 | x q[14]; 64 | x q[18]; 65 | x q[22]; 66 | x q[26]; 67 | x q[29]; 68 | cx q[3], q[4]; 69 | cx q[6], q[7]; 70 | cx q[10], q[11]; 71 | cx q[13], q[14]; 72 | cx q[17], q[18]; 73 | cx q[21], q[22]; 74 | cx q[25], q[26]; 75 | cx q[28], q[29]; 76 | ccx q[7], q[11], q[8]; 77 | ccx q[14], q[18], q[15]; 78 | ccx q[22], q[26], q[23]; 79 | ccx q[15], q[23], q[19]; 80 | ccx q[5], q[7], q[9]; 81 | ccx q[12], q[14], q[16]; 82 | ccx q[20], q[22], q[24]; 83 | ccx q[27], q[29], q[31]; 84 | ccx q[12], q[15], q[20]; 85 | ccx q[12], q[19], q[27]; 86 | ccx q[5], q[8], q[12]; 87 | ccx q[20], q[23], q[27]; 88 | ccx q[2], q[4], q[5]; 89 | ccx q[9], q[11], q[12]; 90 | ccx q[16], q[18], q[20]; 91 | ccx q[24], q[26], q[27]; 92 | ccx q[15], q[23], q[19]; 93 | ccx q[7], q[11], q[8]; 94 | ccx q[14], q[18], q[15]; 95 | ccx q[22], q[26], q[23]; 96 | cx q[3], q[4]; 97 | cx q[6], q[7]; 98 | cx q[10], q[11]; 99 | cx q[13], q[14]; 100 | cx q[17], q[18]; 101 | cx q[21], q[22]; 102 | cx q[25], q[26]; 103 | cx q[28], q[29]; 104 | ccx q[0], q[1], q[2]; 105 | ccx q[3], q[4], q[5]; 106 | ccx q[6], q[7], q[9]; 107 | ccx q[10], q[11], q[12]; 108 | ccx q[13], q[14], q[16]; 109 | ccx q[17], q[18], q[20]; 110 | ccx q[21], q[22], q[24]; 111 | ccx q[25], q[26], q[27]; 112 | ccx q[28], q[29], q[31]; 113 | x q[1]; 114 | x q[4]; 115 | x q[7]; 116 | x q[11]; 117 | x q[14]; 118 | x q[18]; 119 | x q[22]; 120 | x q[26]; 121 | x q[29]; 122 | -------------------------------------------------------------------------------- /test/circuits/original/cm150a_210.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[22] q; 6 | cx q[1], q[0]; 7 | x q[1]; 8 | x q[6]; 9 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[6], q[0]; 10 | x q[14]; 11 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[14], q[0]; 12 | ctrl(5) @ x q[1], q[3], q[4], q[5], q[14], q[0]; 13 | x q[3]; 14 | x q[10]; 15 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[10], q[0]; 16 | x q[18]; 17 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[18], q[0]; 18 | ctrl(5) @ x q[1], q[3], q[4], q[5], q[18], q[0]; 19 | x q[3]; 20 | x q[4]; 21 | x q[8]; 22 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[8], q[0]; 23 | x q[16]; 24 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[16], q[0]; 25 | ctrl(5) @ x q[1], q[3], q[4], q[5], q[16], q[0]; 26 | x q[3]; 27 | x q[12]; 28 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[12], q[0]; 29 | x q[20]; 30 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[20], q[0]; 31 | ctrl(5) @ x q[1], q[3], q[4], q[5], q[20], q[0]; 32 | x q[3]; 33 | x q[4]; 34 | x q[5]; 35 | x q[7]; 36 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[7], q[0]; 37 | x q[15]; 38 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[15], q[0]; 39 | ctrl(5) @ x q[1], q[3], q[4], q[5], q[15], q[0]; 40 | x q[3]; 41 | x q[11]; 42 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[11], q[0]; 43 | x q[19]; 44 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[19], q[0]; 45 | ctrl(5) @ x q[1], q[3], q[4], q[5], q[19], q[0]; 46 | x q[3]; 47 | x q[4]; 48 | x q[9]; 49 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[9], q[0]; 50 | x q[17]; 51 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[17], q[0]; 52 | ctrl(5) @ x q[1], q[3], q[4], q[5], q[17], q[0]; 53 | x q[3]; 54 | x q[13]; 55 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[13], q[0]; 56 | x q[2]; 57 | x q[21]; 58 | ctrl(6) @ x q[1], q[2], q[3], q[4], q[5], q[21], q[0]; 59 | -------------------------------------------------------------------------------- /test/circuits/original/cm151a_211.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[28] q; 6 | ccx q[19], q[20], q[0]; 7 | ccx q[19], q[21], q[1]; 8 | ccx q[19], q[22], q[2]; 9 | ccx q[19], q[23], q[3]; 10 | ccx q[19], q[24], q[4]; 11 | ccx q[19], q[25], q[5]; 12 | ccx q[19], q[26], q[6]; 13 | ccx q[19], q[27], q[7]; 14 | x q[19]; 15 | x q[17]; 16 | ctrl(11) @ x q[9], q[10], q[11], q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[19], q[8]; 17 | ctrl(9) @ x q[11], q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[19], q[1]; 18 | ctrl(10) @ x q[10], q[11], q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[19], q[0]; 19 | ctrl(7) @ x q[13], q[14], q[15], q[16], q[17], q[18], q[19], q[3]; 20 | ctrl(8) @ x q[12], q[13], q[14], q[15], q[16], q[17], q[18], q[19], q[2]; 21 | ctrl(4) @ x q[9], q[17], q[18], q[19], q[0]; 22 | ctrl(4) @ x q[10], q[17], q[18], q[19], q[1]; 23 | ctrl(4) @ x q[11], q[17], q[18], q[19], q[2]; 24 | ctrl(4) @ x q[12], q[17], q[18], q[19], q[3]; 25 | x q[14]; 26 | ctrl(6) @ x q[14], q[15], q[16], q[17], q[18], q[19], q[4]; 27 | ctrl(4) @ x q[14], q[17], q[18], q[19], q[5]; 28 | x q[13]; 29 | ctrl(4) @ x q[13], q[17], q[18], q[19], q[4]; 30 | x q[15]; 31 | ctrl(4) @ x q[15], q[17], q[18], q[19], q[6]; 32 | ctrl(5) @ x q[15], q[16], q[17], q[18], q[19], q[5]; 33 | ctrl(5) @ x q[15], q[16], q[17], q[18], q[19], q[4]; 34 | x q[16]; 35 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[7]; 36 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[6]; 37 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[5]; 38 | ctrl(4) @ x q[16], q[17], q[18], q[19], q[4]; 39 | -------------------------------------------------------------------------------- /test/circuits/original/cm163a_213.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[29] q; 6 | cx q[13], q[5]; 7 | cx q[14], q[8]; 8 | x q[12]; 9 | x q[11]; 10 | x q[10]; 11 | x q[9]; 12 | x q[8]; 13 | x q[7]; 14 | x q[5]; 15 | x q[4]; 16 | ccx q[19], q[27], q[6]; 17 | cx q[15], q[7]; 18 | ctrl(3) @ x q[16], q[17], q[19], q[9]; 19 | ctrl(5) @ x q[19], q[24], q[25], q[26], q[27], q[6]; 20 | ctrl(7) @ x q[16], q[17], q[19], q[20], q[21], q[22], q[23], q[10]; 21 | ctrl(7) @ x q[16], q[17], q[19], q[20], q[21], q[22], q[23], q[9]; 22 | x q[18]; 23 | ctrl(3) @ x q[17], q[18], q[28], q[4]; 24 | ctrl(3) @ x q[17], q[18], q[28], q[3]; 25 | ctrl(8) @ x q[16], q[17], q[18], q[19], q[24], q[25], q[26], q[28], q[4]; 26 | ctrl(8) @ x q[16], q[17], q[18], q[19], q[24], q[25], q[26], q[28], q[2]; 27 | ctrl(4) @ x q[17], q[18], q[27], q[28], q[1]; 28 | ctrl(9) @ x q[16], q[17], q[18], q[19], q[24], q[25], q[26], q[27], q[28], q[1]; 29 | ctrl(4) @ x q[16], q[17], q[18], q[28], q[2]; 30 | x q[16]; 31 | ctrl(4) @ x q[16], q[17], q[18], q[28], q[1]; 32 | ctrl(3) @ x q[16], q[18], q[28], q[3]; 33 | x q[16]; 34 | x q[19]; 35 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[28], q[2]; 36 | ctrl(5) @ x q[16], q[17], q[18], q[19], q[28], q[0]; 37 | ctrl(6) @ x q[16], q[17], q[18], q[19], q[27], q[28], q[1]; 38 | x q[19]; 39 | x q[17]; 40 | ccx q[16], q[17], q[11]; 41 | ctrl(7) @ x q[16], q[17], q[19], q[24], q[25], q[26], q[27], q[6]; 42 | x q[16]; 43 | x q[27]; 44 | ctrl(3) @ x q[16], q[17], q[27], q[12]; 45 | -------------------------------------------------------------------------------- /test/circuits/original/cu_219.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[25] q; 6 | x q[10]; 7 | ccx q[11], q[18], q[1]; 8 | x q[21]; 9 | ctrl(4) @ x q[18], q[19], q[21], q[22], q[0]; 10 | ccx q[18], q[21], q[0]; 11 | x q[22]; 12 | x q[12]; 13 | ctrl(6) @ x q[11], q[12], q[19], q[20], q[21], q[22], q[2]; 14 | x q[17]; 15 | x q[13]; 16 | ctrl(10) @ x q[11], q[12], q[13], q[17], q[19], q[20], q[21], q[22], q[23], q[24], q[4]; 17 | x q[15]; 18 | ctrl(10) @ x q[11], q[12], q[15], q[17], q[19], q[20], q[21], q[22], q[23], q[24], q[4]; 19 | ctrl(9) @ x q[11], q[12], q[15], q[17], q[19], q[20], q[21], q[22], q[24], q[4]; 20 | x q[24]; 21 | x q[14]; 22 | ctrl(10) @ x q[11], q[12], q[14], q[17], q[19], q[20], q[21], q[22], q[23], q[24], q[4]; 23 | x q[23]; 24 | x q[16]; 25 | ctrl(10) @ x q[11], q[12], q[16], q[17], q[19], q[20], q[21], q[22], q[23], q[24], q[4]; 26 | x q[20]; 27 | ctrl(4) @ x q[19], q[20], q[21], q[22], q[10]; 28 | ctrl(4) @ x q[19], q[20], q[21], q[22], q[9]; 29 | x q[11]; 30 | ctrl(5) @ x q[11], q[19], q[20], q[21], q[22], q[3]; 31 | ctrl(6) @ x q[11], q[19], q[20], q[21], q[22], q[23], q[7]; 32 | ctrl(7) @ x q[11], q[19], q[20], q[21], q[22], q[23], q[24], q[8]; 33 | ctrl(7) @ x q[11], q[19], q[20], q[21], q[22], q[23], q[24], q[7]; 34 | x q[23]; 35 | ctrl(6) @ x q[11], q[19], q[20], q[21], q[22], q[23], q[5]; 36 | ctrl(7) @ x q[11], q[19], q[20], q[21], q[22], q[23], q[24], q[6]; 37 | ctrl(7) @ x q[11], q[19], q[20], q[21], q[22], q[23], q[24], q[5]; 38 | x q[20]; 39 | x q[22]; 40 | x q[19]; 41 | ctrl(4) @ x q[19], q[20], q[21], q[22], q[10]; 42 | ctrl(4) @ x q[19], q[20], q[21], q[22], q[9]; 43 | ctrl(5) @ x q[11], q[19], q[20], q[21], q[22], q[4]; 44 | ctrl(5) @ x q[11], q[19], q[20], q[21], q[22], q[2]; 45 | x q[11]; 46 | -------------------------------------------------------------------------------- /test/circuits/original/dk17_224.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[21] q; 6 | ctrl(3) @ x q[11], q[12], q[19], q[5]; 7 | ccx q[11], q[20], q[1]; 8 | x q[19]; 9 | x q[18]; 10 | x q[16]; 11 | x q[15]; 12 | x q[14]; 13 | x q[13]; 14 | ctrl(8) @ x q[11], q[12], q[13], q[14], q[15], q[16], q[18], q[19], q[6]; 15 | x q[20]; 16 | ctrl(9) @ x q[11], q[12], q[13], q[14], q[15], q[16], q[18], q[19], q[20], q[1]; 17 | x q[17]; 18 | ctrl(8) @ x q[11], q[12], q[13], q[15], q[16], q[17], q[19], q[20], q[10]; 19 | ctrl(8) @ x q[11], q[12], q[13], q[15], q[16], q[17], q[19], q[20], q[9]; 20 | ctrl(7) @ x q[11], q[13], q[15], q[16], q[17], q[19], q[20], q[10]; 21 | ctrl(7) @ x q[11], q[13], q[15], q[16], q[17], q[19], q[20], q[2]; 22 | ctrl(7) @ x q[11], q[13], q[15], q[16], q[17], q[19], q[20], q[0]; 23 | ctrl(7) @ x q[11], q[12], q[14], q[17], q[18], q[19], q[20], q[8]; 24 | ctrl(7) @ x q[11], q[12], q[14], q[17], q[18], q[19], q[20], q[2]; 25 | ctrl(9) @ x q[11], q[13], q[14], q[15], q[16], q[17], q[18], q[19], q[20], q[2]; 26 | x q[14]; 27 | x q[17]; 28 | x q[11]; 29 | ctrl(3) @ x q[11], q[12], q[14], q[7]; 30 | ctrl(3) @ x q[11], q[12], q[14], q[6]; 31 | ctrl(3) @ x q[11], q[12], q[17], q[7]; 32 | ccx q[11], q[14], q[7]; 33 | ccx q[11], q[14], q[1]; 34 | x q[14]; 35 | ctrl(4) @ x q[11], q[12], q[14], q[17], q[1]; 36 | x q[17]; 37 | ctrl(8) @ x q[11], q[12], q[13], q[14], q[15], q[16], q[17], q[19], q[10]; 38 | ctrl(8) @ x q[11], q[12], q[13], q[14], q[15], q[16], q[17], q[19], q[9]; 39 | ctrl(7) @ x q[11], q[13], q[14], q[15], q[16], q[17], q[19], q[10]; 40 | ctrl(7) @ x q[11], q[13], q[14], q[15], q[16], q[17], q[19], q[0]; 41 | x q[15]; 42 | ctrl(6) @ x q[11], q[12], q[14], q[17], q[18], q[20], q[8]; 43 | ctrl(6) @ x q[11], q[12], q[14], q[17], q[18], q[20], q[1]; 44 | x q[12]; 45 | ctrl(3) @ x q[11], q[12], q[15], q[4]; 46 | x q[11]; 47 | ctrl(3) @ x q[11], q[12], q[15], q[3]; 48 | x q[15]; 49 | ctrl(7) @ x q[12], q[14], q[15], q[16], q[18], q[19], q[20], q[2]; 50 | ctrl(8) @ x q[11], q[12], q[14], q[15], q[16], q[18], q[19], q[20], q[6]; 51 | ctrl(7) @ x q[11], q[12], q[13], q[14], q[15], q[17], q[18], q[7]; 52 | x q[11]; 53 | ctrl(8) @ x q[11], q[12], q[14], q[15], q[16], q[18], q[19], q[20], q[7]; 54 | ctrl(8) @ x q[11], q[12], q[13], q[14], q[15], q[17], q[18], q[20], q[8]; 55 | -------------------------------------------------------------------------------- /test/circuits/original/dk27_225.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[18] q; 6 | cx q[15], q[0]; 7 | cx q[13], q[8]; 8 | cx q[13], q[1]; 9 | x q[10]; 10 | ccx q[10], q[17], q[5]; 11 | ccx q[10], q[16], q[3]; 12 | cx q[10], q[8]; 13 | cx q[10], q[7]; 14 | ccx q[10], q[12], q[2]; 15 | x q[13]; 16 | ccx q[13], q[15], q[8]; 17 | x q[15]; 18 | ctrl(3) @ x q[10], q[13], q[15], q[8]; 19 | ctrl(3) @ x q[10], q[13], q[15], q[7]; 20 | x q[17]; 21 | x q[16]; 22 | x q[12]; 23 | ctrl(6) @ x q[10], q[12], q[13], q[15], q[16], q[17], q[6]; 24 | ctrl(6) @ x q[10], q[12], q[13], q[15], q[16], q[17], q[1]; 25 | x q[10]; 26 | x q[11]; 27 | ctrl(6) @ x q[10], q[11], q[12], q[13], q[15], q[16], q[6]; 28 | x q[14]; 29 | ctrl(5) @ x q[10], q[13], q[14], q[15], q[17], q[4]; 30 | -------------------------------------------------------------------------------- /test/circuits/original/mod5adder_306.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[32] q; 6 | x q[6]; 7 | x q[7]; 8 | x q[10]; 9 | x q[15]; 10 | x q[18]; 11 | x q[19]; 12 | x q[20]; 13 | x q[24]; 14 | x q[25]; 15 | x q[26]; 16 | x q[28]; 17 | x q[29]; 18 | x q[30]; 19 | x q[31]; 20 | cx q[1], q[6]; 21 | cx q[4], q[6]; 22 | ccx q[3], q[6], q[7]; 23 | cx q[6], q[7]; 24 | cx q[3], q[8]; 25 | ccx q[2], q[7], q[8]; 26 | ccx q[2], q[3], q[8]; 27 | ccx q[3], q[4], q[9]; 28 | ccx q[1], q[4], q[10]; 29 | cx q[1], q[10]; 30 | cx q[10], q[11]; 31 | ccx q[0], q[4], q[11]; 32 | ccx q[0], q[10], q[11]; 33 | ccx q[1], q[4], q[12]; 34 | cx q[12], q[13]; 35 | ccx q[0], q[6], q[13]; 36 | ccx q[0], q[12], q[13]; 37 | cx q[13], q[14]; 38 | ccx q[3], q[11], q[14]; 39 | ccx q[3], q[13], q[14]; 40 | cx q[14], q[9]; 41 | ccx q[2], q[9], q[14]; 42 | cx q[14], q[8]; 43 | ccx q[5], q[8], q[14]; 44 | cx q[0], q[15]; 45 | cx q[4], q[15]; 46 | cx q[1], q[16]; 47 | ccx q[1], q[4], q[16]; 48 | cx q[4], q[16]; 49 | cx q[0], q[17]; 50 | ccx q[0], q[16], q[17]; 51 | cx q[16], q[17]; 52 | cx q[3], q[18]; 53 | cx q[17], q[18]; 54 | ccx q[3], q[15], q[18]; 55 | ccx q[3], q[17], q[18]; 56 | cx q[0], q[19]; 57 | cx q[6], q[19]; 58 | ccx q[0], q[16], q[19]; 59 | ccx q[0], q[6], q[19]; 60 | x q[19]; 61 | ccx q[3], q[19], q[15]; 62 | ccx q[3], q[15], q[19]; 63 | x q[19]; 64 | ccx q[2], q[19], q[18]; 65 | ccx q[2], q[18], q[19]; 66 | cx q[0], q[20]; 67 | cx q[6], q[20]; 68 | ccx q[0], q[10], q[20]; 69 | ccx q[0], q[6], q[20]; 70 | cx q[20], q[21]; 71 | ccx q[3], q[16], q[21]; 72 | ccx q[3], q[20], q[21]; 73 | cx q[4], q[22]; 74 | ccx q[0], q[10], q[22]; 75 | ccx q[0], q[4], q[22]; 76 | cx q[0], q[23]; 77 | ccx q[0], q[6], q[23]; 78 | cx q[6], q[23]; 79 | x q[23]; 80 | ccx q[3], q[23], q[22]; 81 | ccx q[3], q[22], q[23]; 82 | cx q[23], q[21]; 83 | ccx q[2], q[21], q[23]; 84 | cx q[23], q[19]; 85 | ccx q[5], q[19], q[23]; 86 | cx q[0], q[24]; 87 | cx q[12], q[24]; 88 | ccx q[0], q[16], q[24]; 89 | ccx q[0], q[12], q[24]; 90 | ccx q[3], q[24], q[25]; 91 | cx q[24], q[25]; 92 | cx q[0], q[26]; 93 | cx q[12], q[26]; 94 | cx q[3], q[27]; 95 | ccx q[3], q[26], q[27]; 96 | cx q[26], q[27]; 97 | cx q[27], q[25]; 98 | ccx q[2], q[25], q[27]; 99 | ccx q[1], q[4], q[28]; 100 | cx q[4], q[28]; 101 | cx q[0], q[29]; 102 | cx q[12], q[29]; 103 | ccx q[0], q[28], q[29]; 104 | ccx q[0], q[12], q[29]; 105 | ccx q[3], q[29], q[30]; 106 | cx q[29], q[30]; 107 | ccx q[0], q[28], q[31]; 108 | cx q[0], q[31]; 109 | cx q[31], q[11]; 110 | ccx q[3], q[11], q[31]; 111 | cx q[31], q[30]; 112 | ccx q[2], q[30], q[31]; 113 | x q[31]; 114 | ccx q[5], q[31], q[27]; 115 | ccx q[5], q[27], q[31]; 116 | -------------------------------------------------------------------------------- /test/circuits/original/pcler8_248.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[21] q; 6 | ctrl(4) @ x q[15], q[16], q[17], q[18], q[4]; 7 | ctrl(5) @ x q[5], q[6], q[10], q[12], q[17], q[0]; 8 | x q[4]; 9 | x q[3]; 10 | x q[2]; 11 | x q[1]; 12 | x q[11]; 13 | ctrl(5) @ x q[11], q[15], q[16], q[17], q[18], q[3]; 14 | ctrl(3) @ x q[11], q[15], q[16], q[4]; 15 | x q[9]; 16 | ctrl(3) @ x q[9], q[15], q[16], q[3]; 17 | ctrl(6) @ x q[9], q[11], q[15], q[16], q[17], q[18], q[2]; 18 | x q[8]; 19 | ctrl(3) @ x q[8], q[15], q[16], q[2]; 20 | ctrl(7) @ x q[8], q[9], q[11], q[15], q[16], q[17], q[18], q[1]; 21 | x q[7]; 22 | ctrl(3) @ x q[7], q[15], q[16], q[1]; 23 | x q[16]; 24 | ctrl(3) @ x q[15], q[16], q[20], q[4]; 25 | ctrl(3) @ x q[13], q[15], q[16], q[1]; 26 | ctrl(3) @ x q[14], q[15], q[16], q[2]; 27 | ctrl(3) @ x q[15], q[16], q[19], q[3]; 28 | -------------------------------------------------------------------------------- /test/circuits/original/rd73_312.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[25] q; 6 | x q[10]; 7 | x q[12]; 8 | x q[15]; 9 | cx q[5], q[7]; 10 | ccx q[5], q[6], q[7]; 11 | cx q[6], q[7]; 12 | ccx q[5], q[6], q[8]; 13 | cx q[8], q[9]; 14 | ccx q[0], q[7], q[9]; 15 | ccx q[0], q[8], q[9]; 16 | cx q[0], q[10]; 17 | cx q[7], q[10]; 18 | ccx q[0], q[8], q[10]; 19 | ccx q[0], q[7], q[10]; 20 | cx q[10], q[11]; 21 | ccx q[4], q[9], q[11]; 22 | ccx q[4], q[10], q[11]; 23 | cx q[4], q[12]; 24 | cx q[9], q[12]; 25 | ccx q[4], q[10], q[12]; 26 | ccx q[4], q[9], q[12]; 27 | cx q[12], q[13]; 28 | ccx q[1], q[11], q[13]; 29 | ccx q[1], q[12], q[13]; 30 | x q[11]; 31 | ccx q[1], q[11], q[12]; 32 | ccx q[1], q[12], q[11]; 33 | cx q[11], q[14]; 34 | ccx q[2], q[13], q[14]; 35 | ccx q[2], q[11], q[14]; 36 | x q[13]; 37 | ccx q[2], q[13], q[11]; 38 | ccx q[2], q[11], q[13]; 39 | cx q[13], q[14]; 40 | ccx q[3], q[14], q[13]; 41 | cx q[5], q[15]; 42 | cx q[6], q[15]; 43 | cx q[0], q[15]; 44 | x q[15]; 45 | cx q[4], q[15]; 46 | x q[15]; 47 | cx q[1], q[15]; 48 | x q[15]; 49 | cx q[2], q[15]; 50 | x q[15]; 51 | cx q[3], q[15]; 52 | x q[15]; 53 | cx q[0], q[16]; 54 | ccx q[0], q[7], q[16]; 55 | cx q[7], q[16]; 56 | cx q[4], q[17]; 57 | ccx q[4], q[16], q[17]; 58 | cx q[16], q[17]; 59 | cx q[9], q[18]; 60 | ccx q[4], q[16], q[18]; 61 | ccx q[4], q[9], q[18]; 62 | cx q[18], q[19]; 63 | ccx q[1], q[17], q[19]; 64 | ccx q[1], q[18], q[19]; 65 | ccx q[0], q[8], q[20]; 66 | cx q[20], q[21]; 67 | ccx q[4], q[9], q[21]; 68 | ccx q[4], q[20], q[21]; 69 | cx q[21], q[22]; 70 | ccx q[1], q[18], q[22]; 71 | ccx q[1], q[21], q[22]; 72 | cx q[22], q[23]; 73 | ccx q[2], q[19], q[23]; 74 | ccx q[2], q[22], q[23]; 75 | ccx q[4], q[20], q[24]; 76 | cx q[24], q[21]; 77 | ccx q[1], q[21], q[24]; 78 | cx q[24], q[22]; 79 | ccx q[2], q[22], q[24]; 80 | cx q[24], q[23]; 81 | ccx q[3], q[23], q[24]; 82 | -------------------------------------------------------------------------------- /test/circuits/original/rd84_313.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[34] q; 6 | x q[8]; 7 | x q[11]; 8 | x q[13]; 9 | x q[15]; 10 | x q[16]; 11 | x q[17]; 12 | x q[22]; 13 | x q[25]; 14 | x q[28]; 15 | cx q[6], q[8]; 16 | cx q[7], q[8]; 17 | cx q[0], q[8]; 18 | x q[8]; 19 | cx q[5], q[8]; 20 | x q[8]; 21 | cx q[1], q[8]; 22 | x q[8]; 23 | cx q[4], q[8]; 24 | x q[8]; 25 | cx q[2], q[8]; 26 | x q[8]; 27 | cx q[3], q[8]; 28 | x q[8]; 29 | ccx q[6], q[7], q[9]; 30 | cx q[6], q[10]; 31 | ccx q[6], q[7], q[10]; 32 | cx q[7], q[10]; 33 | cx q[0], q[11]; 34 | cx q[10], q[11]; 35 | ccx q[0], q[9], q[11]; 36 | ccx q[0], q[10], q[11]; 37 | cx q[9], q[12]; 38 | ccx q[0], q[10], q[12]; 39 | ccx q[0], q[9], q[12]; 40 | cx q[5], q[13]; 41 | cx q[12], q[13]; 42 | ccx q[5], q[11], q[13]; 43 | ccx q[5], q[12], q[13]; 44 | cx q[11], q[14]; 45 | ccx q[5], q[12], q[14]; 46 | ccx q[5], q[11], q[14]; 47 | cx q[1], q[15]; 48 | cx q[14], q[15]; 49 | ccx q[1], q[13], q[15]; 50 | ccx q[1], q[14], q[15]; 51 | cx q[13], q[14]; 52 | ccx q[1], q[14], q[13]; 53 | cx q[4], q[16]; 54 | cx q[13], q[16]; 55 | ccx q[4], q[15], q[16]; 56 | ccx q[4], q[13], q[16]; 57 | cx q[15], q[13]; 58 | ccx q[4], q[13], q[15]; 59 | cx q[2], q[17]; 60 | cx q[15], q[17]; 61 | ccx q[2], q[16], q[17]; 62 | ccx q[2], q[15], q[17]; 63 | cx q[16], q[15]; 64 | ccx q[2], q[15], q[16]; 65 | x q[16]; 66 | ccx q[3], q[16], q[17]; 67 | ccx q[3], q[17], q[16]; 68 | ccx q[0], q[9], q[18]; 69 | ccx q[5], q[18], q[19]; 70 | cx q[0], q[20]; 71 | ccx q[0], q[10], q[20]; 72 | cx q[10], q[20]; 73 | cx q[5], q[21]; 74 | ccx q[5], q[20], q[21]; 75 | cx q[20], q[21]; 76 | cx q[1], q[22]; 77 | cx q[21], q[22]; 78 | ccx q[1], q[19], q[22]; 79 | ccx q[1], q[21], q[22]; 80 | cx q[12], q[23]; 81 | ccx q[5], q[20], q[23]; 82 | ccx q[5], q[12], q[23]; 83 | cx q[23], q[24]; 84 | ccx q[1], q[21], q[24]; 85 | ccx q[1], q[23], q[24]; 86 | cx q[4], q[25]; 87 | cx q[24], q[25]; 88 | ccx q[4], q[22], q[25]; 89 | ccx q[4], q[24], q[25]; 90 | cx q[18], q[12]; 91 | ccx q[5], q[12], q[18]; 92 | cx q[18], q[26]; 93 | ccx q[1], q[23], q[26]; 94 | ccx q[1], q[18], q[26]; 95 | cx q[26], q[27]; 96 | ccx q[4], q[24], q[27]; 97 | ccx q[4], q[26], q[27]; 98 | cx q[2], q[28]; 99 | cx q[27], q[28]; 100 | ccx q[2], q[25], q[28]; 101 | ccx q[2], q[27], q[28]; 102 | cx q[19], q[29]; 103 | ccx q[1], q[18], q[29]; 104 | ccx q[1], q[19], q[29]; 105 | cx q[29], q[26]; 106 | ccx q[4], q[26], q[29]; 107 | cx q[29], q[27]; 108 | ccx q[2], q[27], q[29]; 109 | x q[29]; 110 | ccx q[3], q[29], q[28]; 111 | ccx q[3], q[28], q[29]; 112 | ccx q[1], q[19], q[30]; 113 | ccx q[4], q[30], q[31]; 114 | ccx q[2], q[31], q[32]; 115 | ccx q[3], q[32], q[33]; 116 | x q[8]; 117 | x q[16]; 118 | x q[29]; 119 | -------------------------------------------------------------------------------- /test/circuits/original/sym9_317.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 2 | // o 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[27] q; 6 | x q[21]; 7 | x q[24]; 8 | cx q[0], q[9]; 9 | ccx q[0], q[8], q[9]; 10 | cx q[8], q[9]; 11 | cx q[7], q[10]; 12 | ccx q[7], q[9], q[10]; 13 | cx q[9], q[10]; 14 | ccx q[0], q[8], q[11]; 15 | cx q[11], q[12]; 16 | ccx q[7], q[9], q[12]; 17 | ccx q[7], q[11], q[12]; 18 | cx q[12], q[13]; 19 | ccx q[1], q[10], q[13]; 20 | ccx q[1], q[12], q[13]; 21 | ccx q[7], q[11], q[14]; 22 | cx q[14], q[15]; 23 | ccx q[1], q[12], q[15]; 24 | ccx q[1], q[14], q[15]; 25 | cx q[15], q[16]; 26 | ccx q[6], q[13], q[16]; 27 | ccx q[6], q[15], q[16]; 28 | ccx q[1], q[14], q[17]; 29 | cx q[17], q[18]; 30 | ccx q[6], q[15], q[18]; 31 | ccx q[6], q[17], q[18]; 32 | cx q[18], q[19]; 33 | ccx q[2], q[16], q[19]; 34 | ccx q[2], q[18], q[19]; 35 | cx q[1], q[20]; 36 | ccx q[1], q[10], q[20]; 37 | cx q[10], q[20]; 38 | cx q[6], q[21]; 39 | cx q[20], q[21]; 40 | ccx q[6], q[17], q[21]; 41 | ccx q[6], q[20], q[21]; 42 | cx q[21], q[22]; 43 | ccx q[2], q[18], q[22]; 44 | ccx q[2], q[21], q[22]; 45 | cx q[22], q[23]; 46 | ccx q[5], q[19], q[23]; 47 | ccx q[5], q[22], q[23]; 48 | cx q[13], q[20]; 49 | ccx q[6], q[20], q[13]; 50 | cx q[2], q[24]; 51 | cx q[13], q[24]; 52 | ccx q[2], q[21], q[24]; 53 | ccx q[2], q[13], q[24]; 54 | cx q[24], q[25]; 55 | ccx q[5], q[22], q[25]; 56 | ccx q[5], q[24], q[25]; 57 | cx q[25], q[26]; 58 | ccx q[4], q[23], q[26]; 59 | ccx q[4], q[25], q[26]; 60 | cx q[16], q[13]; 61 | ccx q[2], q[13], q[16]; 62 | x q[16]; 63 | ccx q[5], q[16], q[24]; 64 | ccx q[5], q[24], q[16]; 65 | cx q[16], q[25]; 66 | ccx q[4], q[25], q[16]; 67 | cx q[16], q[26]; 68 | ccx q[3], q[26], q[16]; 69 | x q[16]; 70 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/Grover_1.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q[11]; 4 | x q[10]; 5 | h q[0]; 6 | h q[1]; 7 | h q[2]; 8 | h q[3]; 9 | h q[4]; 10 | h q[5]; 11 | h q[6]; 12 | h q[7]; 13 | h q[8]; 14 | h q[9]; 15 | h q[10]; 16 | mcx q[0], q[10]; 17 | mcx q[0], q[1], q[10]; 18 | mcx q[0], q[1], q[2], q[10]; 19 | mcx q[0], q[1], q[2], q[3], q[10]; 20 | mcx q[0], q[1], q[2], q[3], q[4], q[10]; 21 | mcx q[0], q[1], q[2], q[3], q[4], q[5], q[10]; 22 | mcx q[0], q[1], q[2], q[3], q[4], q[5], q[6], q[10]; 23 | mcx q[0], q[1], q[2], q[3], q[4], q[5], q[6], q[7], q[10]; 24 | mcx q[0], q[1], q[2], q[3], q[4], q[5], q[6], q[7], q[8], q[10]; 25 | mcx q[0], q[1], q[2], q[3], q[4], q[5], q[6], q[7], q[8], q[9], q[10]; 26 | h q[0]; 27 | h q[1]; 28 | h q[2]; 29 | h q[3]; 30 | h q[4]; 31 | h q[5]; 32 | h q[6]; 33 | h q[7]; 34 | h q[8]; 35 | h q[9]; 36 | x q[0]; 37 | x q[1]; 38 | x q[2]; 39 | x q[3]; 40 | x q[4]; 41 | x q[5]; 42 | x q[6]; 43 | x q[7]; 44 | x q[8]; 45 | x q[9]; 46 | h q[9]; 47 | mcx q[0], q[1], q[2], q[3], q[4], q[5], q[6], q[7], q[8], q[9]; 48 | h q[9]; 49 | x q[0]; 50 | x q[1]; 51 | x q[2]; 52 | x q[3]; 53 | x q[4]; 54 | x q[5]; 55 | x q[6]; 56 | x q[7]; 57 | x q[8]; 58 | x q[9]; 59 | h q[0]; 60 | h q[1]; 61 | h q[2]; 62 | h q[3]; 63 | h q[4]; 64 | h q[5]; 65 | h q[6]; 66 | h q[7]; 67 | h q[8]; 68 | h q[9]; 69 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/Grover_2.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q[12]; 4 | x q[10]; 5 | h q[0]; 6 | h q[1]; 7 | h q[2]; 8 | h q[3]; 9 | h q[4]; 10 | h q[5]; 11 | h q[6]; 12 | h q[7]; 13 | h q[8]; 14 | h q[9]; 15 | h q[10]; 16 | mcx q[0], q[10]; 17 | mcx q[0], q[1], q[10]; 18 | mcx q[0], q[1], q[2], q[10]; 19 | mcx q[0], q[1], q[2], q[3], q[10]; 20 | mcx q[0], q[1], q[2], q[3], q[4], q[11]; 21 | mcx q[11], q[10]; 22 | mcx q[5], q[11], q[10]; 23 | mcx q[5], q[6], q[11], q[10]; 24 | mcx q[5], q[6], q[7], q[11], q[10]; 25 | mcx q[5], q[6], q[7], q[8], q[11], q[10]; 26 | mcx q[5], q[6], q[7], q[8], q[9], q[11], q[10]; 27 | mcx q[0], q[1], q[2], q[3], q[4], q[11]; 28 | h q[0]; 29 | h q[1]; 30 | h q[2]; 31 | h q[3]; 32 | h q[4]; 33 | h q[5]; 34 | h q[6]; 35 | h q[7]; 36 | h q[8]; 37 | h q[9]; 38 | x q[0]; 39 | x q[1]; 40 | x q[2]; 41 | x q[3]; 42 | x q[4]; 43 | x q[5]; 44 | x q[6]; 45 | x q[7]; 46 | x q[8]; 47 | x q[9]; 48 | h q[9]; 49 | mcx q[0], q[1], q[2], q[3], q[4], q[5], q[6], q[7], q[8], q[9]; 50 | h q[9]; 51 | x q[0]; 52 | x q[1]; 53 | x q[2]; 54 | x q[3]; 55 | x q[4]; 56 | x q[5]; 57 | x q[6]; 58 | x q[7]; 59 | x q[8]; 60 | x q[9]; 61 | h q[0]; 62 | h q[1]; 63 | h q[2]; 64 | h q[3]; 65 | h q[4]; 66 | h q[5]; 67 | h q[6]; 68 | h q[7]; 69 | h q[8]; 70 | h q[9]; 71 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/bv_1.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q[10]; 4 | creg c[10]; 5 | h q[0]; 6 | h q[1]; 7 | h q[2]; 8 | h q[3]; 9 | h q[4]; 10 | h q[5]; 11 | h q[6]; 12 | h q[7]; 13 | h q[8]; 14 | x q[9]; 15 | h q[9]; 16 | cx q[0], q[9]; 17 | cx q[1], q[9]; 18 | cx q[2], q[9]; 19 | cx q[3], q[9]; 20 | cx q[4], q[9]; 21 | cx q[5], q[9]; 22 | cx q[6], q[9]; 23 | cx q[7], q[9]; 24 | cx q[8], q[9]; 25 | h q[0]; 26 | h q[1]; 27 | h q[2]; 28 | h q[3]; 29 | h q[4]; 30 | h q[5]; 31 | h q[6]; 32 | h q[7]; 33 | h q[8]; 34 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/bv_2.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q[10]; 4 | creg c[10]; 5 | h q[0]; 6 | h q[1]; 7 | h q[2]; 8 | h q[3]; 9 | h q[4]; 10 | h q[5]; 11 | h q[6]; 12 | h q[7]; 13 | h q[8]; 14 | x q[9]; 15 | h q[9]; 16 | h q[0]; 17 | h q[9]; 18 | cx q[9], q[0]; 19 | h q[0]; 20 | h q[9]; 21 | cx q[1], q[7]; 22 | cx q[7], q[9]; 23 | cx q[1], q[7]; 24 | cx q[7], q[9]; 25 | x q[6]; 26 | ccx q[6], q[2], q[9]; 27 | x q[6]; 28 | ccx q[6], q[2], q[9]; 29 | h q[3]; 30 | h q[9]; 31 | cx q[9], q[3]; 32 | h q[3]; 33 | h q[9]; 34 | h q[4]; 35 | h q[9]; 36 | cx q[9], q[4]; 37 | h q[4]; 38 | h q[9]; 39 | x q[1]; 40 | ccx q[1], q[5], q[9]; 41 | x q[1]; 42 | ccx q[1], q[5], q[9]; 43 | h q[6]; 44 | h q[9]; 45 | cx q[9], q[6]; 46 | h q[6]; 47 | h q[9]; 48 | h q[7]; 49 | h q[9]; 50 | cx q[9], q[7]; 51 | h q[7]; 52 | h q[9]; 53 | h q[8]; 54 | h q[9]; 55 | cx q[9], q[8]; 56 | h q[8]; 57 | h q[9]; 58 | h q[0]; 59 | h q[1]; 60 | h q[2]; 61 | h q[3]; 62 | h q[4]; 63 | h q[5]; 64 | h q[6]; 65 | h q[7]; 66 | h q[8]; 67 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/entanglement_1.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q[10]; 4 | creg c[10]; 5 | h q[0]; 6 | cx q[0], q[1]; 7 | cx q[0], q[2]; 8 | cx q[0], q[3]; 9 | cx q[0], q[4]; 10 | cx q[0], q[5]; 11 | cx q[0], q[6]; 12 | cx q[0], q[7]; 13 | cx q[0], q[8]; 14 | cx q[0], q[9]; 15 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/entanglement_2.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q[10]; 4 | creg c[10]; 5 | h q[0]; 6 | x q[2]; 7 | ccx q[2], q[0], q[1]; 8 | x q[2]; 9 | ccx q[2], q[0], q[1]; 10 | h q[0]; 11 | h q[2]; 12 | cx q[2], q[0]; 13 | h q[0]; 14 | h q[2]; 15 | h q[0]; 16 | h q[3]; 17 | cx q[3], q[0]; 18 | h q[0]; 19 | h q[3]; 20 | h q[0]; 21 | h q[4]; 22 | cx q[4], q[0]; 23 | h q[0]; 24 | h q[4]; 25 | h q[0]; 26 | h q[5]; 27 | cx q[5], q[0]; 28 | h q[0]; 29 | h q[5]; 30 | x q[5]; 31 | ccx q[5], q[0], q[6]; 32 | x q[5]; 33 | ccx q[5], q[0], q[6]; 34 | h q[0]; 35 | h q[7]; 36 | cx q[7], q[0]; 37 | h q[0]; 38 | h q[7]; 39 | cx q[0], q[9]; 40 | cx q[9], q[8]; 41 | cx q[0], q[9]; 42 | cx q[9], q[8]; 43 | cx q[0], q[6]; 44 | cx q[6], q[9]; 45 | cx q[0], q[6]; 46 | cx q[6], q[9]; 47 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/grover-noancilla_indep_qiskit_3.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q[2]; 4 | qreg flag[1]; 5 | creg meas[3]; 6 | h q[0]; 7 | h q[1]; 8 | x flag[0]; 9 | cp(pi/2) q[1],flag[0]; 10 | cx q[1],q[0]; 11 | cp(-pi/2) q[0],flag[0]; 12 | cx q[1],q[0]; 13 | cp(pi/2) q[0],flag[0]; 14 | u2(0,0) q[0]; 15 | u1(-pi) q[1]; 16 | cx q[0],q[1]; 17 | u2(-pi,-pi) q[0]; 18 | u1(-pi) q[1]; 19 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/grover-noancilla_nativegates_ibm_qiskit_opt0_3.qasm: -------------------------------------------------------------------------------- 1 | // Benchmark was created by MQT Bench on 2023-06-29 2 | // For more information about MQT Bench, please visit https://www.cda.cit.tum.de/mqtbench/ 3 | // MQT Bench version: v1.0.0 4 | // Qiskit version: {'qiskit-terra': '0.24.1', 'qiskit-aer': '0.12.0', 'qiskit-ignis': None, 'qiskit-ibmq-provider': '0.20.2', 'qiskit': '0.43.1', 'qiskit-nature': '0.6.2', 'qiskit-finance': '0.3.4', 'qiskit-optimization': '0.5.0', 'qiskit-machine-learning': '0.6.1'} 5 | // Used Gate Set: ['rz', 'sx', 'x', 'cx', 'measure'] 6 | 7 | OPENQASM 2.0; 8 | include "qelib1.inc"; 9 | qreg q[2]; 10 | qreg flag[1]; 11 | creg meas[3]; 12 | rz(pi/2) q[0]; 13 | sx q[0]; 14 | rz(pi/2) q[0]; 15 | rz(pi/2) q[1]; 16 | sx q[1]; 17 | rz(pi/2) q[1]; 18 | rz(pi/4) q[1]; 19 | x flag[0]; 20 | cx q[1],flag[0]; 21 | rz(-pi/4) flag[0]; 22 | cx q[1],flag[0]; 23 | rz(pi/4) flag[0]; 24 | cx q[1],q[0]; 25 | rz(-pi/4) q[0]; 26 | cx q[0],flag[0]; 27 | rz(pi/4) flag[0]; 28 | cx q[0],flag[0]; 29 | rz(-pi/4) flag[0]; 30 | cx q[1],q[0]; 31 | rz(pi/4) q[0]; 32 | cx q[0],flag[0]; 33 | rz(-pi/4) flag[0]; 34 | cx q[0],flag[0]; 35 | rz(pi/4) flag[0]; 36 | rz(pi/2) q[0]; 37 | sx q[0]; 38 | rz(pi/2) q[0]; 39 | x q[0]; 40 | rz(pi/2) q[1]; 41 | sx q[1]; 42 | rz(pi/2) q[1]; 43 | x q[1]; 44 | rz(pi/2) q[1]; 45 | sx q[1]; 46 | rz(pi/2) q[1]; 47 | cx q[0],q[1]; 48 | x q[0]; 49 | rz(pi/2) q[0]; 50 | sx q[0]; 51 | rz(pi/2) q[0]; 52 | rz(pi/2) q[1]; 53 | sx q[1]; 54 | rz(pi/2) q[1]; 55 | x q[1]; 56 | rz(pi/2) q[1]; 57 | sx q[1]; 58 | rz(pi/2) q[1]; 59 | -------------------------------------------------------------------------------- /test/circuits/partialEquivalenceTest/random_1.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q[10]; 4 | creg c[10]; 5 | h q[0]; 6 | h q[1]; 7 | h q[2]; 8 | h q[3]; 9 | h q[4]; 10 | h q[5]; 11 | h q[6]; 12 | h q[7]; 13 | h q[8]; 14 | h q[9]; 15 | ccx q[0], q[6], q[7]; 16 | ccx q[0], q[3], q[7]; 17 | cx q[4], q[2]; 18 | h q[8]; 19 | cx q[5], q[1]; 20 | s q[5]; 21 | h q[6]; 22 | s q[9]; 23 | t q[6]; 24 | cx q[4], q[7]; 25 | s q[4]; 26 | t q[2]; 27 | cx q[3], q[7]; 28 | ccx q[6], q[0], q[9]; 29 | h q[3]; 30 | s q[3]; 31 | t q[8]; 32 | t q[3]; 33 | t q[8]; 34 | cx q[6], q[7]; 35 | h q[9]; 36 | t q[8]; 37 | s q[3]; 38 | cx q[3], q[0]; 39 | h q[7]; 40 | t q[9]; 41 | h q[8]; 42 | h q[2]; 43 | cx q[9], q[5]; 44 | ccx q[2], q[1], q[7]; 45 | s q[3]; 46 | t q[6]; 47 | cx q[7], q[3]; 48 | t q[2]; 49 | ccx q[8], q[2], q[1]; 50 | t q[7]; 51 | t q[2]; 52 | s q[2]; 53 | cx q[5], q[6]; 54 | s q[0]; 55 | ccx q[0], q[5], q[3]; 56 | h q[4]; 57 | cx q[6], q[9]; 58 | s q[6]; 59 | cx q[3], q[8]; 60 | t q[8]; 61 | cx q[9], q[7]; 62 | h q[2]; 63 | cx q[7], q[6]; 64 | s q[6]; 65 | ccx q[9], q[5], q[8]; 66 | cx q[7], q[2]; 67 | ccx q[7], q[1], q[6]; 68 | h q[0]; 69 | cx q[8], q[1]; 70 | h q[5]; 71 | h q[2]; 72 | h q[9]; 73 | cx q[7], q[2]; 74 | cx q[6], q[8]; 75 | cx q[5], q[4]; 76 | cx q[6], q[5]; 77 | ccx q[8], q[2], q[3]; 78 | t q[9]; 79 | h q[3]; 80 | ccx q[9], q[7], q[0]; 81 | h q[4]; 82 | cx q[3], q[4]; 83 | h q[0]; 84 | ccx q[8], q[1], q[4]; 85 | s q[7]; 86 | s q[5]; 87 | ccx q[6], q[3], q[5]; 88 | s q[1]; 89 | ccx q[3], q[6], q[1]; 90 | t q[7]; 91 | ccx q[6], q[7], q[8]; 92 | s q[4]; 93 | ccx q[5], q[1], q[0]; 94 | s q[6]; 95 | ccx q[6], q[3], q[1]; 96 | cx q[1], q[0]; 97 | t q[4]; 98 | t q[7]; 99 | cx q[3], q[4]; 100 | cx q[4], q[8]; 101 | cx q[8], q[4]; 102 | cx q[7], q[5]; 103 | t q[4]; 104 | cx q[7], q[9]; 105 | cx q[1], q[8]; 106 | t q[6]; 107 | s q[9]; 108 | cx q[9], q[1]; 109 | ccx q[4], q[0], q[9]; 110 | t q[5]; 111 | h q[6]; 112 | ccx q[5], q[4], q[9]; 113 | s q[3]; 114 | s q[4]; 115 | h q[8]; 116 | h q[3]; 117 | ccx q[1], q[6], q[3]; 118 | ccx q[9], q[7], q[0]; 119 | cx q[3], q[5]; 120 | ccx q[3], q[8], q[9]; 121 | t q[0]; 122 | ccx q[0], q[9], q[5]; 123 | cx q[5], q[9]; 124 | s q[2]; 125 | h q[9]; 126 | t q[2]; 127 | h q[8]; 128 | ccx q[5], q[1], q[6]; 129 | cx q[9], q[5]; 130 | h q[2]; 131 | cx q[7], q[9]; 132 | cx q[7], q[9]; 133 | s q[5]; 134 | cx q[5], q[8]; 135 | ccx q[7], q[6], q[3]; 136 | h q[6]; 137 | s q[0]; 138 | s q[3]; 139 | ccx q[6], q[5], q[8]; 140 | cx q[0], q[9]; 141 | h q[2]; 142 | t q[3]; 143 | h q[9]; 144 | s q[1]; 145 | ccx q[5], q[2], q[4]; 146 | h q[6]; 147 | ccx q[6], q[1], q[5]; 148 | s q[7]; 149 | s q[2]; 150 | cx q[7], q[5]; 151 | h q[2]; 152 | s q[9]; 153 | cx q[2], q[8]; 154 | cx q[1], q[6]; 155 | -------------------------------------------------------------------------------- /test/circuits/test/test.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 | // o 0 1 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[2] q; 6 | cx q[1], q[0]; 7 | -------------------------------------------------------------------------------- /test/circuits/test/test2.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 2 | // o 0 1 2 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[3] q; 6 | cx q[2], q[1]; 7 | cx q[1], q[0]; 8 | cx q[2], q[1]; 9 | -------------------------------------------------------------------------------- /test/circuits/test/test2_optimized.qasm: -------------------------------------------------------------------------------- 1 | // i 2 0 1 2 | // o 1 2 0 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[3]; 6 | creg c[3]; 7 | cx q[1],q[0]; 8 | cx q[2],q[0]; // | 9 | cx q[0],q[2]; // | swap q[0],q[2]; 10 | //cx q[2],q[0]; 11 | //swap q[0],q[2]; 12 | //cx q[2],q[0]; 13 | swap q[0],q[1]; 14 | cx q[0],q[2]; 15 | -------------------------------------------------------------------------------- /test/circuits/test/test_alternative.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 2 | // o 0 1 2 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[3] q; 6 | h q[1]; 7 | cx q[1], q[2]; 8 | h q[0]; 9 | cx q[1], q[0]; 10 | tdg q[0]; 11 | cx q[2], q[0]; 12 | t q[0]; 13 | cx q[1], q[0]; 14 | tdg q[0]; 15 | t q[1]; 16 | cx q[2], q[0]; 17 | cx q[2], q[1]; 18 | t q[0]; 19 | h q[0]; 20 | tdg q[1]; 21 | t q[2]; 22 | -------------------------------------------------------------------------------- /test/circuits/test/test_ancilla.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 2 | // o 0 1 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[3]; 6 | creg c[2]; 7 | swap q[1],q[2]; 8 | cx q[2],q[0]; 9 | swap q[1],q[2]; 10 | -------------------------------------------------------------------------------- /test/circuits/test/test_ancilla_inputperm.qasm: -------------------------------------------------------------------------------- 1 | // i 0 2 1 2 | // o 0 2 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[3]; 6 | creg c[2]; 7 | swap q[1],q[2]; 8 | cx q[1],q[0]; 9 | swap q[1],q[2]; 10 | -------------------------------------------------------------------------------- /test/circuits/test/test_ancilla_inputperm_outputperm.qasm: -------------------------------------------------------------------------------- 1 | // i 0 2 1 2 | // o 0 1 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[3]; 6 | creg c[2]; 7 | swap q[1],q[2]; 8 | cx q[1],q[0]; 9 | -------------------------------------------------------------------------------- /test/circuits/test/test_ancilla_inputperm_outputperm_optimizedswap.qasm: -------------------------------------------------------------------------------- 1 | // i 0 2 1 2 | // o 1 0 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[3]; 6 | creg c[2]; 7 | swap q[1],q[2]; 8 | cx q[0],q[1]; 9 | cx q[1],q[0]; 10 | -------------------------------------------------------------------------------- /test/circuits/test/test_ancilla_inputperm_outputperm_optimizedswap2.qasm: -------------------------------------------------------------------------------- 1 | // i 0 2 1 3 2 | // o 3 0 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[4]; 6 | creg c[2]; 7 | swap q[1],q[2]; 8 | cx q[0],q[1]; 9 | cx q[1],q[0]; 10 | swap q[1],q[3]; 11 | 12 | //cx q[3],q[1]; 13 | //cx q[1],q[3]; 14 | //id q[0]; 15 | //cx q[3],q[1]; 16 | 17 | //cx q[3],q[0]; 18 | //cx q[0],q[3]; 19 | //id q[0]; 20 | //cx q[3],q[0]; 21 | 22 | //cx q[0],q[1]; 23 | //cx q[1],q[0]; 24 | //id q[0]; 25 | //cx q[0],q[1]; 26 | -------------------------------------------------------------------------------- /test/circuits/test/test_erroneous.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 2 | // o 0 1 2 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[3] q; 6 | h q[1]; 7 | cx q[1], q[2]; 8 | h q[0]; 9 | cx q[1], q[0]; 10 | tdg q[0]; 11 | cx q[2], q[0]; 12 | t q[0]; 13 | cx q[1], q[0]; 14 | tdg q[0]; 15 | t q[1]; 16 | cx q[2], q[0]; 17 | cx q[2], q[1]; 18 | t q[0]; 19 | h q[0]; 20 | tdg q[1]; 21 | -------------------------------------------------------------------------------- /test/circuits/test/test_inputperm.qasm: -------------------------------------------------------------------------------- 1 | // i 1 0 2 | // o 1 0 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[2]; 6 | creg c[2]; 7 | cx q[0],q[1]; 8 | -------------------------------------------------------------------------------- /test/circuits/test/test_optimizedswap.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 | // o 1 0 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[2]; 6 | creg c[2]; 7 | cx q[0],q[1]; 8 | cx q[1],q[0]; 9 | -------------------------------------------------------------------------------- /test/circuits/test/test_original.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 2 | // o 0 1 2 3 | OPENQASM 3.0; 4 | include "stdgates.inc"; 5 | qubit[3] q; 6 | h q[1]; 7 | cx q[1], q[2]; 8 | ccx q[1], q[2], q[0]; 9 | cx q[2], q[1]; 10 | -------------------------------------------------------------------------------- /test/circuits/test/test_outputperm.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 2 | // o 0 2 1 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[3]; 6 | creg c[2]; 7 | swap q[1],q[2]; 8 | cx q[2],q[0]; 9 | -------------------------------------------------------------------------------- /test/circuits/test/test_swap.qasm: -------------------------------------------------------------------------------- 1 | // i 0 1 2 | // o 0 1 3 | OPENQASM 2.0; 4 | include "qelib1.inc"; 5 | qreg q[2]; 6 | creg c[2]; 7 | swap q[0],q[1]; 8 | cx q[0],q[1]; 9 | swap q[0],q[1]; 10 | -------------------------------------------------------------------------------- /test/python/test.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """A simple example of using QCEC.""" 10 | 11 | from __future__ import annotations 12 | 13 | from qiskit import QuantumCircuit, transpile 14 | from qiskit.providers.fake_provider import GenericBackendV2 15 | 16 | from mqt.qcec import verify_compilation 17 | 18 | if __name__ == "__main__": 19 | circ = QuantumCircuit(3) 20 | circ.x(2) 21 | circ.h(range(3)) 22 | circ.ccx(0, 1, 2) 23 | circ.h(range(2)) 24 | circ.x(range(2)) 25 | circ.h(1) 26 | circ.cx(0, 1) 27 | circ.h(1) 28 | circ.x(range(2)) 29 | circ.h(range(2)) 30 | circ.measure_all() 31 | print(circ.draw(fold=-1)) 32 | 33 | # define the target architecture 34 | backend = GenericBackendV2( 35 | num_qubits=5, coupling_map=[[0, 1], [1, 0], [1, 2], [2, 1], [1, 3], [3, 1], [3, 4], [4, 3]] 36 | ) 37 | 38 | # compile the circuit to the target architecture 39 | optimization_level = 1 40 | circ_comp = transpile(circ, backend=backend, optimization_level=optimization_level, seed_transpiler=12345) 41 | print(circ_comp.draw(fold=-1)) 42 | 43 | # verify the compilation 44 | result = verify_compilation(circ, circ_comp, optimization_level=optimization_level) 45 | 46 | # obtain the result 47 | print(result.equivalence) 48 | -------------------------------------------------------------------------------- /test/python/test_compilation_flow_profiles.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Test compilation flow profiles.""" 10 | 11 | from __future__ import annotations 12 | 13 | import difflib 14 | import filecmp 15 | import locale 16 | import os 17 | import sys 18 | from pathlib import Path 19 | from typing import Any, cast 20 | 21 | import pytest 22 | 23 | from mqt.qcec._compat.importlib import resources 24 | from mqt.qcec._compat.optional import HAS_QISKIT 25 | from mqt.qcec.compilation_flow_profiles import AncillaMode, generate_profile, generate_profile_name 26 | 27 | 28 | @pytest.fixture(params=[0, 1, 2, 3]) 29 | def optimization_level(request: Any) -> int: # noqa: ANN401 30 | """Fixture for optimization levels.""" 31 | return cast("int", request.param) 32 | 33 | 34 | @pytest.fixture(params=[AncillaMode.NO_ANCILLA, AncillaMode.RECURSION, AncillaMode.V_CHAIN]) 35 | def ancilla_mode(request: Any) -> AncillaMode: # noqa: ANN401 36 | """Fixture for ancilla modes.""" 37 | return cast("AncillaMode", request.param) 38 | 39 | 40 | def test_ancilla_mode_conversion(ancilla_mode: AncillaMode) -> None: 41 | """Test conversion and equality of ancilla modes.""" 42 | ancilla_str = str(ancilla_mode) 43 | assert AncillaMode(ancilla_str) == ancilla_mode 44 | assert ancilla_str == ancilla_mode 45 | assert ancilla_mode == ancilla_str 46 | 47 | 48 | @pytest.mark.skipif( 49 | os.environ.get("CHECK_PROFILES") is None, 50 | reason="This test is only executed if the CHECK_PROFILES environment variable is set.", 51 | ) 52 | def test_generated_profiles_are_still_valid(optimization_level: int, ancilla_mode: AncillaMode) -> None: 53 | """Test validity of generated profiles. 54 | 55 | The main intention of this check is to catch cases where an update in Qiskit changes the respective costs. 56 | """ 57 | # generate the profile 58 | generate_profile(optimization_level=optimization_level, mode=ancilla_mode, filepath=Path()) 59 | 60 | # get path to the profile from the package resources 61 | profile_name = generate_profile_name(optimization_level=optimization_level, mode=ancilla_mode) 62 | ref = resources.files("mqt.qcec") / "profiles" / profile_name 63 | 64 | # compare the generated profile with the reference profile 65 | with resources.as_file(ref) as path: 66 | equal = filecmp.cmp(path, profile_name, shallow=False) 67 | 68 | if equal: 69 | return 70 | 71 | ref_profile = path.read_text().splitlines(keepends=True) 72 | gen_profile = ( 73 | Path(profile_name).read_text(encoding=locale.getpreferredencoding(False)).splitlines(keepends=True) 74 | ) 75 | diff = difflib.unified_diff(ref_profile, gen_profile, fromfile="reference", tofile="generated", n=0) 76 | num_diffs = sum( 77 | 1 78 | for line in diff 79 | if ( 80 | line.find("Qiskit version") == -1 81 | and ( 82 | (line.startswith("-") and not line.startswith("---")) 83 | or (line.startswith("+") and not line.startswith("+++")) 84 | ) 85 | ) 86 | ) 87 | sys.stdout.writelines(diff) 88 | 89 | assert num_diffs <= 1, ( 90 | f"The generated profile {profile_name} differs from the reference profile {ref} by {num_diffs} lines. " 91 | f"This might be due to a change in Qiskit. If this is the case, the reference profile should be updated." 92 | ) 93 | 94 | 95 | def test_compilation_flow_profile_generation_fails_without_qiskit() -> None: 96 | """Test that profile generation fails if Qiskit is not available.""" 97 | with HAS_QISKIT.disable_locally(), pytest.raises(ImportError, match=r"The 'qiskit' library is required to .*"): 98 | generate_profile() 99 | -------------------------------------------------------------------------------- /test/python/test_configuration.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Test the configuration of the equivalence checker.""" 10 | 11 | from __future__ import annotations 12 | 13 | import pytest 14 | 15 | from mqt.qcec.pyqcec import ApplicationScheme, Configuration, StateType 16 | 17 | 18 | @pytest.mark.parametrize( 19 | ("application_scheme_string", "application_scheme_enum"), 20 | [ 21 | ("sequential", ApplicationScheme.sequential), 22 | ("reference", ApplicationScheme.sequential), 23 | ("one_to_one", ApplicationScheme.one_to_one), 24 | ("naive", ApplicationScheme.one_to_one), 25 | ("lookahead", ApplicationScheme.lookahead), 26 | ("gate_cost", ApplicationScheme.gate_cost), 27 | ("compilation_flow", ApplicationScheme.gate_cost), 28 | ("proportional", ApplicationScheme.proportional), 29 | ], 30 | ) 31 | def test_application_scheme(application_scheme_string: str, application_scheme_enum: ApplicationScheme) -> None: 32 | """Test the application scheme enum.""" 33 | assert ApplicationScheme(application_scheme_string) == application_scheme_enum 34 | 35 | config = Configuration() 36 | 37 | config.application.construction_scheme = application_scheme_enum 38 | config.application.simulation_scheme = application_scheme_enum 39 | config.application.alternating_scheme = application_scheme_enum 40 | 41 | 42 | def test_timeout() -> None: 43 | """Test the timeout configuration.""" 44 | config = Configuration() 45 | config.execution.timeout = 60 46 | config.execution.timeout = 60.0 47 | 48 | 49 | @pytest.mark.parametrize( 50 | ("state_type_string", "state_type_enum"), 51 | [ 52 | ("computational_basis", StateType.computational_basis), 53 | ("classical", StateType.computational_basis), 54 | ("random_1Q_basis", StateType.random_1Q_basis), 55 | ("local_quantum", StateType.random_1Q_basis), 56 | ("stabilizer", StateType.stabilizer), 57 | ("global_quantum", StateType.stabilizer), 58 | ], 59 | ) 60 | def test_state_type(state_type_string: str, state_type_enum: StateType) -> None: 61 | """Test the state type enum.""" 62 | assert StateType(state_type_string) == state_type_enum 63 | 64 | config = Configuration() 65 | config.simulation.state_type = state_type_enum 66 | -------------------------------------------------------------------------------- /test/python/test_construction.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Test the construction of the EquivalenceCheckingManager class.""" 10 | 11 | from __future__ import annotations 12 | 13 | import pytest 14 | from mqt.core.ir import QuantumComputation 15 | 16 | from mqt.qcec.pyqcec import Configuration, EquivalenceCheckingManager 17 | 18 | 19 | @pytest.fixture 20 | def example_circuit() -> QuantumComputation: 21 | """Fixture for a simple circuit.""" 22 | qc = QuantumComputation(1) 23 | qc.h(0) 24 | return qc 25 | 26 | 27 | def test_default_constructor_with_quantum_computation(example_circuit: QuantumComputation) -> None: 28 | """Test constructing an instance from two qiskit circuits with all default arguments.""" 29 | EquivalenceCheckingManager(circ1=example_circuit, circ2=example_circuit) 30 | 31 | 32 | def test_constructor_with_configuration(example_circuit: QuantumComputation) -> None: 33 | """Test constructing an instance from circuits and a configuration object.""" 34 | config = Configuration() 35 | EquivalenceCheckingManager(circ1=example_circuit, circ2=example_circuit, config=config) 36 | -------------------------------------------------------------------------------- /test/python/test_dynamic_circuits.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Tests the dynamic quantum circuit support of QCEC.""" 10 | 11 | from __future__ import annotations 12 | 13 | from qiskit import QuantumCircuit 14 | 15 | from mqt.qcec import verify 16 | from mqt.qcec.pyqcec import EquivalenceCriterion 17 | 18 | 19 | def test_regression1() -> None: 20 | """Test a regression from https://github.com/munich-quantum-toolkit/qcec/issues/343.""" 21 | qc = QuantumCircuit(5) 22 | qc.cx(1, 2) 23 | qc.cx(0, 3) 24 | qc.cx(1, 4) 25 | qc.cx(2, 4) 26 | qc.cx(3, 4) 27 | qc.measure_all() 28 | 29 | qc_dyn = QuantumCircuit(3, 5) 30 | qc_dyn.cx(0, 1) 31 | qc_dyn.cx(0, 2) 32 | qc_dyn.measure(0, 1) 33 | qc_dyn.reset(0) 34 | 35 | qc_dyn.cx(1, 2) 36 | qc_dyn.measure(1, 2) 37 | qc_dyn.reset(1) 38 | 39 | qc_dyn.cx(0, 1) 40 | qc_dyn.measure(0, 0) 41 | 42 | qc_dyn.cx(1, 2) 43 | qc_dyn.measure(1, 3) 44 | qc_dyn.measure(2, 4) 45 | 46 | result = verify(qc, qc_dyn, transform_dynamic_circuit=True, backpropagate_output_permutation=True) 47 | assert result.equivalence == EquivalenceCriterion.equivalent 48 | 49 | 50 | def test_regression2() -> None: 51 | """Test a regression from https://github.com/munich-quantum-toolkit/qcec/issues/343.""" 52 | qc = QuantumCircuit(9) 53 | qc.h(range(9)) 54 | qc.z(8) 55 | qc.cx(0, 8) 56 | qc.cx(1, 8) 57 | qc.cx(3, 8) 58 | qc.cx(5, 8) 59 | qc.cx(6, 8) 60 | qc.cx(7, 8) 61 | qc.h(range(8)) 62 | qc.measure_all() 63 | 64 | qc_dyn = QuantumCircuit(2, 9) 65 | qc_dyn.h(0) 66 | qc_dyn.h(0) 67 | qc_dyn.measure(0, 2) 68 | qc_dyn.reset(0) 69 | qc_dyn.h(0) 70 | qc_dyn.h(0) 71 | qc_dyn.measure(0, 4) 72 | qc_dyn.reset(0) 73 | qc_dyn.h(0) 74 | qc_dyn.h(1) 75 | qc_dyn.z(1) 76 | qc_dyn.cx(0, 1) 77 | qc_dyn.h(0) 78 | qc_dyn.measure(0, 0) 79 | qc_dyn.reset(0) 80 | qc_dyn.h(0) 81 | qc_dyn.cx(0, 1) 82 | qc_dyn.h(0) 83 | qc_dyn.measure(0, 1) 84 | qc_dyn.reset(0) 85 | qc_dyn.h(0) 86 | qc_dyn.cx(0, 1) 87 | qc_dyn.h(0) 88 | qc_dyn.measure(0, 3) 89 | qc_dyn.reset(0) 90 | qc_dyn.h(0) 91 | qc_dyn.cx(0, 1) 92 | qc_dyn.h(0) 93 | qc_dyn.measure(0, 5) 94 | qc_dyn.reset(0) 95 | qc_dyn.h(0) 96 | qc_dyn.cx(0, 1) 97 | qc_dyn.h(0) 98 | qc_dyn.measure(0, 6) 99 | qc_dyn.reset(0) 100 | qc_dyn.h(0) 101 | qc_dyn.cx(0, 1) 102 | qc_dyn.measure(1, 8) 103 | qc_dyn.h(0) 104 | qc_dyn.measure(0, 7) 105 | 106 | result = verify(qc, qc_dyn, transform_dynamic_circuit=True, backpropagate_output_permutation=True) 107 | assert result.equivalence == EquivalenceCriterion.equivalent 108 | -------------------------------------------------------------------------------- /test/python/test_partial_equivalence.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Tests the partial equivalence checking support of QCEC.""" 10 | 11 | from __future__ import annotations 12 | 13 | import pytest 14 | from qiskit import QuantumCircuit 15 | 16 | from mqt.qcec import verify 17 | from mqt.qcec.pyqcec import Configuration, EquivalenceCriterion 18 | 19 | 20 | @pytest.fixture 21 | def original_circuit() -> QuantumCircuit: 22 | """Fixture for a simple circuit.""" 23 | qc = QuantumCircuit(3, 1) 24 | qc.cswap(1, 0, 2) 25 | qc.h(0) 26 | qc.z(2) 27 | qc.cswap(1, 0, 2) 28 | qc.measure(0, 0) 29 | return qc 30 | 31 | 32 | @pytest.fixture 33 | def alternative_circuit() -> QuantumCircuit: 34 | """Fixture for a partially equivalent version of the simple circuit.""" 35 | qc = QuantumCircuit(3, 1) 36 | qc.x(1) 37 | qc.ch(1, 0) 38 | qc.measure(0, 0) 39 | return qc 40 | 41 | 42 | def test_configuration_pec(original_circuit: QuantumCircuit, alternative_circuit: QuantumCircuit) -> None: 43 | """Test if the flag for partial equivalence checking works.""" 44 | config = Configuration() 45 | config.functionality.check_partial_equivalence = True 46 | result = verify(original_circuit, alternative_circuit, configuration=config) 47 | assert result.equivalence == EquivalenceCriterion.equivalent 48 | 49 | 50 | def test_argument_pec(original_circuit: QuantumCircuit, alternative_circuit: QuantumCircuit) -> None: 51 | """Test if the flag for partial equivalence checking works.""" 52 | result = verify(original_circuit, alternative_circuit, check_partial_equivalence=True) 53 | assert result.equivalence == EquivalenceCriterion.equivalent 54 | -------------------------------------------------------------------------------- /test/python/test_verify.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Test the verification of two circuits.""" 10 | 11 | from __future__ import annotations 12 | 13 | import pytest 14 | from qiskit import QuantumCircuit, transpile 15 | 16 | from mqt.qcec import verify 17 | from mqt.qcec.pyqcec import ApplicationScheme, Configuration, EquivalenceCriterion 18 | 19 | 20 | @pytest.fixture 21 | def original_circuit() -> QuantumCircuit: 22 | """Fixture for a simple circuit.""" 23 | qc = QuantumCircuit(3) 24 | qc.h(0) 25 | qc.cx(0, 1) 26 | qc.cx(0, 2) 27 | qc.measure_all() 28 | return qc 29 | 30 | 31 | @pytest.fixture 32 | def alternative_circuit() -> QuantumCircuit: 33 | """Fixture for an alternative version of the simple circuit.""" 34 | qc = QuantumCircuit(3, 3) 35 | qc.h(0) 36 | qc.cx(0, 1) 37 | qc.swap(0, 1) 38 | qc.cx(1, 2) 39 | qc.measure(0, 1) 40 | qc.measure(1, 0) 41 | qc.measure(2, 2) 42 | return qc 43 | 44 | 45 | def test_verify(original_circuit: QuantumCircuit, alternative_circuit: QuantumCircuit) -> None: 46 | """Test the verification of two equivalent circuits.""" 47 | result = verify(original_circuit, alternative_circuit) 48 | assert result.equivalence == EquivalenceCriterion.equivalent 49 | 50 | 51 | def test_verify_kwargs(original_circuit: QuantumCircuit, alternative_circuit: QuantumCircuit) -> None: 52 | """Test the verification of two equivalent circuits with some keyword arguments (one of each category).""" 53 | result = verify( 54 | original_circuit, 55 | alternative_circuit, 56 | alternating_scheme="one_to_one", 57 | timeout=3600, 58 | trace_threshold=1e-6, 59 | transform_dynamic_circuit=True, 60 | additional_instantiations=2, 61 | seed=42, 62 | ) 63 | assert result.equivalence == EquivalenceCriterion.equivalent 64 | 65 | 66 | def test_verify_config(original_circuit: QuantumCircuit, alternative_circuit: QuantumCircuit) -> None: 67 | """Test the verification of two equivalent circuits with a configuration object.""" 68 | config = Configuration() 69 | config.execution.timeout = 3600 70 | result = verify(original_circuit, alternative_circuit, config) 71 | assert result.equivalence == EquivalenceCriterion.equivalent 72 | 73 | 74 | def test_compiled_circuit_without_measurements() -> None: 75 | """Regression test for https://github.com/cda-tum/qcec/issues/236. 76 | 77 | It makes sure that circuits compiled without measurements are handled correctly. 78 | """ 79 | qc = QuantumCircuit(1) 80 | qc.x(0) 81 | qc_compiled = transpile( 82 | qc, 83 | coupling_map=[[0, 1], [1, 0], [1, 2], [2, 1], [2, 3], [3, 2], [3, 4], [4, 3]], 84 | basis_gates=["cx", "x", "id", "u3", "measure", "u2", "rz", "u1", "reset", "sx"], 85 | ) 86 | 87 | result = verify(qc, qc_compiled) 88 | assert result.equivalence == EquivalenceCriterion.equivalent 89 | 90 | 91 | def test_cpp_exception_propagation_internal() -> None: 92 | """Test that C++ exceptions caused by code within QCEC are propagated correctly.""" 93 | qc = QuantumCircuit(1) 94 | qc.x(0) 95 | 96 | config = Configuration() 97 | config.execution.run_alternating_checker = False 98 | config.execution.run_simulation_checker = True 99 | config.execution.run_construction_checker = False 100 | config.execution.run_zx_checker = False 101 | config.application.simulation_scheme = ApplicationScheme.lookahead 102 | 103 | with pytest.raises(ValueError, match=r"Lookahead application scheme can only be used for matrices."): 104 | verify(qc, qc, configuration=config) 105 | -------------------------------------------------------------------------------- /test/python/test_verify_compilation.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 2 | # Copyright (c) 2025 Munich Quantum Software Company GmbH 3 | # All rights reserved. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Licensed under the MIT License 8 | 9 | """Test the compilation flow verification.""" 10 | 11 | from __future__ import annotations 12 | 13 | import pytest 14 | from qiskit import QuantumCircuit, transpile 15 | 16 | from mqt.qcec import verify_compilation 17 | from mqt.qcec.pyqcec import EquivalenceCriterion 18 | 19 | 20 | @pytest.fixture 21 | def original_circuit() -> QuantumCircuit: 22 | """Fixture for a simple circuit.""" 23 | qc = QuantumCircuit(3) 24 | qc.h(0) 25 | qc.cx(0, 1) 26 | qc.cx(0, 2) 27 | qc.measure_all() 28 | return qc 29 | 30 | 31 | @pytest.mark.parametrize("optimization_level", [0, 1, 2, 3]) 32 | def test_verify_compilation_on_optimization_levels(original_circuit: QuantumCircuit, optimization_level: int) -> None: 33 | """Test the verification of the compilation of a circuit to the 5-qubit IBMQ Athens architecture with various optimization levels.""" 34 | compiled_circuit = transpile( 35 | original_circuit, 36 | coupling_map=[[0, 1], [1, 0], [1, 2], [2, 1], [2, 3], [3, 2], [3, 4], [4, 3]], 37 | basis_gates=["cx", "x", "id", "u3", "measure", "u2", "rz", "u1", "reset", "sx"], 38 | optimization_level=optimization_level, 39 | ) 40 | result = verify_compilation(original_circuit, compiled_circuit, optimization_level=optimization_level) 41 | assert result.equivalence in { 42 | EquivalenceCriterion.equivalent, 43 | EquivalenceCriterion.equivalent_up_to_global_phase, 44 | } 45 | 46 | 47 | def test_warning_on_missing_measurements() -> None: 48 | """Tests that a warning is raised when either one of the circuits does not contain measurements.""" 49 | qc = QuantumCircuit(2) 50 | qc.h(0) 51 | qc.cx(0, 1) 52 | 53 | with pytest.warns(UserWarning, match=r"One of the circuits does not contain any measurements."): 54 | result = verify_compilation(qc, qc) 55 | assert result.equivalence == EquivalenceCriterion.equivalent 56 | -------------------------------------------------------------------------------- /test/test_symbolic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Chair for Design Automation, TUM 3 | * Copyright (c) 2025 Munich Quantum Software Company GmbH 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: MIT 7 | * 8 | * Licensed under the MIT License 9 | */ 10 | 11 | #include "Configuration.hpp" 12 | #include "EquivalenceCheckingManager.hpp" 13 | #include "EquivalenceCriterion.hpp" 14 | #include "dd/DDDefinitions.hpp" 15 | #include "ir/QuantumComputation.hpp" 16 | #include "ir/operations/Control.hpp" 17 | #include "ir/operations/Expression.hpp" 18 | 19 | #include <gtest/gtest.h> 20 | 21 | using namespace qc; 22 | using namespace sym; 23 | class SymbolicTest : public ::testing::Test { 24 | public: 25 | Variable x = Variable("x"); 26 | 27 | Symbolic xMonom = Symbolic{Term<dd::fp>{x}}; 28 | Symbolic xMonomNeg = Symbolic{-Term<dd::fp>{x}}; 29 | 30 | QuantumComputation symQc1 = QuantumComputation(1); 31 | QuantumComputation symQc2 = QuantumComputation(1); 32 | }; 33 | 34 | TEST_F(SymbolicTest, SymbolicEqu) { 35 | symQc1.rx(xMonom, 0); 36 | 37 | symQc2.h(0); 38 | symQc2.rz(xMonom, 0); 39 | symQc2.h(0); 40 | 41 | auto ecm = ec::EquivalenceCheckingManager(symQc1, symQc2); 42 | ecm.run(); 43 | 44 | EXPECT_TRUE(ecm.getResults().consideredEquivalent()); 45 | } 46 | 47 | TEST_F(SymbolicTest, SymbolicNonEqu) { 48 | symQc1.rx(xMonom, 0); 49 | 50 | symQc2.h(0); 51 | symQc2.rx(xMonomNeg, 0); 52 | symQc2.h(0); 53 | 54 | auto ecm = ec::EquivalenceCheckingManager(symQc1, symQc2); 55 | ecm.run(); 56 | 57 | EXPECT_FALSE(ecm.getResults().consideredEquivalent()); 58 | } 59 | 60 | TEST_F(SymbolicTest, Timeout) { 61 | // construct large circuit 62 | constexpr auto numLayers = 100000; 63 | symQc1 = qc::QuantumComputation(2); 64 | symQc2 = qc::QuantumComputation(2); 65 | for (auto i = 0; i < numLayers; ++i) { 66 | symQc1.cx(1_pc, 0); 67 | symQc1.rx(xMonom, 0); 68 | 69 | symQc2.cx(1_pc, 0); 70 | symQc2.rx(xMonom, 0); 71 | } 72 | ec::Configuration config{}; 73 | config.execution.timeout = 0.1; 74 | auto ecm = ec::EquivalenceCheckingManager(symQc1, symQc2, config); 75 | 76 | ecm.run(); 77 | EXPECT_EQ(ecm.getResults().equivalence, 78 | ec::EquivalenceCriterion::NoInformation); 79 | } 80 | 81 | TEST_F(SymbolicTest, InvalidCircuit) { 82 | auto qc = qc::QuantumComputation(4); 83 | qc.mcx({1_pc, 2_pc, 3_pc}, 0); 84 | qc.rx(xMonom, 0); 85 | auto ecm = ec::EquivalenceCheckingManager(qc, qc); 86 | ecm.run(); 87 | 88 | EXPECT_EQ(ecm.getResults().equivalence, 89 | ec::EquivalenceCriterion::NoInformation); 90 | } 91 | --------------------------------------------------------------------------------