Code Monkey home page Code Monkey logo

qbraid-qir's Introduction

qbraid-sdk-header

CI codecov Documentation Status PyPI version Downloads License Discord

The qBraid-SDK is a platform-agnostic quantum runtime framework designed for both quantum software and hardware providers.

This Python-based tool streamlines the full lifecycle management of quantum jobs—from defining program specifications to job submission, and through to the post-processing and visualization of results. Distinguishing itself through a streamlined and highly-configurable approach to cross-platform integration, the qBraid-SDK does not assume a fixed target software framework. Instead, it allows providers to dynamically register any desired run input program type as the target, depending on their specific needs. These program types are interconnected via a graph-based transpiler, where each program type is represented as a node and supported conversions as edges. The breadth, depth, and connectivity of this ConversionGraph can be customized by the provider.

The framework also facilitates the insertion of additional program validations, circuit transformations, and transpiler/compiler steps into its modular pipeline through a comprehensive TargetProfile. This profile encapsulates both device properties (such as number of qubits, maximum shots, native gate set) and the software requirements (ProgramSpec) needed to submit a job, vastly reducing the overhead and redundancy typically associated with cross-platform integrations in quantum computing.

Key Features

1. Quantum Program Integration

Offers native support for 10 major quantum programming libraries including 20+ inter-library conversions with the ability to dynamically register new program types and conversions on the fly. This enables flexible program submissions to cater to the unique capabilities and constraints of your preferred framework, facilitated by a unique conversion map that automatically adapts quantum programs during runtime according to the given specifications.

2. Modular Design

Module Description
qbraid.programs Extracts and manages metadata from supported quantum program types, with the flexibility to introduce new types.
qbraid.transpiler Bridges different quantum programming IRs through native and customizable circuit conversions.
qbraid.transforms Ensures quantum programs conform to hardware specifications through essential runtime transformations.
qbraid.runtime Defines essential abstractions for providers, devices, jobs, and results, integrated through a coherent runtime profile.
qbraid.visualization Provides tools for visualizing quantum circuits and experimental data, enhancing data interpretation.

3. Extensibility and Customization

The framework encourages community contributions and extensions, supporting an evolving ecosystem of program types and conversions, adaptable to specific provider needs. By providing a comprehensive runtime solution, the qBraid-SDK offers significant advantages to both hardware and software providers:

  • Reduces Overhead: Minimizes the effort required to develop client-side applications for securely submitting and managing quantum experiments remotely.
  • Enhances Integration: Facilitates seamless integration and interoperability of quantum software tools across all layers of the stack.
  • Broad Compatibility: Supports a diverse range of API complexities, catering to both established players like IBM and AWS as well as emerging providers.

Runtime Diagram

Installation & Setup

qbraid-sdk-env

For the best experience, install the qBraid-SDK environment on lab.qbraid.com. Login (or create an account) and follow the steps to install an environment.

Using the SDK on qBraid Lab means direct, pre-configured access to QPUs from IonQ, Oxford Quantum Circuits, QuEra, and Rigetti, as well as on-demand simulators from AWS, all with no additional access keys or API tokens required. See qBraid Quantum Jobs for more.

Local install

The qBraid-SDK, and all of its dependencies, can also be installed using pip:

pip install qbraid

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

git clone https://github.com/qBraid/qBraid.git
cd qBraid
pip install .

Note: The qBraid-SDK requires Python 3.9 or greater.

If using locally, follow linked instructions to configure your qBraid, AWS, IBM, and/or IonQ credentials.

Check version

You can view the version of the qBraid-SDK you have installed within Python using the following:

In [1]: import qbraid

In [2]: qbraid.__version__

Documentation & Tutorials

qBraid documentation is available at docs.qbraid.com.

See also:

Quickstart

Transpiler

Construct a quantum program of any supported program type.

Below, QPROGRAM_REGISTRY maps shorthand identifiers for supported quantum programs, each corresponding to a type in the typed QPROGRAM Union. For example, 'qiskit' maps to qiskit.QuantumCircuit in QPROGRAM. Notably, 'qasm2' and 'qasm3' both represent raw OpenQASM strings. This arrangement simplifies targeting and transpiling between different quantum programming frameworks.

>>> from qbraid.programs import QPROGRAM_REGISTRY
>>> QPROGRAM_REGISTRY
{'cirq': cirq.circuits.circuit.Circuit,
 'qiskit': qiskit.circuit.quantumcircuit.QuantumCircuit,
 'pyquil': pyquil.quil.Program,
 'pytket': pytket._tket.circuit.Circuit,
 'braket': braket.circuits.circuit.Circuit,
 'openqasm3': openqasm3.ast.Program,
 'qasm2': str,
 'qasm3': str}

