Skip to content
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

Developing the openqasm3 to QIR visitor #54

Merged
merged 36 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ff0bc92
qasm3 to qir convert function template
ryanhill1 Jan 18, 2024
6a0172a
Merge branch 'qasm3-to-qir' of https://github.com/olgOk/qbraid-qir in…
olgOk Jan 26, 2024
fd85ab3
Prototype Qasm3Module which utilizes openqasm3 parser to load program…
olgOk Jan 26, 2024
b5cc729
Merge branch 'main' into dev_qasm3_olga
ryanhill1 Feb 5, 2024
0bf45b1
Merge branch 'main' into qasm3-to-qir
ryanhill1 Feb 5, 2024
9a7272f
Merge branch 'qasm3-to-qir' into dev_qasm3_olga
ryanhill1 Feb 5, 2024
69a528f
Merge pull request #46 from olgOk/dev_qasm3_olga
ryanhill1 Feb 5, 2024
e7f48c4
qasm3 visitor, convert, docs template code cont
ryanhill1 Feb 5, 2024
f9ca6d7
qasm3 register / statement element types
ryanhill1 Feb 5, 2024
6a87ac1
Merge branch 'main' into qasm3-to-qir
ryanhill1 Feb 15, 2024
1daf009
started
TheGupta2012 Feb 18, 2024
f29ba38
complete first implementation
TheGupta2012 Mar 4, 2024
dd34f2c
starting classical declarations
TheGupta2012 Mar 5, 2024
cbcae25
Merge branch 'main' into qasm3-to-qir-harshit
ryanhill1 Mar 5, 2024
7fe7a88
consolidate test utils + linters
ryanhill1 Mar 5, 2024
c3dc638
fix docs workflow, rm qiskit import
ryanhill1 Mar 5, 2024
c9d58dc
add header and update headers script
ryanhill1 Mar 5, 2024
4742824
start custom gate unroll
TheGupta2012 Mar 7, 2024
38c20da
Add gate unfolding!
TheGupta2012 Mar 9, 2024
58055c6
unit tests for gates
TheGupta2012 Mar 11, 2024
426be66
start branching instr
TheGupta2012 Mar 14, 2024
fa83620
updates on expressions
TheGupta2012 Mar 18, 2024
95c303e
add expressions
TheGupta2012 Mar 20, 2024
fff05cb
unit test v1 for if
TheGupta2012 Mar 22, 2024
02b4690
fix tests for if
TheGupta2012 Mar 25, 2024
ce5b300
extend branches to binary and unary ops
TheGupta2012 Mar 26, 2024
881fef9
increase verbosity of exceptions
TheGupta2012 Mar 27, 2024
40814ea
fix bugs related to u3
TheGupta2012 Mar 27, 2024
55a9a09
qasm3 pr review tweaks
ryanhill1 Mar 28, 2024
8e95b4d
Merge pull request #68 from qBraid/rh1-qasm3-review
ryanhill1 Mar 28, 2024
9f24047
housekeeping (deps, workflows)
ryanhill1 Mar 28, 2024
53d8b62
custom exceptions + relative imports
ryanhill1 Mar 28, 2024
d726b86
update register definition
TheGupta2012 Mar 29, 2024
0604c15
add docs, simplify reset
TheGupta2012 Mar 29, 2024
9f8f3b6
fix doc
TheGupta2012 Mar 29, 2024
e3b5f65
fix doc
TheGupta2012 Mar 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
*issue tag(s), if exist*:
<!-- Please link or tag any issues that is PR closes -->

## Changes
1 change: 0 additions & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ jobs:
run: |
python3 -m pip install --upgrade pip
python3 -m pip install -r docs/requirements.txt
python3 -m pip install -r requirements.txt
python3 -m pip install -e .
- name: Build docs
run: |
Expand Down
70 changes: 59 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,32 @@ qBraid-SDK extension providing support for QIR conversions.

