Skip to content

Commit

Permalink
Add base representation of SparseObservable
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jakelishman committed Oct 1, 2024
1 parent 54139be commit 83ca5a9
Show file tree
Hide file tree
Showing 10 changed files with 2,642 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/accelerate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ qiskit-circuit.workspace = true
thiserror.workspace = true
ndarray_einsum_beta = "0.7"
once_cell = "1.20.1"
bytemuck.workspace = true

[dependencies.smallvec]
workspace = true
Expand Down Expand Up @@ -60,4 +61,4 @@ version = "0.18.22"
features = ["macro"]

[features]
cache_pygates = ["qiskit-circuit/cache_pygates"]
cache_pygates = ["qiskit-circuit/cache_pygates"]
1 change: 1 addition & 0 deletions crates/accelerate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub mod remove_diagonal_gates_before_measure;
pub mod results;
pub mod sabre;
pub mod sampled_exp_val;
pub mod sparse_observable;
pub mod sparse_pauli_op;
pub mod split_2q_unitaries;
pub mod star_prerouting;
Expand Down
1,674 changes: 1,674 additions & 0 deletions crates/accelerate/src/sparse_observable.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions crates/circuit/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ pub static UNITARY_GATE: ImportOnceCell = ImportOnceCell::new(
"qiskit.circuit.library.generalized_gates.unitary",
"UnitaryGate",
);
pub static NUMPY_COPY_ONLY_IF_NEEDED: ImportOnceCell =
ImportOnceCell::new("qiskit._numpy_compat", "COPY_ONLY_IF_NEEDED");

/// A mapping from the enum variant in crate::operations::StandardGate to the python
/// module path and class name to import it. This is used to populate the conversion table
Expand Down
1 change: 1 addition & 0 deletions crates/pyext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ fn _accelerate(m: &Bound<PyModule>) -> PyResult<()> {
add_submodule(m, ::qiskit_accelerate::results::results, "results")?;
add_submodule(m, ::qiskit_accelerate::sabre::sabre, "sabre")?;
add_submodule(m, ::qiskit_accelerate::sampled_exp_val::sampled_exp_val, "sampled_exp_val")?;
add_submodule(m, ::qiskit_accelerate::sparse_observable::sparse_observable, "sparse_observable")?;
add_submodule(m, ::qiskit_accelerate::sparse_pauli_op::sparse_pauli_op, "sparse_pauli_op")?;
add_submodule(m, ::qiskit_accelerate::split_2q_unitaries::split_2q_unitaries_mod, "split_2q_unitaries")?;
add_submodule(m, ::qiskit_accelerate::star_prerouting::star_prerouting, "star_prerouting")?;
Expand Down
1 change: 1 addition & 0 deletions qiskit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
sys.modules["qiskit._accelerate.results"] = _accelerate.results
sys.modules["qiskit._accelerate.sabre"] = _accelerate.sabre
sys.modules["qiskit._accelerate.sampled_exp_val"] = _accelerate.sampled_exp_val
sys.modules["qiskit._accelerate.sparse_observable"] = _accelerate.sparse_observable
sys.modules["qiskit._accelerate.sparse_pauli_op"] = _accelerate.sparse_pauli_op
sys.modules["qiskit._accelerate.star_prerouting"] = _accelerate.star_prerouting
sys.modules["qiskit._accelerate.stochastic_swap"] = _accelerate.stochastic_swap
Expand Down
4 changes: 4 additions & 0 deletions qiskit/quantum_info/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
Pauli
Clifford
ScalarOp
SparseObservable
SparsePauliOp
CNOTDihedral
PauliList
Expand Down Expand Up @@ -113,6 +114,9 @@
"""

from __future__ import annotations

from qiskit._accelerate.sparse_observable import SparseObservable

from .analysis import hellinger_distance, hellinger_fidelity, Z2Symmetries
from .operators import (
Clifford,
Expand Down
32 changes: 32 additions & 0 deletions releasenotes/notes/sparse-observable-7de70dcdf6962a64.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
features_quantum_info:
- |
A new observable class has been added. :class:`.SparseObservable` represents observables as a
sum of terms, similar to :class:`.SparsePauliOp`, but with two core differences:
1. Each complete term is stored as (effectively) a series of ``(qubit, bit_term)`` pairs,
without storing qubits that undergo the identity for that term. This significantly improves
the memory usage of observables such as the weighted sum of Paulis :math:`\sum_i c_i Z_i`.
2. The single-qubit term alphabet is overcomplete for the operator space; it can represent Pauli
operators (like :class:`.SparsePauliOp`), but also projectors onto the eigenstates of the
Pauli operators, like :math:`\lvert 0\rangle\langle 0\rangle`. Such projectors can be
measured on hardware equally as efficiently as their corresponding Pauli operator, but
:class:`.SparsePauliOp` would require an exponential number of terms to represent
:math:`{\lvert0\rangle\langle0\rvert}^{\otimes n}` over :math:`n` qubits, while
:class:`.SparseObservable` needs only a single term.
You can construct and manipulate :class:`.SparseObservable` using an interface familiar to users
of :class:`.SparsePauliOp`::
from qiskit.quantum_info import SparseObservable
obs = SparseObservable.from_sparse_list([
("XZY", (2, 1, 0), 1.5j),
("+-", (100, 99), 0.5j),
("01", (50, 49), 0.5),
])
:class:`.SparseObservable` is not currently supported as an input format to the primitives
(:mod:`qiskit.primitives`), but we expect to expand these interfaces to include them in the
future.
Loading

0 comments on commit 83ca5a9

Please sign in to comment.