Pass any registered quantum program along with a target package from QPROGRAM_REGISTRY to "transpile" your circuit to a new program type:

>>> from qbraid.interface import random_circuit
>>> from qbraid.transpiler import transpile
>>> qiskit_circuit = random_circuit("qiskit")
>>> cirq_circuit = transpile(qiskit_circuit, "cirq")
>>> print(qiskit_circuit)
          ┌────────────┐
q_0: ──■──┤ Rx(3.0353) ├
     ┌─┴─┐└───┬────┬───┘
q_1: ┤ H ├────┤ √X ├────
     └───┘    └────┘
>>> print(cirq_circuit)
0: ───@───Rx(0.966π)───
      │
1: ───H───X^0.5────────

Behind the scenes, the qBraid-SDK uses rustworkx to create a directional graph that maps all possible conversions between supported program types:

from qbraid.transpiler import ConversionGraph
from qbraid.visualization import plot_conversion_graph

graph = ConversionGraph()

graph.plot()

conversion_graph

You can use the native conversions supported by qBraid, or define your own custom nodes and/or edges. For example:

from qbraid.transpiler import Conversion

example_func = lambda x: x # replace with your custom conversion function
conversion = Conversion("qasm3", "stim", example_func)

graph.add_conversion(conversion)

graph.plot(seed=42) # using a seed is helpful to ensure reproducibility

QbraidProvider

Run experiements using on-demand simulators provided by qBraid using the qbraid.runtime.QbraidProvider. You can get a Python list of device objects using:

from qbraid.runtime import QbraidProvider

provider = QbraidProvider()
qdevices = provider.get_devices()

Or, instantiate a known device by ID via the QbraidProvider.get_device() method, and submit quantum jobs from any supported program type:

device = provider.get_device("qbraid_qir_simulator")
jobs = device.run([qiskit_circuit, braket_circuit, cirq_circuit, qasm3_str], shots=1000)
results = [job.result() for job in jobs]

print(results[0].measurement_counts())
# {'00': 483, '01': 14, '10': 486, '11': 17}

Local account setup

api_key

To use the qBraid-SDK locally (outside of qBraid Lab), you must add your account credentials:

  1. Create a qBraid account or log in to your existing account by visiting account.qbraid.com
  2. Copy your API Key token from the left side of your account page:

Save account to disk

Once you have your API key from step 2 by, you can save it locally in a configuration file ~/.qbraid/qbraidrc, where ~ corresponds to your home ($HOME) directory:

⚠️ Account credentials are saved in plain text, so only do so if you are using a trusted device.
from qbraid.runtime import QbraidProvider

provider = QbraidProvider(api_key='API_KEY')
provider.save_config()

Once the account is saved on disk, you can instantiate the QbraidProvider without any arguments.

Load account from environment variables

Alternatively, the qBraid-SDK can discover credentials from environment variables:

export QBRAID_API_KEY='QBRAID_API_KEY'

Launch on qBraid

The "Launch on qBraid" button (below) can be added to any public GitHub repository. Clicking on it automaically opens qBraid Lab, and performs a git clone of the project repo into your account's home directory. Copy the code below, and replace YOUR-USERNAME and YOUR-REPOSITORY with your GitHub info.

Use the badge in your project's README.md:

