Today, we’re excited to announce the release of Qiskit SDK v2.0! Our second major version release introduces significant performance improvements over its predecessor, and lays the groundwork for powerful new tools and capabilities that we plan to share in the coming months.
We spent all of 2024 working to make Qiskit into the most performant quantum SDK in the world, with each release in our v1.x series bringing substantial new efficiencies, speedups, and features. Now, as we transition into the v2.x cycle, we’re maintaining our commitment to delivering industry-leading performance at scale, but we’re also placing a greater emphasis on projects aimed at cultivating greater community support for libraries that interface with Qiskit.
Every day, more and more researchers are using the IBM fleet of utility-scale quantum computers to explore problems at the very limits of classical computation, and it is becoming clear that quantum advantage may well be just around the corner. However, to cross that finish line, we must now begin facilitating greater collaboration between the quantum community and the classical high-performance computing (HPC) and applications research communities. With Qiskit SDK v2.0, that work begins in earnest.
A refresher on the Qiskit release lifecycle
Qiskit SDK v2.0 introduces some exciting new features, which we’ll detail below. However, as much as v2.0 is about ringing in the new, it is perhaps even more so focused on clearing out the old.
As a refresher on our versioning strategy: Last year, alongside the rollout of its first major version, the Qiskit SDK also transitioned to the Semantic Versioning design scheme. In this scheme, releases are categorized as major, minor, and patch versions in the format <major>.<minor>.<patch>
, and changes to the API that are incompatible with previous versions are made in major version releases. As part of this transition, we also committed to 18-month support cycles. For Qiskit, this means that (1) a major version is released no more than once per year, and (2) major versions are the only releases that contain breaking changes, but (3) the Qiskit team will continue to support each major version for an additional six months after the release of its successor.
In other words, Qiskit SDK v2.0 will be the first release since Qiskit SDK v1.0 to contain breaking changes that create disruptive incompatibilities with previous releases. However, the Qiskit team will continue providing support for Qiskit SDK v1.4 for the next six months—i.e., until late September—so you have plenty of time to transition. Regardless of when you plan on making the move to Qiskit SDK v2.0, there’s still plenty to look forward to, and even the most modest features introduced in v2.0 reveal a great deal about the much bigger changes coming to the Qiskit SDK over the long term.
Read on for a summary of key highlights, and as always, you can see the full release notes in our documentation here and follow our migration guide here.
The TL;DR
The biggest updates we’re going to cover in this article include the following:
- A brand new C API: We are kicking off this major release by introducing a C-language API to interact with the
SparseObservable
class. This new functionality is just the first step toward building a robust C interface for the Qiskit SDK, and you can expect major expansions of the new C interface as we progress through the rest of the v2.x series. We believe this work will play an important role in supporting large-scale quantum experimentation and enabling the hunt for quantum advantage. - Removal of deprecated features: Many of the minor releases in the previous v1.x series included new deprecation warnings to make room for us to continue improving the SDK. This major release is where all of the deprecated classes, functions, and modules are now being removed.
- Continued performance improvements: We have continued work on porting more and more of the functionality of the Qiskit SDK over to Rust, resulting in a 2x speedup for circuit construction benchmarking tasks and a roughly 20% speedup for transpilation benchmarking tasks.
- Introducing boxes and stretches: Qiskit SDK v2.0 introduces helpful new features for structuring your circuits in preparation for future changes to dynamic circuits on IBM QPUs.
Top New Features & Improvements
In this section we’ll cover some of the most important new features and enhancements included in this release. If you want to know more about these or other features that didn’t make it into this article, you can see the full list of new features here.
Introducing the Qiskit SDK’s C API
We have introduced a C-language API to build and interact with the SparseObservable
class, and we’ll be expanding on this functionality significantly as we progress through the v2.x releases. This is a major step in the evolution of the Qiskit SDK.
Last fall, at the Supercomputing 2024 conference in Atlanta, we shared our prediction that quantum advantage will arrive within the next two years, but only if the quantum and HPC communities work together. We believe a C-language API is an important step towards furthering collaborations between Qiskit and classical HPC researchers.
C is a foundational programming language that powers much of our digital infrastructure, including in classical HPC. It has a long, rich history with a very mature ecosystem of libraries and tools, meaning that a C-language API gives us the ability to extend Qiskit in new ways that would have been difficult or impossible in the past. This makes the Qiskit SDK much more flexible and versatile than ever before. C is also a natural choice because we’ve refactored so much of Qiskit’s internals in the high-performance programming language Rust, which offers native support for defining C APIs.
You’ll find detailed syntax and other useful information about this new feature under the new C API docs, but let’s take a look at a quick example showing how to construct the 100-qubit observable :
For now, the surface of this new C-language API is fairly small. However, it lays an important foundation upon which we’ll be able to further develop Qiskit’s C interface in the near future. Stay tuned for many more important updates coming later this year with the rollout of Qiskit SDK v2.1.
Continuing to port functionality to Rust
A major priority throughout the Qiskit SDK v1.x release cycle was internal refactoring that introduced the high-performance programming language Rust under the hood. This transition has driven much of the performance improvements we’ve seen since the launch of v1.0, and that work continues as we move into the v2.0 era. A few key highlights of the v2.0 release include:
- Ported the representation of
Qubit
,ClBit
,QuantumRegister
, andClassicalRegister
classes to Rust. Each of these is used for sharing context about bits between circuits. This work plays a key role in enabling us to start building a C API in Rust, as the lack of Rust implementation for these classes was one of the biggest blockers preventing the construction of aQuantumCircuit
object in the C API. - Ported the representation of standard non-unitary circuit operations (
Measure
,Reset
,Barrier
,Delay
) akaStandardInstruction
(s) to Rust. - Ported
UnitaryGate
class to Rust. - Partially ported the
HighLevelSynthesis
pass to Rust. A significant portion of this pass still relies on Python because its job is to synthesize abstract circuit objects that are often defined in Python. This was typically the slowest pass in the preset pass managers in v1.4.x and v1.3.x, so moving it to Rust will eliminate that as a bottleneck.
A key aspect for much of the porting described above, and for larger removals described later in this blog (e.g. removal of the c_if/condition
, removal of Qiskit Pulse, standardization on using the Target
internally in the preset pass managers, removal of BackendV1
, etc.) is about building a pure Rust implementation of the core data model that allows you to create and interact without using any Python. This is a prerequisite for enabling the full functionality of a C-language API, since Python isn’t available in a standalone C mode.
Preliminary performance metrics for v2.0 indicate a 2x speedup in circuit construction obtained from moving the Bit
and Register
classes to Rust, and also from removing Python use in code paths where it was previously required in existing Rust circuit generation functions like quantum_volume()
, which now uses UnitaryGate
in Rust instead of Python. In the plot below, which tracks changes in runtime for quantum_volume(100, 50)
for each GitHub commit, the red line demarcates the speedup obtained from the commit that moved the UnitaryGate
usage in that function to Rust.
Time to build a quantum volume circuit with 100 qubits and 50 layers. Each point on the X-axis corresponds to a GitHub commit, while the Y-axis represents runtime in microseconds. The red line coincides with the merging of PR #13765, which switched the quantum_volume (https://ibm.biz/BdnFVh) circuit generation function to use the Rust UnitaryGate internally rather than the Python implementation.
Qiskit SDK v2.0 demonstrates an on average 20% speedup in Benchpress transpilation tests compared to Qiskit v1.3, with further improvements expected in future minor releases. Benchmarks that include the OpenQASM 2 classically conditioned gates, such as benchmarks from benchpress/qasm/qasmbench-*
and benchpress/qasm/feynman
have experienced a change in behavior. The OpenQASM conditional was loaded as c_if()
, which was ignored during transpilation in the v1.x release series. In Qiskit v2.0, conditional gates are loaded as IfElseOp
objects, enabling further optimizations but at a higher runtime cost. This results in a noticeable performance regression in 11% of Benchpress tests. However, when excluding these cases, the remaining tests show an average 1.3x speed improvement over v1.3, with one test even demonstrating a 17x increase.
Each point in this figure represents a transpilation benchmark from Benchpress, comparing the time required to transpile a circuit using Qiskit v1.3 and Qiskit v2.0. A point on the central diagonal line indicates equal transpilation times for both versions. Points above the diagonal signify improvements, while points below indicate cases where transpilation was slower in v2.0 compared to v1.3.
Adding stretch
variables for Delay
instructions
You can now create stretch
durations for Delay
instructions to better express timing relationships between instructions. The new stretch
object extends the existing classical expression system to enable the creation of stretch
variables, making it easier to capture timing design intent at the time of circuit construction and have it resolved during circuit compilation.
Certain error suppression methods, like dynamical decoupling, rely upon control over the timing of gates inserted into otherwise idle periods in a circuit. However, dynamic circuits contain timing constraints that are typically opaque to the developer. For example, an ‘if’ block that depends on the outcome of a measurement cannot execute until that value has propagated through the control system. Since the time this takes is not related to the duration of a gate or instruction, it is invisible to the Qiskit SDK—and to the developer.
OpenQASM 3 introduced the concept of “stretch” to allow the expression of timing relationships even in the presence of these unknown times, where final resolution of exact timing is deferred to a lower level of the execution stack. The stretch structure acts like a spring, expanding to fill the available space. This Qiskit SDK release transfers this concept from OpenQASM into Qiskit.
To create a stretch
variable, you can use QuantumCircuit.add_stretch
. The resulting expression is a constant expression of type Duration
, which can be used as the duration
argument of a QuantumCircuit.delay
. So, for example, to create a typical XX dynamical decoupling sequence on qubit 1 while measuring qubit 0, you can write the following:
IBM’s Qiskit Runtime service does not currently accept circuits containing stretch
es, but a forthcoming update to the dynamic circuits capability will add stretch
to the IBM Quantum ISA. For additional context and examples, take a look at the OpenQASM 3 language specifications here.
Introducing boxes
To provide you with more flexibility and transparency for tasks like Pauli twirling and error mitigation, we’re pleased to introduce the new box
instruction. With box
, you can now more easily group instructions in the Qiskit SDK for later processing and custom scheduling. Instructions can be grouped with downstream data attached, passed through transpilation, and transmitted up and down the execution stack.
Prior to the v2.0 release, the Qiskit SDK did not give you the ability to group instructions as anything other than a user-defined custom gate. However, there are many compilation tasks for which it can be useful to group certain instructions in other ways. For example, a block of several gates might have a known unitary action such that you can treat it as atomic for commutation purposes—even if a candidate gate doesn’t commute with each block element individually, or you might apply noise-learning techniques to simultaneous logical blocks of operations, rather than individual two-qubit hardware gates.
In many cases, Qiskitters have been able to get around this limitation by making ad-hoc blocks using labelled Barrier
instructions, but this optimization barrier has effects beyond simple grouping, and a Barrier
can be hard to interpret when you’re inspecting circuits after compilation. Taking inspiration from the semantics of the box
concept from OpenQASM 3, the new box
instruction is able to pass through the compiler—albeit with some limitations—is QPY serializable, and can be transmitted up and down the execution stacks.
Near-term use cases for the box
instruction include building grouping constructions to simplify stretch-based scheduling in the Qiskit SDK, specifying noise-learning and twirling blocks for error mitigation in Qiskit Runtime primitives, and getting better insight into how primitives divide your circuits into blocks for noise learning and twirling. In future releases, we plan to also introduce box
annotations, so that you can apply compiler directives and potentially other general instructions for your boxed content. Annotations will make box
instructions significantly more powerful and flexible by giving you the ability to better define how the scope of a box
’s body will be compiled.
Breaking Changes
Because this is a major release, all of the deprecations we’ve announced since the release of Qiskit SDK v1.0 have now been removed in Qiskit SDK v2.0.
As we explained earlier, this is a key part of the new, more stable release cycle we first introduced last year with Qiskit SDK v1.0. As a result, you only need to adapt to breaking changes once a year, which ensures you get plenty of notice through deprecation warnings in the minor version releases. If you’d like to go over the entire list of breaking changes and learn how to modify your projects, check out the full release notes and migration guide, but we’ll go over a few of the largest changes below.
First, there are a few modules within the Qiskit SDK that have been removed entirely. These are the qiskit.pulse
, qiskit.qobj
, and qiskit.assembler
modules. We’ll explain more about how to migrate from using qiskit.pulse
below. Removal of the qobj
and assembler
modules is part of our ongoing efforts to clean up the interfaces for the transpiler, as both were tightly coupled to the REST API specification for the old IBM Quantum Experience—the predecessor of the current IBM Quantum Platform—and are essentially legacy paths that are no longer relevant today.
Along the same lines, the v2.0 release comes with the removal of the BackendV1
, ProviderV1
and all of the related models and utilities—as these were also modeled on the old IBM Quantum Experience. This means that all fake backend classes based on BackendV1
in qiskit.providers.fake_provider
and all objects in qiskit.providers.models
have been removed.
The Primitive V1 implementations and related aliases have also been removed; superseded by their V2 counterparts. It’s important to note here that it is just the Primitive V1 implementations and not the definitions which have been removed (see our documentation page on the difference for more information). This removal includes the following classes:
Estimator
, in favor of the V2 equivalent,StatevectorEstimator
Sampler
, in favor of the V2 equivalent,StatevectorSampler
BackendEstimator
, in favor of the V2 equivalent,BackendEstimatorV2
BackendSampler
, in favor of the V2 equivalent,BackendSamplerV2
BaseEstimator
, which was an alias forBaseEstimatorV1
BaseSampler
, which was an alias forBaseSamplerV1
Removing Qiskit Pulse
One of the major breaking changes to the Qiskit SDK in the new v2.0 release is the removal of the qiskit.pulse
module. This is part of our efforts to continue delivering higher-level services that support utility-scale experimentation and the search for quantum advantage, and follows the recent removal of Pulse-level control from IBM Quantum QPUs.
Qiskit Pulse provides valuable capabilities for manipulating hardware and accessing qubit data at the pulse level, but these capabilities come at a cost. The custom operations that Qiskit Pulse enables are expensive, and the size of the data model quickly grows unmanageable when you try to compile Pulse programs beyond the 100-qubit scale. These inefficiencies have been a blocker for important capabilities we’ve targeted on our hardware roadmap.
However, we’re working to ensure that you will still be able to use the Qiskit SDK to explore some of the most common use cases enabled by Qiskit Pulse. For example, users often employed pulse-level control in the direct implementation of single- and two-qubit rotations, and that capability remains in v2.0 in the form of fractional gates. Originally introduced last fall, fractional gates execute and rotations directly on hardware and can be enabled by adding the flag use_fractional_gates=True
when selecting a backend:
Selecting a backend this way will ensure that the Target
attribute of the returned backend includes fractional gates when transpiling circuits. If you’d like to read more about how to use this feature in your project, be sure to review our documentation on the subject.
We understand that pulse-level control and the qiskit.pulse
module were used for more than just direct implementations of these gates. Additional use cases include the execution of calibration experiments to fine-tune the quality of specific gates. These calibrations were mostly used for optimal control studies and we encourage you to explore tools and resources like Qiskit Dynamics, which may provide a replacement for your specific use case. You can also combine Qiskit Dynamics with external pulse packages from other hardware providers to continue exploring your pulse-level use cases on real quantum hardware.
Final notes
And there you have it! The most important details of the latest release. Remember if you want to put ideas forward for future versions of Qiskit you can always open a GitHub issue to request a feature or report a bug! And if you want to follow what's coming up in the next release checkout the 2.x roadmap and join #roadmap-announcements in the Qiskit Slack workspace.
Many people contributed to this release, special thanks to (in alphabetical order):
This blog post was written by Kaelyn Ferris with contributions from Abby Mitchell, Blake Johnson, Elena Peña Tapia, Julien Gacon, Luciano Bello, Matthew Treinish, Steffen Thoß, Tushar Mittal, and Robert Davis.