Skip to content

Commit 83ca5a9

Browse files
committed
Add base representation of SparseObservable
This adds the base representation of `SparseObservable`, including the simple constructors from Python space and the ability to view the data buffers. This commit does not include the mathematical manipulations of the operators, nor some of the helper methods that will be used to manipulate the operators in the context of primitives execution. These will follow in subsequent patches. The design and implementation notes of `SparseObservable` are described in a Qiskit RFC that preceeded this patch series[^1], and it's best to consult that document for full details on the operator considerations. [^1]: https://github.com/Qiskit/RFCs/blob/7a74b08793475b7b0142d3a3f7142cabcfd33ab8/0021-sparse-observable.md
1 parent 54139be commit 83ca5a9

File tree

10 files changed

+2642
-1
lines changed

10 files changed

+2642
-1
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/accelerate/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ qiskit-circuit.workspace = true
2626
thiserror.workspace = true
2727
ndarray_einsum_beta = "0.7"
2828
once_cell = "1.20.1"
29+
bytemuck.workspace = true
2930

3031
[dependencies.smallvec]
3132
workspace = true
@@ -60,4 +61,4 @@ version = "0.18.22"
6061
features = ["macro"]
6162

6263
[features]
63-
cache_pygates = ["qiskit-circuit/cache_pygates"]
64+
cache_pygates = ["qiskit-circuit/cache_pygates"]

crates/accelerate/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub mod remove_diagonal_gates_before_measure;
3939
pub mod results;
4040
pub mod sabre;
4141
pub mod sampled_exp_val;
42+
pub mod sparse_observable;
4243
pub mod sparse_pauli_op;
4344
pub mod split_2q_unitaries;
4445
pub mod star_prerouting;

crates/accelerate/src/sparse_observable.rs

+1,674
Large diffs are not rendered by default.

crates/circuit/src/imports.rs

+2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ pub static UNITARY_GATE: ImportOnceCell = ImportOnceCell::new(
116116
"qiskit.circuit.library.generalized_gates.unitary",
117117
"UnitaryGate",
118118
);
119+
pub static NUMPY_COPY_ONLY_IF_NEEDED: ImportOnceCell =
120+
ImportOnceCell::new("qiskit._numpy_compat", "COPY_ONLY_IF_NEEDED");
119121

120122
/// A mapping from the enum variant in crate::operations::StandardGate to the python
121123
/// module path and class name to import it. This is used to populate the conversion table

crates/pyext/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ fn _accelerate(m: &Bound<PyModule>) -> PyResult<()> {
5252
add_submodule(m, ::qiskit_accelerate::results::results, "results")?;
5353
add_submodule(m, ::qiskit_accelerate::sabre::sabre, "sabre")?;
5454
add_submodule(m, ::qiskit_accelerate::sampled_exp_val::sampled_exp_val, "sampled_exp_val")?;
55+
add_submodule(m, ::qiskit_accelerate::sparse_observable::sparse_observable, "sparse_observable")?;
5556
add_submodule(m, ::qiskit_accelerate::sparse_pauli_op::sparse_pauli_op, "sparse_pauli_op")?;
5657
add_submodule(m, ::qiskit_accelerate::split_2q_unitaries::split_2q_unitaries_mod, "split_2q_unitaries")?;
5758
add_submodule(m, ::qiskit_accelerate::star_prerouting::star_prerouting, "star_prerouting")?;

qiskit/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
sys.modules["qiskit._accelerate.results"] = _accelerate.results
7878
sys.modules["qiskit._accelerate.sabre"] = _accelerate.sabre
7979
sys.modules["qiskit._accelerate.sampled_exp_val"] = _accelerate.sampled_exp_val
80+
sys.modules["qiskit._accelerate.sparse_observable"] = _accelerate.sparse_observable
8081
sys.modules["qiskit._accelerate.sparse_pauli_op"] = _accelerate.sparse_pauli_op
8182
sys.modules["qiskit._accelerate.star_prerouting"] = _accelerate.star_prerouting
8283
sys.modules["qiskit._accelerate.stochastic_swap"] = _accelerate.stochastic_swap

qiskit/quantum_info/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
Pauli
2929
Clifford
3030
ScalarOp
31+
SparseObservable
3132
SparsePauliOp
3233
CNOTDihedral
3334
PauliList
@@ -113,6 +114,9 @@
113114
"""
114115

115116
from __future__ import annotations
117+
118+
from qiskit._accelerate.sparse_observable import SparseObservable
119+
116120
from .analysis import hellinger_distance, hellinger_fidelity, Z2Symmetries
117121
from .operators import (
118122
Clifford,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
features_quantum_info:
3+
- |
4+
A new observable class has been added. :class:`.SparseObservable` represents observables as a
5+
sum of terms, similar to :class:`.SparsePauliOp`, but with two core differences:
6+
7+
1. Each complete term is stored as (effectively) a series of ``(qubit, bit_term)`` pairs,
8+
without storing qubits that undergo the identity for that term. This significantly improves
9+
the memory usage of observables such as the weighted sum of Paulis :math:`\sum_i c_i Z_i`.
10+
11+
2. The single-qubit term alphabet is overcomplete for the operator space; it can represent Pauli
12+
operators (like :class:`.SparsePauliOp`), but also projectors onto the eigenstates of the
13+
Pauli operators, like :math:`\lvert 0\rangle\langle 0\rangle`. Such projectors can be
14+
measured on hardware equally as efficiently as their corresponding Pauli operator, but
15+
:class:`.SparsePauliOp` would require an exponential number of terms to represent
16+
:math:`{\lvert0\rangle\langle0\rvert}^{\otimes n}` over :math:`n` qubits, while
17+
:class:`.SparseObservable` needs only a single term.
18+
19+
You can construct and manipulate :class:`.SparseObservable` using an interface familiar to users
20+
of :class:`.SparsePauliOp`::
21+
22+
from qiskit.quantum_info import SparseObservable
23+
24+
obs = SparseObservable.from_sparse_list([
25+
("XZY", (2, 1, 0), 1.5j),
26+
("+-", (100, 99), 0.5j),
27+
("01", (50, 49), 0.5),
28+
])
29+
30+
:class:`.SparseObservable` is not currently supported as an input format to the primitives
31+
(:mod:`qiskit.primitives`), but we expect to expand these interfaces to include them in the
32+
future.

0 commit comments

Comments
 (0)