This project aims to make [QIR](https://www.qir-alliance.org/) representations accessible via the qBraid-SDK [transpiler](#architecture-diagram), and by doing so, open the door to language-specific conversions from any and all high-level quantum languages [supported](https://docs.qbraid.com/en/latest/sdk/overview.html#supported-frontends) by `qbraid`. See QIR Alliance: [why do we need it?](https://www.qir-alliance.org/qir-book/concepts/why-do-we-need.html).

## Getting started

### Installation
## Installation

qBraid-QIR requires Python 3.8 or greater, and can be installed with pip as follows:

```shell
pip install qbraid-qir
```

### Optional dependencies

qBraid-QIR offers integrations that require extra (optional) dependencies, which can be installed as follows:

For Cirq to QIR conversions, install the `cirq` extra:

```shell
pip install 'qbraid-qir[cirq]'
```

For OpenQASM 3 to QIR conversions, install the `qasm3` extra:

```shell
pip install 'qbraid-qir[qasm3]'
```

### Install from source

You can also install from source by cloning this repository and running a pip install command
in the root directory of the repository:

Expand All @@ -53,7 +69,13 @@ cd qbraid-qir
pip install .
```

### Check version
To include optional dependencies when installing from source, use the same "extras_require" format, e.g.

```shell
pip install '.[cirq,qasm3]'
```

## Check version

You can view the version of qbraid-qir you have installed within a Python shell as follows:

Expand All @@ -63,18 +85,20 @@ In [1]: import qbraid_qir
In [2]: qbraid_qir.__version__
```

### Resources
## Resources

- [User Guide](https://docs.qbraid.com/projects/qir/)
- [API Reference](https://docs.qbraid.com/projects/qir/en/latest/api/qbraid_qir.html)
- [Example Notebooks](examples)
- [Test Containers](test-containers)

### Usage Example
## Usage examples

### Cirq conversions

```python
import cirq
from qbraid_qir import cirq_to_qir
from qbraid_qir.cirq import cirq_to_qir

q0, q1 = cirq.LineQubit.range(2)

Expand All @@ -89,6 +113,30 @@ module = cirq_to_qir(circuit, name="my-circuit")
ir = str(module)
```

### OpenQASM 3 conversions

```python
from qbraid_qir.qasm3 import qasm3_to_qir

program = """
OPENQASM 3;
include "stdgates.inc";

qubit[2] q;
bit[2] c;

h q[0];
cx q[0], q[1];

measure q[0] -> c[0];
measure q[1] -> c[1];
"""

module = qasm3_to_qir(program, name="my-program")

ir = str(module)
```

### Add QIR node to qBraid conversion graph

```python
Expand Down Expand Up @@ -131,12 +179,12 @@ citation details, please refer to [CITATION.cff](CITATION.cff).

```tex
@software{Kushnir_qBraid-QIR_Python_package_2024,
author = {Kushnir, Samuel and Jain, Rohan and Parakh, Priyansh and Hill, Ryan James},
author = {Kushnir, Samuel and Gupta, Harshit and Jain, Rohan and Parakh, Priyansh and Hill, Ryan James},
license = {GPL-3.0},
month = jan,
title = {{qBraid-QIR: Python package for generating QIR programs from Cirq.}},
month = mar,
title = {{qBraid-QIR: Python package for QIR conversions, integrations, and utilities.}},
url = {https://github.com/qBraid/qbraid-qir},
version = {0.1.0},
version = {0.2.0},
year = {2024}
}
```
Expand Down
9 changes: 9 additions & 0 deletions docs/api/qbraid_qir.qasm3.rst
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:
6 changes: 2 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,10 @@
# set_type_checking_flag = True
autodoc_member_order = "bysource"
autoclass_content = "both"
autodoc_mock_imports = ["cirq"]
autodoc_mock_imports = ["cirq", "openqasm3"]
napoleon_numpy_docstring = False
todo_include_todos = True
mathjax_path = (
"https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
)
mathjax_path = "https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML"

# The master toctree document.
master_doc = "index"
Expand Down
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ This project was conceived in cooperation with the Quantum Open Source Foundatio
:hidden:

userguide/cirq_qir
userguide/qasm3_qir

.. toctree::
:maxdepth: 1
Expand All @@ -173,6 +174,7 @@ This project was conceived in cooperation with the Quantum Open Source Foundatio

api/qbraid_qir
api/qbraid_qir.cirq
api/qbraid_qir.qasm3


Indices and Tables
Expand Down
75 changes: 75 additions & 0 deletions docs/userguide/qasm3_qir.rst
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
2 changes: 1 addition & 1 deletion examples/microsoft_resource_estimatation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"from azure.quantum import Workspace\n",
"from azure.quantum.qiskit import AzureQuantumProvider\n",
"from azure.quantum.qiskit.job import AzureQuantumJob\n",
"from qbraid_qir import cirq_to_qir\n",
"from qbraid_qir.cirq import cirq_to_qir\n",
"from qiskit.tools.monitor import job_monitor"
]
},
Expand Down
24 changes: 23 additions & 1 deletion qbraid_qir/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,28 @@

"""
from ._version import __version__
from .cirq import cirq_to_qir
from .exceptions import QbraidQirError, QirConversionError
from .serialization import dumps

__all__ = [
"__version__",
"QbraidQirError",
"QirConversionError",
"dumps",
]

_lazy_mods = ["cirq", "qasm3"]


def __getattr__(name):
if name in _lazy_mods:
import importlib # pylint: disable=import-outside-toplevel

module = importlib.import_module(f".{name}", __name__)
globals()[name] = module
return module
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


def __dir__():
return sorted(__all__ + _lazy_mods)
2 changes: 1 addition & 1 deletion qbraid_qir/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
Version number (major.minor.patch[-label])

"""
__version__ = "0.1.2.dev"
__version__ = "0.2.0.dev"
9 changes: 9 additions & 0 deletions qbraid_qir/cirq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,16 @@
CirqModule
BasicQisVisitor

Exceptions
-----------

.. autosummary::
:toctree: ../stubs/

CirqConversionError

"""
from .convert import cirq_to_qir
from .elements import CirqModule
from .exceptions import CirqConversionError
from .visitor import BasicQisVisitor
14 changes: 7 additions & 7 deletions qbraid_qir/cirq/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
import cirq
from pyqir import Context, Module, qir_module

from qbraid_qir.cirq.elements import CirqModule, generate_module_id
from qbraid_qir.cirq.passes import preprocess_circuit
from qbraid_qir.cirq.visitor import BasicQisVisitor
from qbraid_qir.exceptions import QirConversionError
from .elements import CirqModule, generate_module_id
from .exceptions import CirqConversionError
from .passes import preprocess_circuit
from .visitor import BasicQisVisitor


def cirq_to_qir(circuit: cirq.Circuit, name: Optional[str] = None, **kwargs) -> Module:
Expand All @@ -42,7 +42,7 @@ def cirq_to_qir(circuit: cirq.Circuit, name: Optional[str] = None, **kwargs) ->
Raises:
TypeError: If the input is not a valid Cirq circuit.
ValueError: If the input circuit is empty.
QirConversionError: If the conversion fails.
CirqConversionError: If the conversion fails.
"""
if not isinstance(circuit, cirq.Circuit):
raise TypeError("Input quantum program must be of type cirq.Circuit.")
Expand All @@ -56,7 +56,7 @@ def cirq_to_qir(circuit: cirq.Circuit, name: Optional[str] = None, **kwargs) ->
try:
circuit = preprocess_circuit(circuit)
except Exception as err: # pylint: disable=broad-exception-caught
raise QirConversionError("Failed to preprocess circuit.") from err
raise CirqConversionError("Failed to preprocess circuit.") from err

llvm_module = qir_module(Context(), name)
module = CirqModule.from_circuit(circuit, llvm_module)
Expand All @@ -66,5 +66,5 @@ def cirq_to_qir(circuit: cirq.Circuit, name: Optional[str] = None, **kwargs) ->

err = llvm_module.verify()
if err is not None:
raise QirConversionError(err)
raise CirqConversionError(err)
return llvm_module
2 changes: 0 additions & 2 deletions qbraid_qir/cirq/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

"""
Module defining Cirq LLVM Module elements.

"""

import hashlib
Expand Down Expand Up @@ -45,7 +44,6 @@ def generate_module_id(circuit: cirq.Circuit) -> str:


class _CircuitElement(metaclass=ABCMeta):

@abstractmethod
def accept(self, visitor):
pass
Expand Down
19 changes: 19 additions & 0 deletions qbraid_qir/cirq/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 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 exceptions for errors raised during Cirq conversions.

"""
from qbraid_qir.exceptions import QirConversionError


class CirqConversionError(QirConversionError):
"""Class for errors raised when converting Cirq program to QIR."""
Loading
Loading