-
Notifications
You must be signed in to change notification settings - Fork 16
Developing the openqasm3 to QIR visitor
#54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 13 commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
ff0bc92
qasm3 to qir convert function template
ryanhill1 6a0172a
Merge branch 'qasm3-to-qir' of https://github.com/olgOk/qbraid-qir in…
olgOk fd85ab3
Prototype Qasm3Module which utilizes openqasm3 parser to load program…
olgOk b5cc729
Merge branch 'main' into dev_qasm3_olga
ryanhill1 0bf45b1
Merge branch 'main' into qasm3-to-qir
ryanhill1 9a7272f
Merge branch 'qasm3-to-qir' into dev_qasm3_olga
ryanhill1 69a528f
Merge pull request #46 from olgOk/dev_qasm3_olga
ryanhill1 e7f48c4
qasm3 visitor, convert, docs template code cont
ryanhill1 f9ca6d7
qasm3 register / statement element types
ryanhill1 6a87ac1
Merge branch 'main' into qasm3-to-qir
ryanhill1 1daf009
started
TheGupta2012 f29ba38
complete first implementation
TheGupta2012 dd34f2c
starting classical declarations
TheGupta2012 cbcae25
Merge branch 'main' into qasm3-to-qir-harshit
ryanhill1 7fe7a88
consolidate test utils + linters
ryanhill1 c3dc638
fix docs workflow, rm qiskit import
ryanhill1 c9d58dc
add header and update headers script
ryanhill1 4742824
start custom gate unroll
TheGupta2012 38c20da
Add gate unfolding!
TheGupta2012 58055c6
unit tests for gates
TheGupta2012 426be66
start branching instr
TheGupta2012 fa83620
updates on expressions
TheGupta2012 95c303e
add expressions
TheGupta2012 fff05cb
unit test v1 for if
TheGupta2012 02b4690
fix tests for if
TheGupta2012 ce5b300
extend branches to binary and unary ops
TheGupta2012 881fef9
increase verbosity of exceptions
TheGupta2012 40814ea
fix bugs related to u3
TheGupta2012 55a9a09
qasm3 pr review tweaks
ryanhill1 8e95b4d
Merge pull request #68 from qBraid/rh1-qasm3-review
ryanhill1 9f24047
housekeeping (deps, workflows)
ryanhill1 53d8b62
custom exceptions + relative imports
ryanhill1 d726b86
update register definition
TheGupta2012 0604c15
add docs, simplify reset
TheGupta2012 9f8f3b6
fix doc
TheGupta2012 e3b5f65
fix doc
TheGupta2012 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| :orphan: | ||
|
|
||
| qbraid_qir.qasm3 | ||
| ================= | ||
|
|
||
| .. automodule:: qbraid_qir.qasm3 | ||
| :members: | ||
| :undoc-members: | ||
| :show-inheritance: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| .. _sdk_qir_qasm3: | ||
|
|
||
| QASM conversions | ||
| ================== | ||
|
|
||
| Example Usage | ||
| -------------- | ||
|
|
||
| Convert an ``OpenQASM 3`` program to ``QIR`` code: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| from qbraid_qir import dumps | ||
| from qbraid_qir.qasm3 import qasm3_to_qir | ||
|
|
||
| # create a test program | ||
| program = """ | ||
| OPENQASM 3; | ||
| include "stdgates.inc"; | ||
| qubit[2] q; | ||
| h q[0]; | ||
| cx q[0], q[1]; | ||
| measure q[0] -> c[0]; | ||
| measure q[1] -> c[1]; | ||
| """ | ||
|
|
||
| # convert to QIR | ||
| module = qasm3_to_qir(program, name="bell") | ||
|
|
||
| # saves to .ll and .bc files in working directory | ||
| dumps(module) | ||
|
|
||
| print(module) | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| ; ModuleID = 'bell' | ||
| source_filename = "bell" | ||
|
|
||
| %Qubit = type opaque | ||
| %Result = type opaque | ||
|
|
||
| define void @main() #0 { | ||
| entry: | ||
| call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*)) # Corrected %Qubit* null to inttoptr (i64 0 to %Qubit*) | ||
| call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*)) # Corrected %Qubit* null and added correct inttoptr conversion | ||
| call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) # Corrected %Qubit* and %Result* null to correct inttoptr conversion | ||
| call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) # Added correct inttoptr conversion | ||
| ret void | ||
| } | ||
|
|
||
| declare void @__quantum__qis__h__body(%Qubit*) | ||
| declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*) | ||
| declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1 | ||
|
|
||
| attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="2" "required_num_results"="2" } | ||
| attributes #1 = { "irreversible" } | ||
|
|
||
| !llvm.module.flags = !{!0, !1, !2, !3} | ||
| !0 = !{i32 1, !"qir_major_version", i32 1} | ||
| !1 = !{i32 7, !"qir_minor_version", i32 0} | ||
| !2 = !{i32 1, !"dynamic_qubit_management", i1 false} | ||
| !3 = !{i32 1, !"dynamic_result_management", i1 false} | ||
|
|
||
|
|
||
| Execute the QIR program using the `qir-runner <https://github.com/qir-alliance/qir-runner>`_ command line tool: | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| $ qir-runner -f bell.bc | ||
|
|
||
|
|
||
| .. seealso:: | ||
|
|
||
| https://github.com/qBraid/qbraid-qir/tree/main/test-containers |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,6 @@ | |
|
|
||
| """ | ||
| Module defining Cirq LLVM Module elements. | ||
|
|
||
| """ | ||
|
|
||
| import hashlib | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Copyright (C) 2023 qBraid | ||
| # | ||
| # This file is part of the qBraid-SDK | ||
| # | ||
| # The qBraid-SDK is free software released under the GNU General Public License v3 | ||
| # or later. You can redistribute and/or modify it under the terms of the GPL v3. | ||
| # See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>. | ||
| # | ||
| # THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3. | ||
|
|
||
| """ | ||
| Module containing OpenQASM QIR functionality. | ||
|
|
||
| .. currentmodule:: qbraid_qir.qasm3 | ||
|
|
||
| Functions | ||
| ----------- | ||
|
|
||
| .. autosummary:: | ||
| :toctree: ../stubs/ | ||
|
|
||
| qasm3_to_qir | ||
|
|
||
|
|
||
| Classes | ||
| --------- | ||
|
|
||
| .. autosummary:: | ||
| :toctree: ../stubs/ | ||
|
|
||
| Qasm3Module | ||
| BasicQisVisitor | ||
|
|
||
| """ | ||
| from .convert import qasm3_to_qir | ||
| from .elements import Qasm3Module | ||
| from .visitor import BasicQisVisitor |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # Copyright (C) 2023 qBraid | ||
| # | ||
| # This file is part of the qBraid-SDK | ||
| # | ||
| # The qBraid-SDK is free software released under the GNU General Public License v3 | ||
| # or later. You can redistribute and/or modify it under the terms of the GPL v3. | ||
| # See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>. | ||
| # | ||
| # THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3. | ||
|
|
||
| """ | ||
| Module containing OpenQASM to QIR conversion functions | ||
|
|
||
| """ | ||
| from typing import Optional, Union | ||
|
|
||
| import openqasm3 | ||
| from pyqir import Context, Module, qir_module | ||
| from qiskit.qasm3 import loads | ||
| from qiskit.qasm3.exporter import Exporter | ||
|
|
||
| from qbraid_qir.exceptions import QirConversionError | ||
| from qbraid_qir.qasm3.elements import Qasm3Module, generate_module_id | ||
| from qbraid_qir.qasm3.visitor import BasicQisVisitor | ||
|
|
||
|
|
||
| def qasm3_to_qir( | ||
| program: Union[openqasm3.ast.Program, str], name: Optional[str] = None, **kwargs | ||
| ) -> Module: | ||
| """ | ||
| Converts an OpenQASM 3 program to a PyQIR module. | ||
|
|
||
| Args: | ||
| program (openqasm3.ast.Program or str): The OpenQASM 3 program to convert. | ||
| name (str, optional): Identifier for created QIR module. Auto-generated if not provided. | ||
|
|
||
| Keyword Args: | ||
| initialize_runtime (bool): Whether to perform quantum runtime environment initialization, | ||
| default `True`. | ||
| record_output (bool): Whether to record output calls for registers, default `True` | ||
|
|
||
| Returns: | ||
| The QIR ``pyqir.Module`` representation of the input OpenQASM 3 program. | ||
|
|
||
| Raises: | ||
| TypeError: If the input is not a valid OpenQASM 3 program. | ||
| QirConversionError: If the conversion fails. | ||
| """ | ||
| if isinstance(program, str): | ||
| # Supported conversions qasm3 -> qiskit : | ||
| # https://github.com/Qiskit/qiskit-qasm3-import/blob/main/src/qiskit_qasm3_import/converter.py | ||
|
|
||
| # PROPOSED SEMANTIC + DECOMPOSITION PASS | ||
| # qiskit_circuit = loads(program).decompose(reps=3) | ||
| # decomposed_qasm = Exporter().dumps(qiskit_circuit) | ||
| # PROPOSED SEMANTIC + DECOMPOSITION PASS | ||
|
|
||
| # program = openqasm3.parse(decomposed_qasm) | ||
|
|
||
| program = openqasm3.parse(program) | ||
|
|
||
| elif not isinstance(program, openqasm3.ast.Program): | ||
| raise TypeError( | ||
| "Input quantum program must be of type openqasm3.ast.Program or str." | ||
| ) | ||
|
|
||
| if name is None: | ||
| name = generate_module_id() | ||
|
|
||
| llvm_module = qir_module(Context(), name) | ||
| module = Qasm3Module.from_program(program, llvm_module) | ||
|
|
||
| visitor = BasicQisVisitor(**kwargs) | ||
| module.accept(visitor) | ||
|
|
||
| err = llvm_module.verify() | ||
| if err is not None: | ||
| raise QirConversionError(err) | ||
| return llvm_module |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| # Copyright (C) 2023 qBraid | ||
| # | ||
| # This file is part of the qBraid-SDK | ||
| # | ||
| # The qBraid-SDK is free software released under the GNU General Public License v3 | ||
| # or later. You can redistribute and/or modify it under the terms of the GPL v3. | ||
| # See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>. | ||
| # | ||
| # THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3. | ||
|
|
||
| """ | ||
| Module defining Qasm3 Converter elements. | ||
|
|
||
| """ | ||
|
|
||
| import uuid | ||
| from abc import ABCMeta, abstractmethod | ||
| from typing import List, Optional, Tuple | ||
|
|
||
| from openqasm3.ast import ( | ||
| BitType, | ||
| ClassicalDeclaration, | ||
| Program, | ||
| QubitDeclaration, | ||
| Statement, | ||
| ) | ||
| from pyqir import Context, Module | ||
|
|
||
|
|
||
| def generate_module_id() -> str: | ||
| """ | ||
| Generates a QIR module ID from a given openqasm3 program. | ||
| """ | ||
|
|
||
| # TODO: Consider a better approach of generating a unique identifier. | ||
| generated_id = uuid.uuid1() | ||
| return f"circuit-{generated_id}" | ||
|
|
||
|
|
||
| class _ProgramElement(metaclass=ABCMeta): | ||
| @classmethod | ||
| def from_element_list(cls, elements): | ||
| return [cls(elem) for elem in elements] | ||
|
|
||
| @abstractmethod | ||
| def accept(self, visitor): | ||
| pass | ||
|
|
||
|
|
||
| class _Register(_ProgramElement): | ||
| def __init__(self, register: Tuple[str, Optional[int]], is_qubit: bool = True): | ||
| self._register = register | ||
| self._is_qubit = is_qubit | ||
|
|
||
| def accept(self, visitor): | ||
| visitor.visit_register(self._register, self._is_qubit) | ||
|
|
||
| def __str__(self) -> str: | ||
| return f"Register({self._register}, is_qubit = {self._is_qubit})" | ||
|
|
||
|
|
||
| class _Statement(_ProgramElement): | ||
| def __init__(self, statement: Statement): | ||
| self._statement = statement | ||
|
|
||
| def accept(self, visitor): | ||
| visitor.visit_statement(self._statement) | ||
|
|
||
| def __str__(self) -> str: | ||
| return f"Statement({self._statement})" | ||
|
|
||
|
|
||
| class Qasm3Module: | ||
| """ | ||
| A module representing an openqasm3 quantum program using QIR. | ||
|
|
||
| Args: | ||
| name (str): Name of the module. | ||
| module (Module): QIR Module instance. | ||
| num_qubits (int): Number of qubits in the circuit. | ||
| num_clbits (int): Number of classical bits in the circuit. | ||
| elements (List[Statement]): List of openqasm3 Statements. | ||
| """ | ||
|
|
||
| def __init__( | ||
| self, name: str, module: Module, num_qubits: int, num_clbits: int, elements | ||
| ): | ||
| self._name = name | ||
| self._module = module | ||
| self._num_qubits = num_qubits | ||
| self._num_clbits = num_clbits | ||
| self._elements = elements | ||
|
|
||
| @property | ||
| def name(self) -> str: | ||
| """Returns the name of the module.""" | ||
| return self._name | ||
|
|
||
| @property | ||
| def module(self) -> Module: | ||
| """Returns the QIR Module instance.""" | ||
| return self._module | ||
|
|
||
| @property | ||
| def num_qubits(self) -> int: | ||
| """Returns the number of qubits in the circuit.""" | ||
| return self._num_qubits | ||
|
|
||
| @property | ||
| def num_clbits(self) -> int: | ||
| """Returns the number of classical bits in the circuit.""" | ||
| return self._num_clbits | ||
|
|
||
| @classmethod | ||
| def from_program(cls, program: Program, module: Optional[Module] = None): | ||
| """ | ||
| Class method. Construct a Qasm3Module from a given openqasm3.ast.Program object | ||
| and an optional QIR Module. | ||
| """ | ||
| elements: List[Statement] = [] | ||
|
|
||
| num_qubits = 0 | ||
| num_clbits = 0 | ||
| for statement in program.statements: | ||
| if isinstance(statement, QubitDeclaration): | ||
| name = statement.qubit.name | ||
| size = None if statement.size is None else statement.size.value | ||
| num_qubits += 1 if size is None else size | ||
| elements.append(_Register((name, size), True)) | ||
|
|
||
| elif isinstance(statement, ClassicalDeclaration) and isinstance( | ||
| statement.type, BitType | ||
| ): | ||
| name = statement.identifier.name | ||
| size = ( | ||
| None if statement.type.size is None else statement.type.size.value | ||
| ) | ||
| num_clbits += 1 if size is None else size | ||
| elements.append(_Register((name, size), False)) | ||
| else: | ||
| elements.append(_Statement(statement)) | ||
|
|
||
| if module is None: | ||
| module = Module(Context(), generate_module_id(program)) | ||
|
|
||
| # for element in elements: | ||
| # print(element,"\n") | ||
| return cls( | ||
| name="main", | ||
| module=module, | ||
| num_qubits=num_qubits, | ||
| num_clbits=num_clbits, | ||
| elements=elements, | ||
| ) | ||
|
|
||
| def accept(self, visitor): | ||
| visitor.visit_qasm3_module(self) | ||
| for element in self._elements: | ||
| element.accept(visitor) | ||
| visitor.record_output(self) | ||
| visitor.finalize() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.