[<img src="https://qbraid-static.s3.amazonaws.com/logos/Launch_on_qBraid_white.png" width="150">](https://account.qbraid.com?gitHubUrl=https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git)

Use the badge in your project's README.rst:

.. image:: https://qbraid-static.s3.amazonaws.com/logos/Launch_on_qBraid_white.png
    :target: https://account.qbraid.com?gitHubUrl=https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git
    :width: 150px

Contributing

License

GNU General Public License v3.0

qbraid-qir's People

Contributors

dependabot[bot] avatar olgok avatar priyansh-1902 avatar rjain37 avatar ryanhill1 avatar skushnir123 avatar thegupta2012 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

gmh5225 olgok

qbraid-qir's Issues

Investigate QIR for resource estimation

Feature Description

It was recently brought up that QIR can be used as an input to Microsoft Azure's resource estimation tools. It seems like the current implementation of qbraid-qir does not do a good job of translating cirq into QIR in a way that preserves the resources involved in a quantum algorithm. It should be investigated whether this is something we care about and to what degree users want to do resource estimation from a QIR format.

Proposed Implementation

No response

qasm3_to_qir support for subroutines

Add support for converting OpenQASM 3 program which contain subroutines to QIR.

elif isinstance(statement, SubroutineDefinition):
raise NotImplementedError("OpenQASM 3 subroutines not yet supported")

Placeholder test cases: test_subroutines.py

e.g.

OPENQASM 3.0;
include "stdgates.inc";

def apply_h_and_measure(qubit q) -> bit {
    bit result;
    h q;
    measure q -> result;
    return result;
}

qreg q[1];
creg c[1];

c[0] = apply_h_and_measure(q[0]);

openqasm reference for implementing subroutines

Value : $150

Exception handling

Move exception handling to inside of visitor for unsupported operations used try except around convert to callable

Build pyqir from source in qir-runner test container

Right now, we can not pip install qbraid-qir into the test qir-runner Dockerfile because of this weird bug: qir-alliance/pyqir#267

As an initial workaround, we attempted to create a script get-wheel.sh that downloaded the latest pyqir wheel files directly from github, however, there have been some difficulties with this as well, including trying to make it work programmatically in an OS-agnostic way.

The best solution until the the above linked issue is resolved it to add code to build pyqir from source within the Dockerfile. Instructions on how to do that can be found here: https://www.qir-alliance.org/pyqir/building.html

After adding the steps to build and install pyqir from source, we would like to install qbraid-qir into the container so that we can use it seamlessly along with qir-runner.

`qir-runner` simulation examples

Put together one or two Cirq example implementation of Grover's, QPE, or some other small programs that have some type of physical significance, pass them through the QIR converter, simulate using the qir-runner package (available through the test-containers), and determine if the results are consistent with what we would expect. Add some LaTeX/markdown providing some context for the example so that's it's not just raw code. Then we add the notebooks to a new examples folder demonstrating how the package can be used.

Investigating useful applications

Now that we've implemented and rolled out a functional Cirq $\rightarrow$ QIR converter, the next step is to demonstrate the project's utility i.e. justify the work we've done with a compelling use-case or application.

There's multiple directions we can take this including but not limited to:

  • Resource estimation (#45)
  • Running experiments on hardware and/or hybrid simulations (#28)
  • Writing a developer's guide that provides a roadmap for building a "high-level quantum package" $\rightarrow$ QIR converter
  • Benchmarking compilation times: https://arxiv.org/pdf/2101.11365.pdf

visitor + elements modules

Implement BasicQisVisitor class. In the visit_operation() method, instead of using conditionals to map string gate names to functions, import a dictionary which defines those mappings from opsets.py. See #16

Writing the BasicQisVisitorclass will, by extension, also involve modifying to the _CircuitElement and CirqModule constructs defined in elements.py.

convert + preprocess cirq circuit

The cirq_to_qir() top-level function is the entry-point into the QIR conversion module(s). Before passing the input Cirq circuit to CirqModule.from_circuit(), we will want to pass it through a pre-processing function that ensures that the circuit is composed only of supported gates and operations. According to supported gate set defined in #16, perform gate decomposition. Ensure that input/output circuit.unitary() are equivalent.

In the future, we will expand this circuit pre-processing function to also account for edge cases like converting Cirq Moments to barriers. Depending on what makes the most sense, some or all of this "pre-processing" logic might be more efficient if defined directly within the CirqModule.from_circuit() method.

qasm3_to_qir support for gate modifiers

Feature Description

openqasm3 supports the 4gate modifiers -

  1. inv @ U : replaces the gate $\mathbf{U}$ with $\mathbf{U^{\dagger}}$.
  2. ctrl @ U and negctrl @ U : replaces $\mathbf{U}$ with the controlled and inverted controlled versions of the unitary respectively
  3. pow(k) @ U : replaces $\mathbf{U}$ with $\mathbf{U^{k}}$

Implementation (Optional)

The easiest implementation path would be to make a _handle_modifier method.

  1. Since pow only adds copies of the gate, it can be delegated to the gate call handling method.
  2. Handling inv will depend on whether we have a custom gate definition or a native gate. If a custom gate is called, we would first invert the gate body and recursively apply the inversion function. If a basic gate is encountered(as defined in pyqir._native), apply its inverted equivalent.
  3. ctrl would be tricky as we need to check if pyqir even supports custom control over qubits. If yes, the straightforward way to implement this would be a recursive implementation - for each gate in the gate body, call the ctrl handling method. If a basic gate is encountered, directly apply the control.

Use openqasm gate modifier reference for any clarifications.

Please confirm the following:

  • I have searched the existing issues and confirm this is a new feature request.

Add support for classical variables in qasm3_to_qir converter

Feature Description

openqasm supports types like int, float, bool, etc as its classical types. Currently, the declaration of variables or their usage is not supported by the converter. Users should be able to define and user variables and arrays of different types while writing openqasm programs.

Implementation (Optional)

  1. Since there can be single variable declarations and arrays, start with single variables first.
  2. Handling variable definitions across scopes would be required. Can refer to how openqasm handles this by using a stack of scopes
  3. Post this, array declarations should be developed

openqasm reference for classical declarations

Please confirm the following:

  • I have searched the existing issues and confirm this is a new feature request.

Support `Identifier` in expression evaluation in the `qasm3` converter

Feature Description

  • Currently, the qasm3 visitor only supports static expression evaluation. Eg. -
# 1 + 3*8 -> Evaluated correctly 
# 1 + a*5 -> Exception thrown
  • Since Identifiers are generally present in the openqasm expressions, we look to extend this functionality

Implementation (Optional)

  • This requires an evaluation function that replaces the Identifier values according to the "current scope". A modification of the existing implementation of _evaluate_expression in qasm3 visitor could be a good starting point
  • A scope definition is required as many identifiers tend to have values only defined in a particular scope. Eg -
gate custom(a) p {
    rx(a / 2) p;
}
qubit q;
custom(0.1) q;
  • In the above example, the "scope" must be something like - { "a" : 0.1, ...} and thus replace the value of a correctly while the expression a/2 is being evaluated.
  • Note that this is not a single-level evaluation. The scope may change and be passed up to evaluate other expressions. Eg -
gate custom1(b) q{
    rx(pi * b) q;
}
gate custom2(a) p {
    custom1(a / 2) p;
}
qubit q;
custom(0.1) q;

openqasm reference for extending expressions

Support for aliases for openqasm3 to qir

In OpenQASM 3 the let keyword allows declared quantum bits and registers to be referred to by another name as long as the alias is in scope:

qubit[5] q;
// myreg[0] refers to the qubit q[1]
let myreg = q[1:4];

See https://openqasm.com/language/types.html#aliasing

Add support for converting OpenQASM 3 programs that use aliasing to QIR.

elif isinstance(statement, AliasStatement):
raise NotImplementedError("OpenQASM 3 aliases not yet supported")

Placeholder test-cases in test_alias.py

Value : $75

Improve code coverage

We would like to bring our codecov from ~93% to as close to 100% as we can. Right now, there are only a total of 20 missed lines.

The coverage report from the latest main branch is also available here: https://app.codecov.io/gh/qBraid/qbraid-qir/

If there are lines that shouldn't be tested (e.g. "pass" statements), you can add those to the "exclude_lines" list in the tool.coverage.report section in pyproject.toml.

To generate the coverage report locally, run

pytest tests --cov=qbraid_qir --cov-report=html --cov-report=term

Then, to view the specific missed lines, you can open the report in a browser window (On OS X) with

open htmlcov/index.html

For example:

codecov.mov

Improve Code Coverage for `qir-qasm3` module

Feature Description

  • Currently, the code coverage stands at somewhere around 85% for the qasm3-qir module.
  • The goal of this issue is to make it > 95%, and ideally 100%

Implementation (Optional)

  • Parse missing lines in the coverage report and add tests to cover the same.

Please confirm the following:

  • I have searched the existing issues and confirm this is a new feature request.

build out test suite

start writing passing tests for partial and full converted qir program outputs

Support loop statements in `qasm3` converter

Feature Description

  • Openqasm3 supports looping statements as described in their language specification
  • Looping support will allow users to pass in more general programs to the qasm3 converter and generate equivalent qir representation

Implementation (Optional)

  • Firstly we will need to introduce scope in the converter
  • Post this, a loop can be unrolled concerning its scope
  • This may either be done as a pre-processing step OR in conjunction with the qir conversion
  • A good starting point would be to analyze the ast representation of loops in openqasm

Value : $150

Add support for `switch` statements in qasm3_to_qir converter

Feature Description

  • openqasm 3 also supports switch statements which allow users to condition statement execution based on integral variables.

Implementation (Optional)

  • The pyqir._native module does have a definition of the Switch construct but it is not entirely clear how that can be incorporated into the converter. A good starting point would be the pyqir._native definition and the openqasm switch reference

  • It would be good to have a handler for the switch, like the _visit_branching_statement. Since switch is also a type of branching instruction, we can either expand this method or create a new handler.

Circuit preprocessing / decompositions

Follow-up to #17

  • test cirq to line qubits function and make sure that operations aren't being manipulated in unexpected ways
  • implement any necessary gate decompositions against our "supported" gate set.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.