From 385527d384dd0b3fb26093d9fae7936848d9c97f Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Sun, 1 Dec 2024 23:16:07 +0900 Subject: [PATCH 1/5] Fix clippy warnings with latest rust release (#13505) The recent rust release 1.83 introduced a few new clippy warnings and tweaks to existing checks that are triggering warnings in Qiskit's source. While we run clippy in CI it is with our MSRV of 1.70 for stability to avoid periodic CI outages when a new rust reversion is released. But for those who develop locally using the latest stable version of rust these warnings can make it hard to find issues in under development code. The new clippy rules are also real issues in the code that would be good to fix even if it's not a hard requirement yet. --- crates/accelerate/src/rayon_ext.rs | 10 +++++----- crates/accelerate/src/sabre/route.rs | 2 +- crates/accelerate/src/sparse_observable.rs | 6 +++--- crates/accelerate/src/sparse_pauli_op.rs | 2 +- .../src/synthesis/multi_controlled/mcmt.rs | 16 ++++++++-------- crates/accelerate/src/target_transpiler/mod.rs | 6 +++--- .../src/target_transpiler/nullable_index_map.rs | 6 +++--- crates/circuit/src/operations.rs | 2 +- crates/circuit/src/slice.rs | 2 +- crates/qasm2/src/error.rs | 2 +- crates/qasm2/src/expr.rs | 2 +- crates/qasm3/Cargo.toml | 5 ++++- crates/qasm3/src/expr.rs | 6 +++--- 13 files changed, 35 insertions(+), 32 deletions(-) diff --git a/crates/accelerate/src/rayon_ext.rs b/crates/accelerate/src/rayon_ext.rs index af914a86d41..0bd57ab0f90 100644 --- a/crates/accelerate/src/rayon_ext.rs +++ b/crates/accelerate/src/rayon_ext.rs @@ -52,7 +52,7 @@ pub struct ParUnevenChunksMut<'len, 'data, T> { data: &'data mut [T], } -impl<'len, 'data, T: Send + 'data> ParallelIterator for ParUnevenChunksMut<'len, 'data, T> { +impl<'data, T: Send + 'data> ParallelIterator for ParUnevenChunksMut<'_, 'data, T> { type Item = &'data mut [T]; #[track_caller] @@ -61,7 +61,7 @@ impl<'len, 'data, T: Send + 'data> ParallelIterator for ParUnevenChunksMut<'len, } } -impl<'len, 'data, T: Send + 'data> IndexedParallelIterator for ParUnevenChunksMut<'len, 'data, T> { +impl<'data, T: Send + 'data> IndexedParallelIterator for ParUnevenChunksMut<'_, 'data, T> { #[track_caller] fn drive>(self, consumer: C) -> C::Result { bridge(self, consumer) @@ -132,7 +132,7 @@ impl<'len, 'data, T> UnevenChunksMutIter<'len, 'data, T> { } } -impl<'len, 'data, T> Iterator for UnevenChunksMutIter<'len, 'data, T> { +impl<'data, T> Iterator for UnevenChunksMutIter<'_, 'data, T> { type Item = &'data mut [T]; #[track_caller] @@ -154,8 +154,8 @@ impl<'len, 'data, T> Iterator for UnevenChunksMutIter<'len, 'data, T> { (self.chunk_lengths.len(), Some(self.chunk_lengths.len())) } } -impl<'len, 'data, T> ExactSizeIterator for UnevenChunksMutIter<'len, 'data, T> {} -impl<'len, 'data, T> DoubleEndedIterator for UnevenChunksMutIter<'len, 'data, T> { +impl ExactSizeIterator for UnevenChunksMutIter<'_, '_, T> {} +impl DoubleEndedIterator for UnevenChunksMutIter<'_, '_, T> { #[track_caller] fn next_back(&mut self) -> Option { if self.chunk_lengths.is_empty() { diff --git a/crates/accelerate/src/sabre/route.rs b/crates/accelerate/src/sabre/route.rs index acc3e50f735..82d83d607a6 100644 --- a/crates/accelerate/src/sabre/route.rs +++ b/crates/accelerate/src/sabre/route.rs @@ -83,7 +83,7 @@ struct RoutingState<'a, 'b> { seed: u64, } -impl<'a, 'b> RoutingState<'a, 'b> { +impl RoutingState<'_, '_> { /// Apply a swap to the program-state structures (front layer, extended set and current /// layout). #[inline] diff --git a/crates/accelerate/src/sparse_observable.rs b/crates/accelerate/src/sparse_observable.rs index 8cdc94f316f..e1d2f2689d2 100644 --- a/crates/accelerate/src/sparse_observable.rs +++ b/crates/accelerate/src/sparse_observable.rs @@ -2520,7 +2520,7 @@ pub struct SparseTermView<'a> { pub bit_terms: &'a [BitTerm], pub indices: &'a [u32], } -impl<'a> SparseTermView<'a> { +impl SparseTermView<'_> { /// Convert this `SparseTermView` into an owning [SparseTerm] of the same data. pub fn to_term(&self) -> SparseTerm { SparseTerm { @@ -2618,8 +2618,8 @@ impl<'a> Iterator for IterMut<'a> { (self.coeffs.len(), Some(self.coeffs.len())) } } -impl<'a> ExactSizeIterator for IterMut<'a> {} -impl<'a> ::std::iter::FusedIterator for IterMut<'a> {} +impl ExactSizeIterator for IterMut<'_> {} +impl ::std::iter::FusedIterator for IterMut<'_> {} /// Helper class of `ArrayView` that denotes the slot of the `SparseObservable` we're looking at. #[derive(Clone, Copy, PartialEq, Eq)] diff --git a/crates/accelerate/src/sparse_pauli_op.rs b/crates/accelerate/src/sparse_pauli_op.rs index 89f03333895..8c9ffe97e52 100644 --- a/crates/accelerate/src/sparse_pauli_op.rs +++ b/crates/accelerate/src/sparse_pauli_op.rs @@ -216,7 +216,7 @@ pub struct ZXPaulisView<'py> { coeffs: ArrayView1<'py, Complex64>, } -impl<'py> ZXPaulisView<'py> { +impl ZXPaulisView<'_> { /// The number of qubits this operator acts on. pub fn num_qubits(&self) -> usize { self.x.shape()[1] diff --git a/crates/accelerate/src/synthesis/multi_controlled/mcmt.rs b/crates/accelerate/src/synthesis/multi_controlled/mcmt.rs index 80128b077e7..42f7a72542f 100644 --- a/crates/accelerate/src/synthesis/multi_controlled/mcmt.rs +++ b/crates/accelerate/src/synthesis/multi_controlled/mcmt.rs @@ -20,6 +20,13 @@ use smallvec::{smallvec, SmallVec}; use crate::QiskitError; +type CCXChainItem = PyResult<( + PackedOperation, + SmallVec<[Param; 3]>, + Vec, + Vec, +)>; + /// A Toffoli chain, implementing a multi-control condition on all controls using /// ``controls.len() - 1`` auxiliary qubits. /// @@ -42,14 +49,7 @@ use crate::QiskitError; fn ccx_chain<'a>( controls: &'a [usize], auxiliaries: &'a [usize], -) -> impl DoubleEndedIterator< - Item = PyResult<( - PackedOperation, - SmallVec<[Param; 3]>, - Vec, - Vec, - )>, -> + 'a { +) -> impl DoubleEndedIterator + 'a { let n = controls.len() - 1; // number of chain elements std::iter::once((controls[0], controls[1], auxiliaries[0])) .chain((0..n - 1).map(|i| (controls[i + 2], auxiliaries[i], auxiliaries[i + 1]))) diff --git a/crates/accelerate/src/target_transpiler/mod.rs b/crates/accelerate/src/target_transpiler/mod.rs index 8eb9f385a67..f57facf28b7 100644 --- a/crates/accelerate/src/target_transpiler/mod.rs +++ b/crates/accelerate/src/target_transpiler/mod.rs @@ -934,10 +934,10 @@ impl Target { // TODO: Remove once `Target` is being consumed. #[allow(dead_code)] pub fn operations(&self) -> impl Iterator { - return self._gate_name_map.values().filter_map(|oper| match oper { + self._gate_name_map.values().filter_map(|oper| match oper { TargetOperation::Normal(oper) => Some(oper), _ => None, - }); + }) } /// Get the error rate of a given instruction in the target @@ -1025,7 +1025,7 @@ impl Target { } else if self.non_global_basis.is_some() { return self.non_global_basis.as_deref(); } - return Some(self.generate_non_global_op_names(strict_direction)); + Some(self.generate_non_global_op_names(strict_direction)) } /// Gets all the operation names that use these qargs. Rust native equivalent of ``BaseTarget.operation_names_for_qargs()`` diff --git a/crates/accelerate/src/target_transpiler/nullable_index_map.rs b/crates/accelerate/src/target_transpiler/nullable_index_map.rs index e6e2a0fca3a..c48386222fc 100644 --- a/crates/accelerate/src/target_transpiler/nullable_index_map.rs +++ b/crates/accelerate/src/target_transpiler/nullable_index_map.rs @@ -234,7 +234,7 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { } } -impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { +impl ExactSizeIterator for Iter<'_, K, V> { fn len(&self) -> usize { self.map.len() + self.null_value.is_some() as usize } @@ -318,7 +318,7 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { } } -impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { +impl ExactSizeIterator for Keys<'_, K, V> { fn len(&self) -> usize { self.map_keys.len() + self.null_value as usize } @@ -356,7 +356,7 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { } } -impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { +impl ExactSizeIterator for Values<'_, K, V> { fn len(&self) -> usize { self.map_values.len() + self.null_value.is_some() as usize } diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index a7b147c7e37..59adfd9e0e8 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -183,7 +183,7 @@ pub enum OperationRef<'a> { Operation(&'a PyOperation), } -impl<'a> Operation for OperationRef<'a> { +impl Operation for OperationRef<'_> { #[inline] fn name(&self) -> &str { match self { diff --git a/crates/circuit/src/slice.rs b/crates/circuit/src/slice.rs index 24c378849a2..9bde2683deb 100644 --- a/crates/circuit/src/slice.rs +++ b/crates/circuit/src/slice.rs @@ -41,7 +41,7 @@ impl<'py> FromPyObject<'py> for PySequenceIndex<'py> { } } -impl<'py> PySequenceIndex<'py> { +impl PySequenceIndex<'_> { /// Specialize this index to a collection of the given `len`, returning a Rust-native type. pub fn with_len(&self, len: usize) -> Result { match self { diff --git a/crates/qasm2/src/error.rs b/crates/qasm2/src/error.rs index 6b34364a2ab..f5c9cdc9fc4 100644 --- a/crates/qasm2/src/error.rs +++ b/crates/qasm2/src/error.rs @@ -30,7 +30,7 @@ impl<'a> Position<'a> { } } -impl<'a> std::fmt::Display for &Position<'a> { +impl std::fmt::Display for &Position<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, diff --git a/crates/qasm2/src/expr.rs b/crates/qasm2/src/expr.rs index fe78b290e0f..0186253b2f8 100644 --- a/crates/qasm2/src/expr.rs +++ b/crates/qasm2/src/expr.rs @@ -242,7 +242,7 @@ pub struct ExprParser<'a> { pub strict: bool, } -impl<'a> ExprParser<'a> { +impl ExprParser<'_> { /// Get the next token available in the stack of token streams, popping and removing any /// complete streams, except the base case. Will only return `None` once all streams are /// exhausted. diff --git a/crates/qasm3/Cargo.toml b/crates/qasm3/Cargo.toml index eb7b7137c7a..a7be442f67e 100644 --- a/crates/qasm3/Cargo.toml +++ b/crates/qasm3/Cargo.toml @@ -10,8 +10,11 @@ name = "qiskit_qasm3" doctest = false [dependencies] -pyo3.workspace = true indexmap.workspace = true hashbrown.workspace = true oq3_semantics = "0.7.0" ahash.workspace = true + +[dependencies.pyo3] +workspace = true +features = ["py-clone"] diff --git a/crates/qasm3/src/expr.rs b/crates/qasm3/src/expr.rs index 64afe58991c..40d2da4af2d 100644 --- a/crates/qasm3/src/expr.rs +++ b/crates/qasm3/src/expr.rs @@ -132,7 +132,7 @@ impl<'py> Iterator for BroadcastQubitsIter<'py> { (self.len - self.offset, Some(self.len - self.offset)) } } -impl<'py> ExactSizeIterator for BroadcastQubitsIter<'py> {} +impl ExactSizeIterator for BroadcastQubitsIter<'_> {} struct BroadcastMeasureIter<'a, 'py> { py: Python<'py>, @@ -142,7 +142,7 @@ struct BroadcastMeasureIter<'a, 'py> { carg: &'a BroadcastItem, } -impl<'a, 'py> Iterator for BroadcastMeasureIter<'a, 'py> { +impl<'py> Iterator for BroadcastMeasureIter<'_, 'py> { type Item = (Bound<'py, PyTuple>, Bound<'py, PyTuple>); fn next(&mut self) -> Option { @@ -165,7 +165,7 @@ impl<'a, 'py> Iterator for BroadcastMeasureIter<'a, 'py> { (self.len - self.offset, Some(self.len - self.offset)) } } -impl<'a, 'py> ExactSizeIterator for BroadcastMeasureIter<'a, 'py> {} +impl ExactSizeIterator for BroadcastMeasureIter<'_, '_> {} fn broadcast_bits_for_identifier( py: Python, From 1ae287bd97b46e19b2f9c411be24dd26949cb307 Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Mon, 2 Dec 2024 11:05:41 +0100 Subject: [PATCH 2/5] Remove `deprecate_function` and `deprecate_arguments` decorators (deprecated in 0.24) (#13448) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove deprecated_function and deprecated_argument decorators * reno * Update releasenotes/notes/deprecate_arguments_and_deprecate_function-5e19f6f049fa489c.yaml Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- qiskit/utils/__init__.py | 6 - qiskit/utils/deprecation.py | 108 ------------------ ...d_deprecate_function-5e19f6f049fa489c.yaml | 7 ++ test/python/utils/test_deprecation.py | 94 --------------- 4 files changed, 7 insertions(+), 208 deletions(-) create mode 100644 releasenotes/notes/deprecate_arguments_and_deprecate_function-5e19f6f049fa489c.yaml diff --git a/qiskit/utils/__init__.py b/qiskit/utils/__init__.py index 30935437ebf..c6b73e09ff2 100644 --- a/qiskit/utils/__init__.py +++ b/qiskit/utils/__init__.py @@ -23,9 +23,7 @@ .. autofunction:: add_deprecation_to_docstring .. autofunction:: deprecate_arg -.. autofunction:: deprecate_arguments .. autofunction:: deprecate_func -.. autofunction:: deprecate_function SI unit conversion ================== @@ -58,9 +56,7 @@ from .deprecation import ( add_deprecation_to_docstring, deprecate_arg, - deprecate_arguments, deprecate_func, - deprecate_function, ) from .multiprocessing import local_hardware_info from .multiprocessing import is_main_process @@ -78,9 +74,7 @@ "LazySubprocessTester", "add_deprecation_to_docstring", "deprecate_arg", - "deprecate_arguments", "deprecate_func", - "deprecate_function", "local_hardware_info", "is_main_process", "apply_prefix", diff --git a/qiskit/utils/deprecation.py b/qiskit/utils/deprecation.py index aebea233282..2a1e4adbc1b 100644 --- a/qiskit/utils/deprecation.py +++ b/qiskit/utils/deprecation.py @@ -205,114 +205,6 @@ def wrapper(*args, **kwargs): return decorator -def deprecate_arguments( - kwarg_map: dict[str, str | None], - category: Type[Warning] = DeprecationWarning, - *, - since: str | None = None, -): - """Deprecated. Instead, use `@deprecate_arg`. - - Args: - kwarg_map: A dictionary of the old argument name to the new name. - category: Usually either DeprecationWarning or PendingDeprecationWarning. - since: The version the deprecation started at. Only Optional for backwards - compatibility - this should always be set. If the deprecation is pending, set - the version to when that started; but later, when switching from pending to - deprecated, update `since` to the new version. - - Returns: - Callable: The decorated callable. - """ - - def decorator(func): - func_name = func.__qualname__ - old_kwarg_to_msg = {} - for old_arg, new_arg in kwarg_map.items(): - msg_suffix = ( - "will in the future be removed." if new_arg is None else f"replaced with {new_arg}." - ) - old_kwarg_to_msg[old_arg] = ( - f"{func_name} keyword argument {old_arg} is deprecated and {msg_suffix}" - ) - - @functools.wraps(func) - def wrapper(*args, **kwargs): - for old, new in kwarg_map.items(): - _maybe_warn_and_rename_kwarg( - args, - kwargs, - func_name=func_name, - original_func_co_varnames=wrapper.__original_func_co_varnames, - old_arg_name=old, - new_alias=new, - warning_msg=old_kwarg_to_msg[old], - category=category, - predicate=None, - ) - return func(*args, **kwargs) - - # When decorators get called repeatedly, `func` refers to the result of the prior - # decorator, not the original underlying function. This trick allows us to record the - # original function's variable names regardless of how many decorators are used. - # - # If it's the very first decorator call, we also check that *args and **kwargs are not used. - if hasattr(func, "__original_func_co_varnames"): - wrapper.__original_func_co_varnames = func.__original_func_co_varnames - else: - wrapper.__original_func_co_varnames = func.__code__.co_varnames - param_kinds = {param.kind for param in inspect.signature(func).parameters.values()} - if inspect.Parameter.VAR_POSITIONAL in param_kinds: - raise ValueError( - "@deprecate_arg cannot be used with functions that take variable *args. Use " - "warnings.warn() directly instead." - ) - - for msg in old_kwarg_to_msg.values(): - add_deprecation_to_docstring( - wrapper, msg, since=since, pending=issubclass(category, PendingDeprecationWarning) - ) - return wrapper - - return decorator - - -def deprecate_function( - msg: str, - stacklevel: int = 2, - category: Type[Warning] = DeprecationWarning, - *, - since: str | None = None, -): - """Deprecated. Instead, use `@deprecate_func`. - - Args: - msg: Warning message to emit. - stacklevel: The warning stacklevel to use, defaults to 2. - category: Usually either DeprecationWarning or PendingDeprecationWarning. - since: The version the deprecation started at. Only Optional for backwards - compatibility - this should always be set. If the deprecation is pending, set - the version to when that started; but later, when switching from pending to - deprecated, update `since` to the new version. - - Returns: - Callable: The decorated, deprecated callable. - """ - - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - warnings.warn(msg, category=category, stacklevel=stacklevel) - return func(*args, **kwargs) - - add_deprecation_to_docstring( - wrapper, msg, since=since, pending=issubclass(category, PendingDeprecationWarning) - ) - return wrapper - - return decorator - - def _maybe_warn_and_rename_kwarg( args: tuple[Any, ...], kwargs: dict[str, Any], diff --git a/releasenotes/notes/deprecate_arguments_and_deprecate_function-5e19f6f049fa489c.yaml b/releasenotes/notes/deprecate_arguments_and_deprecate_function-5e19f6f049fa489c.yaml new file mode 100644 index 00000000000..7dfb70703cf --- /dev/null +++ b/releasenotes/notes/deprecate_arguments_and_deprecate_function-5e19f6f049fa489c.yaml @@ -0,0 +1,7 @@ +--- +upgrade_misc: + - | + The ``deprecate_function`` and ``deprecate_arguments`` decorators had been deprecated since 0.24, released + on May 2023, and have been removed in 2.0. + Current :func:`deprecate_func`` replaces ``@deprecate_function`` and current + :func:`deprecate_arg` replaces ``@deprecate_arguments``. diff --git a/test/python/utils/test_deprecation.py b/test/python/utils/test_deprecation.py index 08872b9e7a4..1e2f98b1726 100644 --- a/test/python/utils/test_deprecation.py +++ b/test/python/utils/test_deprecation.py @@ -20,9 +20,7 @@ from qiskit.utils.deprecation import ( add_deprecation_to_docstring, deprecate_arg, - deprecate_arguments, deprecate_func, - deprecate_function, ) from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -164,51 +162,6 @@ def my_func() -> None: ), ) - def test_deprecate_arguments_docstring(self) -> None: - """Test that `@deprecate_arguments` adds the correct message to the docstring.""" - - @deprecate_arguments( - {"old_arg1": "new_arg1", "old_arg2": None}, - category=PendingDeprecationWarning, - since="9.99", - ) - def my_func() -> None: - pass - - self.assertEqual( - my_func.__doc__, - dedent( - f"""\ - - .. deprecated:: 9.99_pending - {my_func.__qualname__} keyword argument old_arg1 is deprecated and replaced with \ -new_arg1. - - .. deprecated:: 9.99_pending - {my_func.__qualname__} keyword argument old_arg2 is deprecated and will in the \ -future be removed. - """ - ), - ) - - def test_deprecate_function_docstring(self) -> None: - """Test that `@deprecate_function` adds the correct message to the docstring.""" - - @deprecate_function("Stop using my_func!", since="9.99") - def my_func() -> None: - pass - - self.assertEqual( - my_func.__doc__, - dedent( - """\ - - .. deprecated:: 9.99 - Stop using my_func! - """ - ), - ) - def test_deprecate_func_runtime_warning(self) -> None: """Test that `@deprecate_func` warns whenever the function is used.""" @@ -313,53 +266,6 @@ def my_func2(my_kwarg: int | None = None, **kwargs) -> None: with self.assertWarnsRegex(DeprecationWarning, "my_kwarg"): my_func2(my_kwarg=5, another_arg=0, yet_another=0) - def test_deprecate_arguments_runtime_warning(self) -> None: - """Test that `@deprecate_arguments` warns whenever the arguments are used. - - Also check that old arguments are passed in as their new alias. - """ - - @deprecate_arguments({"arg1": "new_arg1", "arg2": None}, since="9.99") - def my_func(arg1: str = "a", arg2: str = "a", new_arg1: str | None = None) -> None: - del arg2 - # If the old arg was set, we should set its `new_alias` to that value. - if arg1 != "a": - self.assertEqual(new_arg1, "z") - if new_arg1 is not None: - self.assertEqual(new_arg1, "z") - - # No warnings if no deprecated args used. - my_func() - my_func(new_arg1="z") - - # Warn if argument is specified, regardless of positional vs kwarg. - with self.assertWarnsRegex(DeprecationWarning, "arg1"): - my_func("z") - with self.assertWarnsRegex(DeprecationWarning, "arg1"): - my_func(arg1="z") - with self.assertWarnsRegex(DeprecationWarning, "arg2"): - my_func("z", "z") - with self.assertWarnsRegex(DeprecationWarning, "arg2"): - my_func(arg2="z") - - # Error if new_alias specified at the same time as old argument name. - with self.assertRaises(TypeError): - my_func("a", new_arg1="z") - with self.assertRaises(TypeError): - my_func(arg1="a", new_arg1="z") - with self.assertRaises(TypeError): - my_func("a", "a", "z") - - def test_deprecate_function_runtime_warning(self) -> None: - """Test that `@deprecate_function` warns whenever the function is used.""" - - @deprecate_function("Stop using my_func!", since="9.99") - def my_func() -> None: - pass - - with self.assertWarnsRegex(DeprecationWarning, "Stop using my_func!"): - my_func() - class AddDeprecationDocstringTest(QiskitTestCase): """Test that we correctly insert the deprecation directive at the right location. From 276456f289cc7e7c7848ab9cad5a60625f6b2e3e Mon Sep 17 00:00:00 2001 From: Frank Harkins Date: Mon, 2 Dec 2024 11:58:17 +0000 Subject: [PATCH 3/5] Use `.. plot::` directive to test code examples (#13179) * Switch to plot directive * Apply suggestions from code review Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> * Update qiskit/transpiler/passes/scheduling/padding/pad_delay.py Co-authored-by: Jake Lishman * Avoid writing to disk during testing Co-authored-by: Jake Lishman --------- Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> Co-authored-by: Jake Lishman Co-authored-by: Jake Lishman --- crates/circuit/src/circuit_data.rs | 4 +- qiskit/assembler/assemble_circuits.py | 4 +- qiskit/assembler/assemble_schedules.py | 4 +- qiskit/assembler/disassemble.py | 4 +- qiskit/circuit/__init__.py | 6 +- qiskit/circuit/classical/types/ordering.py | 5 +- qiskit/circuit/classicalfunction/__init__.py | 4 +- qiskit/circuit/library/__init__.py | 12 +- .../library/generalized_gates/unitary.py | 4 +- qiskit/circuit/library/pauli_evolution.py | 8 +- qiskit/circuit/quantumcircuit.py | 66 +++++-- qiskit/converters/circuit_to_dag.py | 4 +- qiskit/converters/circuit_to_instruction.py | 4 +- qiskit/passmanager/__init__.py | 30 +++- qiskit/primitives/__init__.py | 16 +- qiskit/primitives/base/base_estimator.py | 4 +- qiskit/primitives/base/base_sampler.py | 4 +- .../primitives/containers/bindings_array.py | 4 +- qiskit/primitives/containers/data_bin.py | 4 +- qiskit/primitives/statevector_sampler.py | 4 +- qiskit/providers/basic_provider/__init__.py | 4 +- .../basic_provider/basic_simulator.py | 4 +- qiskit/pulse/builder.py | 165 +++++++++++++----- qiskit/pulse/instructions/directives.py | 14 +- qiskit/pulse/library/symbolic_pulses.py | 6 +- qiskit/pulse/schedule.py | 86 +++++++-- qiskit/pulse/transforms/alignments.py | 4 +- qiskit/pulse/transforms/canonicalization.py | 10 +- qiskit/pulse/transforms/dag.py | 10 +- qiskit/qasm2/__init__.py | 27 ++- qiskit/qasm3/__init__.py | 6 +- qiskit/qobj/converters/pulse_instruction.py | 8 +- qiskit/qobj/pulse_qobj.py | 2 +- qiskit/qobj/qasm_qobj.py | 2 +- qiskit/qpy/__init__.py | 47 ++++- qiskit/qpy/interface.py | 5 +- qiskit/quantum_info/analysis/distance.py | 4 +- .../operators/dihedral/dihedral.py | 4 +- qiskit/quantum_info/operators/operator.py | 4 +- .../operators/symplectic/clifford.py | 4 +- .../operators/symplectic/pauli.py | 4 +- .../operators/symplectic/pauli_list.py | 22 ++- .../operators/symplectic/sparse_pauli_op.py | 24 ++- qiskit/quantum_info/states/densitymatrix.py | 20 ++- qiskit/quantum_info/states/stabilizerstate.py | 8 +- qiskit/quantum_info/states/statevector.py | 20 ++- qiskit/transpiler/__init__.py | 26 ++- .../passes/calibration/rx_builder.py | 4 +- .../commuting_2q_gate_router.py | 4 +- .../passes/scheduling/padding/pad_delay.py | 4 +- .../synthesis/solovay_kitaev_synthesis.py | 8 +- .../transpiler/preset_passmanagers/plugin.py | 4 +- qiskit/utils/parallel.py | 4 +- qiskit/visualization/__init__.py | 2 + .../pass_manager_visualization.py | 8 +- qiskit/visualization/pulse_v2/events.py | 12 +- qiskit/visualization/pulse_v2/interface.py | 4 +- 57 files changed, 612 insertions(+), 177 deletions(-) diff --git a/crates/circuit/src/circuit_data.rs b/crates/circuit/src/circuit_data.rs index 5422138264b..3ed429d4f5e 100644 --- a/crates/circuit/src/circuit_data.rs +++ b/crates/circuit/src/circuit_data.rs @@ -57,7 +57,9 @@ import_exception!(qiskit.circuit.exceptions, CircuitError); /// /// For example, /// -/// .. code-block:: +/// .. plot:: +/// :include-source: +/// :no-figs: /// /// qubits = [Qubit()] /// data = CircuitData(qubits) diff --git a/qiskit/assembler/assemble_circuits.py b/qiskit/assembler/assemble_circuits.py index 62f3df18071..0656bae0778 100644 --- a/qiskit/assembler/assemble_circuits.py +++ b/qiskit/assembler/assemble_circuits.py @@ -429,7 +429,9 @@ def assemble_circuits( Examples: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.assembler import assemble_circuits diff --git a/qiskit/assembler/assemble_schedules.py b/qiskit/assembler/assemble_schedules.py index 697f3a46677..5a9fae4c79b 100644 --- a/qiskit/assembler/assemble_schedules.py +++ b/qiskit/assembler/assemble_schedules.py @@ -54,7 +54,9 @@ def assemble_schedules( Examples: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.assembler import assemble_schedules diff --git a/qiskit/assembler/disassemble.py b/qiskit/assembler/disassemble.py index 74905a9a6d2..44107eddbaf 100644 --- a/qiskit/assembler/disassemble.py +++ b/qiskit/assembler/disassemble.py @@ -69,7 +69,9 @@ def disassemble(qobj) -> Union[CircuitModule, PulseModule]: Examples: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.compiler.assembler import assemble diff --git a/qiskit/circuit/__init__.py b/qiskit/circuit/__init__.py index ab7ff9a8416..f4d533b7a2f 100644 --- a/qiskit/circuit/__init__.py +++ b/qiskit/circuit/__init__.py @@ -559,7 +559,11 @@ The :class:`Barrier` instruction can span an arbitrary number of qubits and clbits, and is a no-op in hardware. During transpilation and optimization, however, it blocks any optimizations from -"crossing" the barrier; that is, in:: +"crossing" the barrier; that is, in: + +.. plot:: + :include-source: + :nofigs: from qiskit.circuit import QuantumCircuit diff --git a/qiskit/circuit/classical/types/ordering.py b/qiskit/circuit/classical/types/ordering.py index b000e91cf5e..5a4365b8e14 100644 --- a/qiskit/circuit/classical/types/ordering.py +++ b/qiskit/circuit/classical/types/ordering.py @@ -205,7 +205,10 @@ def cast_kind(from_: Type, to_: Type, /) -> CastKind: Examples: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + >>> from qiskit.circuit.classical import types >>> types.cast_kind(types.Bool(), types.Bool()) diff --git a/qiskit/circuit/classicalfunction/__init__.py b/qiskit/circuit/classicalfunction/__init__.py index b045227b167..85f430ba5a3 100644 --- a/qiskit/circuit/classicalfunction/__init__.py +++ b/qiskit/circuit/classicalfunction/__init__.py @@ -25,7 +25,7 @@ how to synthesize a simple boolean function defined using Python into a QuantumCircuit: - .. code-block:: + .. code-block:: python from qiskit.circuit.classicalfunction import classical_function from qiskit.circuit.classicalfunction.types import Int1 @@ -37,6 +37,8 @@ def grover_oracle(a: Int1, b: Int1, c: Int1, d: Int1) -> Int1: quantum_circuit = grover_oracle.synth(registerless=False) quantum_circuit.draw('text') + .. code-block:: text + a: ──o── │ b: ──■── diff --git a/qiskit/circuit/library/__init__.py b/qiskit/circuit/library/__init__.py index 283f5b287a5..969ccfc5e5a 100644 --- a/qiskit/circuit/library/__init__.py +++ b/qiskit/circuit/library/__init__.py @@ -52,7 +52,9 @@ For example: -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit.circuit.library import XGate gate = XGate() @@ -155,7 +157,9 @@ set the amount of qubits involved at instantiation time. -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit.circuit.library import DiagonalGate @@ -446,7 +450,9 @@ In this example, the identity constant in a template is checked: -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit.circuit.library.templates import template_nct_4b_1 from qiskit.quantum_info import Operator diff --git a/qiskit/circuit/library/generalized_gates/unitary.py b/qiskit/circuit/library/generalized_gates/unitary.py index 9aa03be8631..40271ed4f59 100644 --- a/qiskit/circuit/library/generalized_gates/unitary.py +++ b/qiskit/circuit/library/generalized_gates/unitary.py @@ -45,7 +45,9 @@ class UnitaryGate(Gate): quantum circuit. The matrix can also be directly applied to the quantum circuit, see :meth:`.QuantumCircuit.unitary`. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit from qiskit.circuit.library import UnitaryGate diff --git a/qiskit/circuit/library/pauli_evolution.py b/qiskit/circuit/library/pauli_evolution.py index b7818f72d5f..e5c0c46bd31 100644 --- a/qiskit/circuit/library/pauli_evolution.py +++ b/qiskit/circuit/library/pauli_evolution.py @@ -49,7 +49,9 @@ class PauliEvolutionGate(Gate): **Examples:** - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import PauliEvolutionGate @@ -68,7 +70,9 @@ class PauliEvolutionGate(Gate): circuit.append(evo, range(2)) print(circuit.draw()) - The above will print (note that the ``-0.1`` coefficient is not printed!):: + The above will print (note that the ``-0.1`` coefficient is not printed!): + + .. code-block:: text ┌──────────────────────────┐ q_0: ┤0 ├ diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 2c96ec533f3..dee2f3e7227 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -3867,7 +3867,10 @@ def measure(self, qubit: QubitSpecifier, cbit: ClbitSpecifier) -> InstructionSet In this example, a qubit is measured and the result of that measurement is stored in the classical bit (usually expressed in diagrams as a double line): - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import QuantumCircuit circuit = QuantumCircuit(1, 1) @@ -3887,12 +3890,18 @@ def measure(self, qubit: QubitSpecifier, cbit: ClbitSpecifier) -> InstructionSet It is possible to call ``measure`` with lists of ``qubits`` and ``cbits`` as a shortcut for one-to-one measurement. These two forms produce identical results: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: circuit = QuantumCircuit(2, 2) circuit.measure([0,1], [0,1]) - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: circuit = QuantumCircuit(2, 2) circuit.measure(0, 0) @@ -3901,7 +3910,10 @@ def measure(self, qubit: QubitSpecifier, cbit: ClbitSpecifier) -> InstructionSet Instead of lists, you can use :class:`~qiskit.circuit.QuantumRegister` and :class:`~qiskit.circuit.ClassicalRegister` under the same logic. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister qreg = QuantumRegister(2, "qreg") @@ -3911,7 +3923,10 @@ def measure(self, qubit: QubitSpecifier, cbit: ClbitSpecifier) -> InstructionSet This is equivalent to: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: circuit = QuantumCircuit(qreg, creg) circuit.measure(qreg[0], creg[0]) @@ -4160,7 +4175,9 @@ def parameters(self) -> ParameterView: The snippet below shows that insertion order of parameters does not matter. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: >>> from qiskit.circuit import QuantumCircuit, Parameter >>> a, b, elephant = Parameter("a"), Parameter("b"), Parameter("elephant") @@ -4174,7 +4191,9 @@ def parameters(self) -> ParameterView: Bear in mind that alphabetical sorting might be unintuitive when it comes to numbers. The literal "10" comes before "2" in strict alphabetical sorting. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: >>> from qiskit.circuit import QuantumCircuit, Parameter >>> angles = [Parameter("angle_1"), Parameter("angle_2"), Parameter("angle_10")] @@ -4189,7 +4208,9 @@ def parameters(self) -> ParameterView: To respect numerical sorting, a :class:`.ParameterVector` can be used. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: >>> from qiskit.circuit import QuantumCircuit, Parameter, ParameterVector >>> x = ParameterVector("x", 12) @@ -5720,7 +5741,9 @@ def prepare_state( Examples: Prepare a qubit in the state :math:`(|0\rangle - |1\rangle) / \sqrt{2}`. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit import QuantumCircuit @@ -5743,7 +5766,9 @@ def prepare_state( More information about labels for basis states are in :meth:`.Statevector.from_label`. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit import QuantumCircuit @@ -5764,7 +5789,10 @@ def prepare_state( Initialize two qubits from an array of complex amplitudes - .. code-block:: + + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit import QuantumCircuit @@ -5835,7 +5863,9 @@ class to prepare the qubits in a specified state. Examples: Prepare a qubit in the state :math:`(|0\rangle - |1\rangle) / \sqrt{2}`. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit import QuantumCircuit @@ -5858,7 +5888,9 @@ class to prepare the qubits in a specified state. More information about labels for basis states are in :meth:`.Statevector.from_label`. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit import QuantumCircuit @@ -5879,7 +5911,9 @@ class to prepare the qubits in a specified state. Initialize two qubits from an array of complex amplitudes. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit import QuantumCircuit @@ -5930,7 +5964,9 @@ def unitary( Apply a gate specified by a unitary matrix to a quantum circuit - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit matrix = [[0, 0, 0, 1], diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index 6896f8a698f..b4f14636bff 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -41,7 +41,9 @@ def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_ord the circuit. Example: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.dagcircuit import DAGCircuit diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index db314eee267..bd7d720a5dd 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -43,7 +43,9 @@ def circuit_to_instruction(circuit, parameter_map=None, equivalence_library=None yield the components comprising the original circuit. Example: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.converters import circuit_to_instruction diff --git a/qiskit/passmanager/__init__.py b/qiskit/passmanager/__init__.py index 9c1ea0577b7..9043f5bdc98 100644 --- a/qiskit/passmanager/__init__.py +++ b/qiskit/passmanager/__init__.py @@ -87,7 +87,10 @@ We use the pass manager framework here, putting the efficiency aside for a moment to learn how to build a custom Qiskit compiler. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: from qiskit.passmanager import BasePassManager, GenericPass, ConditionalController @@ -111,7 +114,10 @@ def _passmanager_backend(self, passmanager_ir: str, in_program: int, **kwargs) - Next, we implement a pass that removes a digit when the number is five. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: class RemoveFive(GenericPass): @@ -124,7 +130,10 @@ def run(self, passmanager_ir: str): Running the pass manager with random row of numbers returns new numbers that don't contain five. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: pm = ToyPassManager() pm.append(task) @@ -143,7 +152,10 @@ def run(self, passmanager_ir: str): We start from an analysis pass that provides the flow controller with information about the number of digits. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: class CountDigits(GenericPass): @@ -155,7 +167,10 @@ def run(self, passmanager_ir: str): Then, we wrap the remove five task with the :class:`.ConditionalController` that runs the stored tasks only when the condition is met. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: def digit_condition(property_set): # Return True when condition is met. @@ -168,7 +183,10 @@ def digit_condition(property_set): As before, we schedule these passes with the pass manager and run. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: pm = ToyPassManager() pm.append(analysis_task) diff --git a/qiskit/primitives/__init__.py b/qiskit/primitives/__init__.py index 7cf8355354e..c4fb9855115 100644 --- a/qiskit/primitives/__init__.py +++ b/qiskit/primitives/__init__.py @@ -66,7 +66,9 @@ Here is an example of how an estimator is used. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: from qiskit.primitives import StatevectorEstimator as Estimator from qiskit.circuit.library import RealAmplitudes @@ -126,7 +128,9 @@ Here is an example of how a sampler is used. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: from qiskit.primitives import StatevectorSampler as Sampler from qiskit import QuantumCircuit @@ -192,7 +196,9 @@ Here is an example of how the estimator is used. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: from qiskit.primitives import Estimator from qiskit.circuit.library import RealAmplitudes @@ -251,7 +257,9 @@ Here is an example of how sampler is used. -.. code-block:: python +.. plot:: + :include-source: + :nofigs: from qiskit.primitives import Sampler from qiskit import QuantumCircuit diff --git a/qiskit/primitives/base/base_estimator.py b/qiskit/primitives/base/base_estimator.py index 5171a73ffc7..0843aa6a328 100644 --- a/qiskit/primitives/base/base_estimator.py +++ b/qiskit/primitives/base/base_estimator.py @@ -70,7 +70,9 @@ class BaseEstimatorV1(BasePrimitive, Generic[T]): Here is an example of how the estimator is used. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.primitives import Estimator from qiskit.circuit.library import RealAmplitudes diff --git a/qiskit/primitives/base/base_sampler.py b/qiskit/primitives/base/base_sampler.py index 65d87d86b07..6235196f181 100644 --- a/qiskit/primitives/base/base_sampler.py +++ b/qiskit/primitives/base/base_sampler.py @@ -56,7 +56,9 @@ class BaseSamplerV1(BasePrimitive, Generic[T]): Here is an example of how sampler is used. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.primitives import Sampler from qiskit import QuantumCircuit diff --git a/qiskit/primitives/containers/bindings_array.py b/qiskit/primitives/containers/bindings_array.py index 89730e5ce94..5b72067a1f3 100644 --- a/qiskit/primitives/containers/bindings_array.py +++ b/qiskit/primitives/containers/bindings_array.py @@ -67,7 +67,9 @@ class BindingsArray(ShapedMixin): allows flexibility about whether values for different parameters are stored in one big array, or across several smaller arrays. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: # 0-d array (i.e. only one binding) BindingsArray({"a": 4, ("b", "c"): [5, 6]}) diff --git a/qiskit/primitives/containers/data_bin.py b/qiskit/primitives/containers/data_bin.py index 9032f85ab59..21252d2ef90 100644 --- a/qiskit/primitives/containers/data_bin.py +++ b/qiskit/primitives/containers/data_bin.py @@ -32,7 +32,9 @@ def _value_repr(value: Any) -> str: class DataBin(ShapedMixin): """Namespace for storing data. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.primitives import DataBin, BitArray diff --git a/qiskit/primitives/statevector_sampler.py b/qiskit/primitives/statevector_sampler.py index 486f35bc936..9c12eb7dd43 100644 --- a/qiskit/primitives/statevector_sampler.py +++ b/qiskit/primitives/statevector_sampler.py @@ -64,7 +64,9 @@ class StatevectorSampler(BaseSamplerV2): primitive unified bloc (PUB), produces its own array-valued result. The :meth:`~run` method can be given many pubs at once. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.circuit import ( Parameter, QuantumCircuit, ClassicalRegister, QuantumRegister diff --git a/qiskit/providers/basic_provider/__init__.py b/qiskit/providers/basic_provider/__init__.py index 4fc0f06d76a..0317ad66b28 100644 --- a/qiskit/providers/basic_provider/__init__.py +++ b/qiskit/providers/basic_provider/__init__.py @@ -20,7 +20,9 @@ A module of Python-based quantum simulators. Simulators can be accessed via the `BasicProvider` provider, e.g.: -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit.providers.basic_provider import BasicProvider diff --git a/qiskit/providers/basic_provider/basic_simulator.py b/qiskit/providers/basic_provider/basic_simulator.py index e412867a0e1..f9534cb4d9a 100644 --- a/qiskit/providers/basic_provider/basic_simulator.py +++ b/qiskit/providers/basic_provider/basic_simulator.py @@ -17,7 +17,9 @@ The simulator is run using -.. code-block:: python +.. plot:: + :include-source: + :nofigs: BasicSimulator().run(run_input) diff --git a/qiskit/pulse/builder.py b/qiskit/pulse/builder.py index 74341816806..9b2c9208ac7 100644 --- a/qiskit/pulse/builder.py +++ b/qiskit/pulse/builder.py @@ -131,7 +131,9 @@ In the example below we demonstrate some more features of the pulse builder: -.. code-block:: +.. plot:: + :include-source: + :nofigs: import math from qiskit.compiler import schedule @@ -246,7 +248,9 @@ Methods to return the correct channels for the respective qubit indices. -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import GenericBackendV2 @@ -351,7 +355,9 @@ Macros help you add more complex functionality to your pulse program. -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import GenericBackendV2 @@ -377,7 +383,9 @@ The utility functions can be used to gather attributes about the backend and modify how the program is built. -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -785,7 +793,10 @@ def build( To enter a building context and starting building a pulse program: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import transpile, pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -881,7 +892,9 @@ def append_instruction(instruction: instructions.Instruction): Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -905,7 +918,9 @@ def num_qubits() -> int: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -965,7 +980,9 @@ def qubit_channels(qubit: int) -> set[chans.Channel]: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -1041,7 +1058,9 @@ def align_left() -> Generator[None, None, None]: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1080,7 +1099,9 @@ def align_right() -> Generator[None, None, None]: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1119,7 +1140,9 @@ def align_sequential() -> Generator[None, None, None]: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1297,7 +1320,9 @@ def phase_offset(phase: float, *channels: chans.PulseChannel) -> Generator[None, Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: import math @@ -1336,8 +1361,9 @@ def frequency_offset( Examples: - .. code-block:: python - :emphasize-lines: 7, 16 + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -1400,7 +1426,9 @@ def drive_channel(qubit: int) -> chans.DriveChannel: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -1424,7 +1452,9 @@ def measure_channel(qubit: int) -> chans.MeasureChannel: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -1448,7 +1478,9 @@ def acquire_channel(qubit: int) -> chans.AcquireChannel: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -1475,7 +1507,9 @@ def control_channels(*qubits: Iterable[int]) -> list[chans.ControlChannel]: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -1507,7 +1541,9 @@ def delay(duration: int, channel: chans.Channel, name: str | None = None): Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1530,7 +1566,9 @@ def play(pulse: library.Pulse | np.ndarray, channel: chans.PulseChannel, name: s Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1570,7 +1608,9 @@ def acquire( Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1618,7 +1658,9 @@ def set_frequency(frequency: float, channel: chans.PulseChannel, name: str | Non Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1641,8 +1683,9 @@ def shift_frequency(frequency: float, channel: chans.PulseChannel, name: str | N Examples: - .. code-block:: python - :emphasize-lines: 6 + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1665,8 +1708,9 @@ def set_phase(phase: float, channel: chans.PulseChannel, name: str | None = None Examples: - .. code-block:: python - :emphasize-lines: 8 + .. plot:: + :include-source: + :nofigs: import math @@ -1691,7 +1735,9 @@ def shift_phase(phase: float, channel: chans.PulseChannel, name: str | None = No Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: import math @@ -1716,7 +1762,9 @@ def snapshot(label: str, snapshot_type: str = "statevector"): Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1755,7 +1803,10 @@ def call( 1. Calling a schedule block (recommended) - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import circuit, pulse from qiskit.providers.fake_provider import GenericBackendV2 @@ -1787,7 +1838,10 @@ def call( The actual program is stored in the reference table attached to the schedule. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: print(pulse_prog.references) @@ -1798,7 +1852,10 @@ def call( In addition, you can call a parameterized target program with parameter assignment. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: amp = circuit.Parameter("amp") @@ -1837,7 +1894,10 @@ def call( If there is a name collision between parameters, you can distinguish them by specifying each parameter object in a python dictionary. For example, - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: amp1 = circuit.Parameter('amp') amp2 = circuit.Parameter('amp') @@ -1866,7 +1926,10 @@ def call( 2. Calling a schedule - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: x_sched = backend.instruction_schedule_map.get("x", (0,)) @@ -1932,7 +1995,9 @@ def reference(name: str, *extra_keys: str): A :class:`~qiskit.pulse.instructions.Reference` instruction is implicitly created and a schedule can be separately registered to the reference at a later stage. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit import pulse @@ -1960,7 +2025,10 @@ def barrier(*channels_or_qubits: chans.Channel | int, name: str | None = None): the barrier. Consider the case where we want to enforce that one pulse happens after another on separate channels, this can be done with: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -1977,7 +2045,10 @@ def barrier(*channels_or_qubits: chans.Channel | int, name: str | None = None): Of course this could have been accomplished with: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: from qiskit.pulse import transforms @@ -1996,7 +2067,9 @@ def barrier(*channels_or_qubits: chans.Channel | int, name: str | None = None): in the case where we are calling an outside circuit or schedule and want to align a pulse at the end of one call: - .. code-block:: + .. plot:: + :include-source: + :nofigs: import math from qiskit import pulse @@ -2106,7 +2179,10 @@ def measure( To use the measurement it is as simple as specifying the qubit you wish to measure: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -2126,7 +2202,10 @@ def measure( future we will support using this handle to a result register to build up ones program. It is also possible to supply this register: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: with pulse.build(backend) as pulse_prog: pulse.play(pulse.Constant(100, 1.0), qubit_drive_chan) @@ -2189,7 +2268,9 @@ def measure_all() -> list[chans.MemorySlot]: Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse2Q @@ -2230,7 +2311,9 @@ def delay_qubits(duration: int, *qubits: int): Examples: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import pulse from qiskit.providers.fake_provider import FakeOpenPulse3Q diff --git a/qiskit/pulse/instructions/directives.py b/qiskit/pulse/instructions/directives.py index 7d44d14dd4e..1a9731798fe 100644 --- a/qiskit/pulse/instructions/directives.py +++ b/qiskit/pulse/instructions/directives.py @@ -72,7 +72,9 @@ class TimeBlockade(Directive): This schedule plays constant pulse at t0 = 120. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.pulse import Schedule, Play, Constant, DriveChannel @@ -81,7 +83,10 @@ class TimeBlockade(Directive): This schedule block is expected to be identical to above at a time of execution. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit.pulse import ScheduleBlock, Play, Constant, DriveChannel from qiskit.pulse.instructions import TimeBlockade @@ -92,7 +97,10 @@ class TimeBlockade(Directive): Such conversion may be done by - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: from qiskit.pulse.transforms import block_to_schedule, remove_directives diff --git a/qiskit/pulse/library/symbolic_pulses.py b/qiskit/pulse/library/symbolic_pulses.py index 0f3104dfa65..f18a1080573 100644 --- a/qiskit/pulse/library/symbolic_pulses.py +++ b/qiskit/pulse/library/symbolic_pulses.py @@ -314,7 +314,7 @@ class SymbolicPulse(Pulse): This is how a user can instantiate a symbolic pulse instance. In this example, we instantiate a custom `Sawtooth` envelope. - .. code-block:: + .. code-block:: python from qiskit.pulse.library import SymbolicPulse @@ -353,7 +353,9 @@ class SymbolicPulse(Pulse): Note that it would be convenient to define a factory function that automatically accomplishes this procedure. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: def Sawtooth(duration, amp, freq, name): t, amp, freq = sympy.symbols("t, amp, freq") diff --git a/qiskit/pulse/schedule.py b/qiskit/pulse/schedule.py index d4753847b5d..a5df8989a96 100644 --- a/qiskit/pulse/schedule.py +++ b/qiskit/pulse/schedule.py @@ -80,7 +80,10 @@ class Schedule: - Appending an instruction to the end of a channel - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit.pulse import Schedule, Gaussian, DriveChannel, Play sched = Schedule() @@ -88,14 +91,20 @@ class Schedule: - Appending an instruction shifted in time by a given amount - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: sched = Schedule() sched += Play(Gaussian(160, 0.1, 40), DriveChannel(0)) << 30 - Merge two schedules - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: sched1 = Schedule() sched1 += Play(Gaussian(160, 0.1, 40), DriveChannel(0)) @@ -629,7 +638,10 @@ def replace( The replacement matching is based on an instruction equality check. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import pulse @@ -648,9 +660,12 @@ def replace( Only matches at the top-level of the schedule tree. If you wish to perform this replacement over all instructions in the schedule tree. - Flatten the schedule prior to running:: + Flatten the schedule prior to running: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: sched = pulse.Schedule() @@ -884,7 +899,10 @@ class ScheduleBlock: reference key "grand_child". You can call a subroutine without specifying a substantial program. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import pulse from qiskit.circuit.parameter import Parameter @@ -914,7 +932,10 @@ class ScheduleBlock: The program calling the "grand_child" has a reference program description which is accessed through :attr:`ScheduleBlock.references`. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: print(sched_outer.references) @@ -927,7 +948,10 @@ class ScheduleBlock: Here we try a different approach to define subroutine. Namely, we call a subroutine from the root program with the actual program ``sched2``. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: amp3 = Parameter("amp3") @@ -946,7 +970,10 @@ class ScheduleBlock: Note that the root program is only aware of its direct references. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: print(main.references) @@ -960,7 +987,10 @@ class ScheduleBlock: However, the returned :class:`.ReferenceManager` is a dict-like object, and you can still reach to "grand_child" via the "child" program with the following chained dict access. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: main.references[("child", )].references[("grand_child", )] @@ -1454,7 +1484,10 @@ def assign_references( which are directly referred within the current scope. Let's see following example: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import pulse @@ -1479,14 +1512,35 @@ def assign_references( you must first assign "A" of the ``sub_prog``, and then assign the ``sub_prog`` to the ``main_prog``. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: sub_prog.assign_references({("A", ): nested_prog}, inplace=True) main_prog.assign_references({("B", ): sub_prog}, inplace=True) Alternatively, you can also write - .. code-block:: python + .. plot:: + :nofigs: + :context: reset + + # This code is hidden from readers + # It resets the variables so the following code example runs correctly + from qiskit import pulse + with pulse.build() as nested_prog: + pulse.delay(10, pulse.DriveChannel(0)) + with pulse.build() as sub_prog: + pulse.reference("A") + with pulse.build() as main_prog: + pulse.reference("B") + + + .. plot:: + :include-source: + :nofigs: + :context: main_prog.assign_references({("B", ): sub_prog}, inplace=True) main_prog.references[("B", )].assign_references({("A", ): nested_prog}, inplace=True) @@ -1530,7 +1584,9 @@ def get_parameters(self, parameter_name: str) -> list[Parameter]: because these different objects are identified by their unique uuid. For example, - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit import pulse, circuit diff --git a/qiskit/pulse/transforms/alignments.py b/qiskit/pulse/transforms/alignments.py index bc0df39efea..b0983ea80c4 100644 --- a/qiskit/pulse/transforms/alignments.py +++ b/qiskit/pulse/transforms/alignments.py @@ -336,7 +336,9 @@ class AlignFunc(AlignmentKind): For example, UDD sequence with 10 pulses can be specified with following function. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: import numpy as np diff --git a/qiskit/pulse/transforms/canonicalization.py b/qiskit/pulse/transforms/canonicalization.py index 9bda5907c2f..6d4c3cb3af7 100644 --- a/qiskit/pulse/transforms/canonicalization.py +++ b/qiskit/pulse/transforms/canonicalization.py @@ -248,7 +248,10 @@ def align_measures( correspond to the same qubit and the acquire/play instructions should be shifted together on these channels. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import pulse from qiskit.pulse import transforms @@ -272,7 +275,10 @@ def align_measures( If it is desired to only shift acquisition and measurement stimulus instructions set the flag ``align_all=False``: - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: aligned_sched, aligned_sched_shifted = transforms.align_measures( [sched, sched_shifted], diff --git a/qiskit/pulse/transforms/dag.py b/qiskit/pulse/transforms/dag.py index 90c434a4276..92e346b0f00 100644 --- a/qiskit/pulse/transforms/dag.py +++ b/qiskit/pulse/transforms/dag.py @@ -30,7 +30,10 @@ def block_to_dag(block: ScheduleBlock) -> rx.PyDAG: ``ScheduleBlock`` can be represented as a DAG as needed. For example, equality of two programs are efficiently checked on DAG representation. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import pulse @@ -54,7 +57,10 @@ def block_to_dag(block: ScheduleBlock) -> rx.PyDAG: Another example is instruction optimization. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: from qiskit import pulse diff --git a/qiskit/qasm2/__init__.py b/qiskit/qasm2/__init__.py index f17fe29113e..b6372ef000a 100644 --- a/qiskit/qasm2/__init__.py +++ b/qiskit/qasm2/__init__.py @@ -133,7 +133,10 @@ Export a simple :class:`.QuantumCircuit` to an OpenQASM 2 string: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: reset import qiskit.qasm2 from qiskit.circuit import QuantumCircuit @@ -183,7 +186,9 @@ Use :func:`loads` to import an OpenQASM 2 program in a string into a :class:`.QuantumCircuit`: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: import qiskit.qasm2 program = """ @@ -259,7 +264,9 @@ named instructions. Gates that are defined by the statement ``include "qelib1.inc";`` will automatically be associated with a suitable Qiskit circuit-library gate, but you can extend this: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: from qiskit.circuit import Gate from qiskit.qasm2 import loads, CustomInstruction @@ -292,7 +299,9 @@ def __init__(self): which mathematically is :math:`\arctan(y/x)` but correctly handling angle quadrants and infinities, and a custom ``add_one`` function: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: import math from qiskit.qasm2 import loads, CustomClassical @@ -356,7 +365,10 @@ def add_one(x): For the standard ``qelib1.inc`` include there is only one point of difference, and so the override needed to switch its phase convention is: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: reset from qiskit import qasm2 from qiskit.circuit.library import PhaseGate @@ -376,7 +388,10 @@ def add_one(x): This will use Qiskit's :class:`.PhaseGate` class to represent the ``rz`` instruction, which is equal (including the phase) to :class:`.U1Gate`: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: + :context: Operator(qasm2.loads(program, custom_instructions=custom)) diff --git a/qiskit/qasm3/__init__.py b/qiskit/qasm3/__init__.py index c0168a9a8a9..8f2ef60369b 100644 --- a/qiskit/qasm3/__init__.py +++ b/qiskit/qasm3/__init__.py @@ -59,7 +59,11 @@ If you want to enable multiple experimental features, you should combine the flags using the ``|`` operator, such as ``flag1 | flag2``. -For example, to perform an export using the early semantics of ``switch`` support:: +For example, to perform an export using the early semantics of ``switch`` support: + +.. plot:: + :include-source: + :nofigs: from qiskit import qasm3, QuantumCircuit, QuantumRegister, ClassicalRegister diff --git a/qiskit/qobj/converters/pulse_instruction.py b/qiskit/qobj/converters/pulse_instruction.py index 3a0947f34f0..1c7b740d92f 100644 --- a/qiskit/qobj/converters/pulse_instruction.py +++ b/qiskit/qobj/converters/pulse_instruction.py @@ -93,7 +93,9 @@ class InstructionToQobjConverter: Extension to the OpenPulse can be achieved by subclassing this this with extra methods corresponding to each augmented instruction. For example, - .. code-block:: python + .. plot:: + :include-source: + :nofigs: class MyConverter(InstructionToQobjConverter): @@ -515,7 +517,9 @@ class QobjToInstructionConverter: Extension to the OpenPulse can be achieved by subclassing this this with extra methods corresponding to each augmented instruction. For example, - .. code-block:: python + .. plot:: + :include-source: + :nofigs: class MyConverter(QobjToInstructionConverter): diff --git a/qiskit/qobj/pulse_qobj.py b/qiskit/qobj/pulse_qobj.py index 7a5ce06c8f3..1d2d33a1fa1 100644 --- a/qiskit/qobj/pulse_qobj.py +++ b/qiskit/qobj/pulse_qobj.py @@ -649,7 +649,7 @@ def to_dict(self): for use with IBMQ you can leverage a json encoder that converts these as expected. For example: - .. code-block:: + .. code-block:: python import json import numpy diff --git a/qiskit/qobj/qasm_qobj.py b/qiskit/qobj/qasm_qobj.py index 8858913fb47..eef2bb1315c 100644 --- a/qiskit/qobj/qasm_qobj.py +++ b/qiskit/qobj/qasm_qobj.py @@ -648,7 +648,7 @@ def to_dict(self): for use with IBM systems, you can leverage a json encoder that converts these as expected. For example: - .. code-block:: + .. code-block:: python import json import numpy diff --git a/qiskit/qpy/__init__.py b/qiskit/qpy/__init__.py index b6f7420ccfd..ffaaa5f5614 100644 --- a/qiskit/qpy/__init__.py +++ b/qiskit/qpy/__init__.py @@ -40,7 +40,24 @@ 2 user facing functions: :func:`qiskit.qpy.dump` and :func:`qiskit.qpy.load` which are used to dump QPY data to a file object and load circuits from QPY data in a file object respectively. -For example:: +For example: + +.. plot:: + :nofigs: + :context: reset + + # This code is hidden from users + # It's a hack to avoid writing to file when testing the code examples + import io + bytestream = io.BytesIO() + bytestream.close = lambda: bytestream.seek(0) + def open(*args): + return bytestream + +.. plot:: + :include-source: + :nofigs: + :context: from qiskit.circuit import QuantumCircuit from qiskit import qpy @@ -57,16 +74,27 @@ new_qc = qpy.load(fd)[0] The :func:`qiskit.qpy.dump` function also lets you -include multiple circuits in a single QPY file:: +include multiple circuits in a single QPY file: + +.. plot:: + :include-source: + :nofigs: + :context: with open('twenty_bells.qpy', 'wb') as fd: qpy.dump([qc] * 20, fd) and then loading that file will return a list with all the circuits +.. plot:: + :include-source: + :nofigs: + :context: + with open('twenty_bells.qpy', 'rb') as fd: twenty_new_bells = qpy.load(fd) + API documentation ================= @@ -984,7 +1012,9 @@ :class:`~.ScheduleBlock` is first supported in QPY Version 5. This allows users to save pulse programs in the QPY binary format as follows: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: from qiskit import pulse, qpy @@ -992,10 +1022,17 @@ pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0)) with open('schedule.qpy', 'wb') as fd: - qpy.dump(qc, fd) + qpy.dump(schedule, fd) with open('schedule.qpy', 'rb') as fd: - new_qc = qpy.load(fd)[0] + new_schedule = qpy.load(fd)[0] + +.. plot:: + :nofigs: + + # This block is hidden from readers. It's cleanup code. + from pathlib import Path + Path("schedule.qpy").unlink() Note that circuit and schedule block are serialized and deserialized through the same QPY interface. Input data type is implicitly analyzed and diff --git a/qiskit/qpy/interface.py b/qiskit/qpy/interface.py index c56630fa2b1..cab90eb9407 100644 --- a/qiskit/qpy/interface.py +++ b/qiskit/qpy/interface.py @@ -94,7 +94,10 @@ def dump( For example: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: + :context: reset from qiskit.circuit import QuantumCircuit from qiskit import qpy diff --git a/qiskit/quantum_info/analysis/distance.py b/qiskit/quantum_info/analysis/distance.py index 59f145eaab9..170cc615986 100644 --- a/qiskit/quantum_info/analysis/distance.py +++ b/qiskit/quantum_info/analysis/distance.py @@ -74,7 +74,9 @@ def hellinger_fidelity(dist_p: dict, dist_q: dict) -> float: Example: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit from qiskit.quantum_info.analysis import hellinger_fidelity diff --git a/qiskit/quantum_info/operators/dihedral/dihedral.py b/qiskit/quantum_info/operators/dihedral/dihedral.py index 8389061495f..67b93754607 100644 --- a/qiskit/quantum_info/operators/dihedral/dihedral.py +++ b/qiskit/quantum_info/operators/dihedral/dihedral.py @@ -46,7 +46,9 @@ class CNOTDihedral(BaseOperator, AdjointMixin): The phase polynomial is a polynomial of degree at most 3, in :math:`N` variables, whose coefficients are in the ring Z_8 with 8 elements. - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit from qiskit.quantum_info import CNOTDihedral diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index d549a130ae3..8479aa5dd99 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -61,7 +61,9 @@ class Operator(LinearOp): :math:`|\psi\rangle=|0\rangle (\rho = |0\rangle\langle 0|)` changes it to the one state :math:`|\psi\rangle=|1\rangle (\rho = |1\rangle\langle 1|)`: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: >>> import numpy as np >>> from qiskit.quantum_info import Operator diff --git a/qiskit/quantum_info/operators/symplectic/clifford.py b/qiskit/quantum_info/operators/symplectic/clifford.py index 4064e0e3704..49fd4b027b3 100644 --- a/qiskit/quantum_info/operators/symplectic/clifford.py +++ b/qiskit/quantum_info/operators/symplectic/clifford.py @@ -72,7 +72,9 @@ class Clifford(BaseOperator, AdjointMixin, Operation): be obtained by calling the :meth:`to_dict` method. This representation is also used if a Clifford object is printed as in the following example - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit from qiskit.quantum_info import Clifford diff --git a/qiskit/quantum_info/operators/symplectic/pauli.py b/qiskit/quantum_info/operators/symplectic/pauli.py index 759c618b140..298a0d7cd7e 100644 --- a/qiskit/quantum_info/operators/symplectic/pauli.py +++ b/qiskit/quantum_info/operators/symplectic/pauli.py @@ -142,7 +142,9 @@ class initialization (``Pauli('-iXYZ')``). A ``Pauli`` object can be For example - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import Pauli diff --git a/qiskit/quantum_info/operators/symplectic/pauli_list.py b/qiskit/quantum_info/operators/symplectic/pauli_list.py index 02f9a78052b..af2a0ed9407 100644 --- a/qiskit/quantum_info/operators/symplectic/pauli_list.py +++ b/qiskit/quantum_info/operators/symplectic/pauli_list.py @@ -54,7 +54,10 @@ class PauliList(BasePauli, LinearMixin, GroupMixin): For example, - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: reset import numpy as np @@ -93,7 +96,10 @@ class PauliList(BasePauli, LinearMixin, GroupMixin): operator which accepts integer, lists, or slices for selecting subsets of PauliList. If integer is given, it returns Pauli not PauliList. - .. code-block:: + .. plot:: + :include-source: + :nofigs: + :context: pauli_list = PauliList(["XX", "ZZ", "IZ"]) print("Integer: ", repr(pauli_list[1])) @@ -544,7 +550,9 @@ def sort(self, weight: bool = False, phase: bool = False) -> PauliList: Consider sorting all a random ordering of all 2-qubit Paulis - .. code-block:: + .. plot:: + :include-source: + :nofigs: from numpy.random import shuffle from qiskit.quantum_info.operators import PauliList @@ -595,7 +603,9 @@ def unique(self, return_index: bool = False, return_counts: bool = False) -> Pau **Example** - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info.operators import PauliList @@ -1214,7 +1224,9 @@ def group_commuting(self, qubit_wise: bool = False) -> list[PauliList]: qubit_wise (bool): whether the commutation rule is applied to the whole operator, or on a per-qubit basis. For example: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: >>> from qiskit.quantum_info import PauliList >>> op = PauliList(["XX", "YY", "IZ", "ZZ"]) diff --git a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py index e8e19bd7af5..34e524348bf 100644 --- a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +++ b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py @@ -69,7 +69,9 @@ class SparsePauliOp(LinearOp): configure this by passing ``np.ndarray`` with a different dtype. For example, a parameterized :class:`SparsePauliOp` can be made as follows: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: >>> import numpy as np >>> from qiskit.circuit import ParameterVector @@ -530,7 +532,9 @@ def argsort(self, weight: bool = False): Here is an example of how to use SparsePauliOp argsort. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.quantum_info import SparsePauliOp @@ -599,7 +603,9 @@ def sort(self, weight: bool = False): Here is an example of how to use SparsePauliOp sort. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.quantum_info import SparsePauliOp @@ -792,7 +798,9 @@ def from_list( can be constructed as - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import SparsePauliOp @@ -858,7 +866,9 @@ def from_sparse_list( can be constructed as - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import SparsePauliOp @@ -1063,7 +1073,9 @@ def group_commuting(self, qubit_wise: bool = False) -> list[SparsePauliOp]: qubit_wise (bool): whether the commutation rule is applied to the whole operator, or on a per-qubit basis. For example: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: >>> from qiskit.quantum_info import SparsePauliOp >>> op = SparsePauliOp.from_list([("XX", 2), ("YY", 1), ("IZ",2j), ("ZZ",1j)]) diff --git a/qiskit/quantum_info/states/densitymatrix.py b/qiskit/quantum_info/states/densitymatrix.py index 33fb937780a..875a67baacf 100644 --- a/qiskit/quantum_info/states/densitymatrix.py +++ b/qiskit/quantum_info/states/densitymatrix.py @@ -443,7 +443,9 @@ def probabilities( with :math:`\\rho_1=|+\\rangle\\!\\langle+|`, :math:`\\rho_0=|0\\rangle\\!\\langle0|`. - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import DensityMatrix @@ -470,7 +472,9 @@ def probabilities( We can also permute the order of qubits in the ``qargs`` list to change the qubit position in the probabilities output - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import DensityMatrix @@ -647,7 +651,9 @@ def to_dict(self, decimals: None | int = None) -> dict: The ket-form of a 2-qubit density matrix :math:`rho = |-\rangle\!\langle -|\otimes |0\rangle\!\langle 0|` - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import DensityMatrix @@ -666,7 +672,9 @@ def to_dict(self, decimals: None | int = None) -> dict: For non-qubit subsystems the integer range can go from 0 to 9. For example in a qutrit system - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.quantum_info import DensityMatrix @@ -687,7 +695,9 @@ def to_dict(self, decimals: None | int = None) -> dict: following example is for a 20-dimensional system consisting of a qubit and 10-dimensional qudit. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.quantum_info import DensityMatrix diff --git a/qiskit/quantum_info/states/stabilizerstate.py b/qiskit/quantum_info/states/stabilizerstate.py index 4da5808ebfa..5fb9859ad8d 100644 --- a/qiskit/quantum_info/states/stabilizerstate.py +++ b/qiskit/quantum_info/states/stabilizerstate.py @@ -34,7 +34,9 @@ class StabilizerState(QuantumState): Stabilizer simulator using the convention from reference [1]. Based on the internal class :class:`~qiskit.quantum_info.Clifford`. - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit from qiskit.quantum_info import StabilizerState, Pauli @@ -63,7 +65,9 @@ class StabilizerState(QuantumState): Given a list of stabilizers, :meth:`qiskit.quantum_info.StabilizerState.from_stabilizer_list` returns a state stabilized by the list - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import StabilizerState diff --git a/qiskit/quantum_info/states/statevector.py b/qiskit/quantum_info/states/statevector.py index 1265d677abe..2bbaf4e3c55 100644 --- a/qiskit/quantum_info/states/statevector.py +++ b/qiskit/quantum_info/states/statevector.py @@ -536,7 +536,9 @@ def probabilities( Consider a 2-qubit product state :math:`|\\psi\\rangle=|+\\rangle\\otimes|0\\rangle`. - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import Statevector @@ -563,7 +565,9 @@ def probabilities( We can also permute the order of qubits in the ``qargs`` list to change the qubit position in the probabilities output - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import Statevector @@ -787,7 +791,9 @@ def to_dict(self, decimals: None | int = None) -> dict: The ket-form of a 2-qubit statevector :math:`|\psi\rangle = |-\rangle\otimes |0\rangle` - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.quantum_info import Statevector @@ -801,7 +807,9 @@ def to_dict(self, decimals: None | int = None) -> dict: For non-qubit subsystems the integer range can go from 0 to 9. For example in a qutrit system - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.quantum_info import Statevector @@ -820,7 +828,9 @@ def to_dict(self, decimals: None | int = None) -> dict: following example is for a 20-dimensional system consisting of a qubit and 10-dimensional qudit. - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.quantum_info import Statevector diff --git a/qiskit/transpiler/__init__.py b/qiskit/transpiler/__init__.py index 1b3a3841e94..e0c8d02cabf 100644 --- a/qiskit/transpiler/__init__.py +++ b/qiskit/transpiler/__init__.py @@ -85,7 +85,9 @@ preset pass manager you can use the :func:`~.generate_preset_pass_manager` function to easily generate one. For example: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit.providers.fake_provider import GenericBackendV2 @@ -103,7 +105,9 @@ also add initial logical optimization prior to routing, you would do something like (building off the previous example): -.. code-block:: python +.. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.providers.fake_provider import GenericBackendV2 @@ -205,7 +209,9 @@ For example, to construct a simple :class:`~.Target` object, one can iteratively add descriptions of the instructions it supports: -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit.circuit import Parameter, Measure from qiskit.transpiler import Target, InstructionProperties @@ -521,7 +527,9 @@ and non-gate operations. The allowed instructions for a given backend can be found by querying the :class:`~.Target` for the devices: -.. code-block:: +.. plot:: + :include-source: + :nofigs: from qiskit.providers.fake_provider import GenericBackendV2 backend = GenericBackendV2(5) @@ -558,6 +566,7 @@ .. plot:: :include-source: + :context: reset from qiskit import transpile from qiskit import QuantumCircuit @@ -579,7 +588,10 @@ A few things to highlight. First, the circuit has gotten longer with respect to the original. This can be verified by checking the depth of both circuits: -.. code-block:: +.. plot:: + :include-source: + :nofigs: + :context: print('Original depth:', qc.depth(), 'Decomposed Depth:', qc_basis.depth()) @@ -596,7 +608,9 @@ 1. If A swap gate is not a native gate and must be decomposed this requires three CNOT gates: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.providers.fake_provider import GenericBackendV2 backend = GenericBackendV2(5) diff --git a/qiskit/transpiler/passes/calibration/rx_builder.py b/qiskit/transpiler/passes/calibration/rx_builder.py index 8543badc128..7dfeb56c68b 100644 --- a/qiskit/transpiler/passes/calibration/rx_builder.py +++ b/qiskit/transpiler/passes/calibration/rx_builder.py @@ -37,7 +37,9 @@ class RXCalibrationBuilder(CalibrationBuilder): It is recommended to place this pass in the post-optimization stage of a passmanager. A simple demo: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.providers.fake_provider import GenericBackendV2 from qiskit.transpiler import PassManager, PassManagerConfig diff --git a/qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py b/qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py index b1e976f91f7..7f0be5337d2 100644 --- a/qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +++ b/qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py @@ -52,7 +52,9 @@ class Commuting2qGateRouter(TransformationPass): To do this we use a line swap strategy for qubits 0, 1, 3, and 4 defined it in terms of virtual qubits 0, 1, 2, and 3. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit from qiskit.circuit.library import PauliEvolutionGate diff --git a/qiskit/transpiler/passes/scheduling/padding/pad_delay.py b/qiskit/transpiler/passes/scheduling/padding/pad_delay.py index b61b5ae5c83..56027a66dad 100644 --- a/qiskit/transpiler/passes/scheduling/padding/pad_delay.py +++ b/qiskit/transpiler/passes/scheduling/padding/pad_delay.py @@ -25,7 +25,9 @@ class PadDelay(BasePadding): Consecutive delays will be merged in the output of this pass. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit from qiskit.transpiler import InstructionDurations diff --git a/qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py b/qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py index ab15e797893..bb31e5cc002 100644 --- a/qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py @@ -73,7 +73,9 @@ class SolovayKitaev(TransformationPass): Per default, the basis gate set is ``["t", "tdg", "h"]``: - .. code-block:: + .. plot:: + :include-source: + :nofigs: import numpy as np from qiskit.circuit import QuantumCircuit @@ -110,7 +112,9 @@ class SolovayKitaev(TransformationPass): For individual basis gate sets, the ``generate_basic_approximations`` function can be used: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit.synthesis import generate_basic_approximations from qiskit.transpiler.passes import SolovayKitaev diff --git a/qiskit/transpiler/preset_passmanagers/plugin.py b/qiskit/transpiler/preset_passmanagers/plugin.py index acacc2b55c9..ac3b2b618cc 100644 --- a/qiskit/transpiler/preset_passmanagers/plugin.py +++ b/qiskit/transpiler/preset_passmanagers/plugin.py @@ -314,7 +314,9 @@ def passmanager_stage_plugins(stage: str) -> Dict[str, PassManagerStagePlugin]: This function is useful for getting more information about a plugin: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: from qiskit.transpiler.preset_passmanagers.plugin import passmanager_stage_plugins routing_plugins = passmanager_stage_plugins('routing') diff --git a/qiskit/utils/parallel.py b/qiskit/utils/parallel.py index f87eeb81596..6ad21e538aa 100644 --- a/qiskit/utils/parallel.py +++ b/qiskit/utils/parallel.py @@ -147,7 +147,9 @@ def parallel_map( # pylint: disable=dangerous-default-value Examples: - .. code-block:: python + .. plot:: + :include-source: + :nofigs: import time from qiskit.utils import parallel_map diff --git a/qiskit/visualization/__init__.py b/qiskit/visualization/__init__.py index d11107f84b3..3fdaa9ffaa5 100644 --- a/qiskit/visualization/__init__.py +++ b/qiskit/visualization/__init__.py @@ -61,6 +61,7 @@ .. plot:: :include-source: + :context: reset from qiskit.visualization import plot_histogram @@ -85,6 +86,7 @@ hist = plot_histogram(data) hist.savefig('new_hist.png') + Counts Visualizations ===================== diff --git a/qiskit/visualization/pass_manager_visualization.py b/qiskit/visualization/pass_manager_visualization.py index 1cdc1e9214e..3fa9c9d1b97 100644 --- a/qiskit/visualization/pass_manager_visualization.py +++ b/qiskit/visualization/pass_manager_visualization.py @@ -56,7 +56,9 @@ def pass_manager_drawer(pass_manager, filename=None, style=None, raw=False): VisualizationError: If raw=True and filename=None. Example: - .. code-block:: + .. plot:: + :include-source: + :nofigs: from qiskit import QuantumCircuit from qiskit.transpiler import generate_preset_pass_manager @@ -131,7 +133,9 @@ def staged_pass_manager_drawer(pass_manager, filename=None, style=None, raw=Fals VisualizationError: If raw=True and filename=None. Example: - .. code-block:: + .. plot:: + :include-source: + :nofigs: %matplotlib inline from qiskit.providers.fake_provider import GenericBackendV2 diff --git a/qiskit/visualization/pulse_v2/events.py b/qiskit/visualization/pulse_v2/events.py index 74da24b1db2..8830d8e7a1d 100644 --- a/qiskit/visualization/pulse_v2/events.py +++ b/qiskit/visualization/pulse_v2/events.py @@ -20,7 +20,9 @@ The `ChannelEvents` class instance is created with the class method ``load_program``: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: event = ChannelEvents.load_program(sched, DriveChannel(0)) @@ -33,7 +35,9 @@ The grouped instructions are returned as an iterator by the corresponding method call: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: for t0, frame, instruction in event.get_waveforms(): ... @@ -59,7 +63,9 @@ Note that these instructions are not interchangeable and the order should be kept. For example: -.. code-block:: python +.. plot:: + :include-source: + :nofigs: sched1 = Schedule() sched1 = sched1.insert(0, ShiftPhase(-1.57, DriveChannel(0)) diff --git a/qiskit/visualization/pulse_v2/interface.py b/qiskit/visualization/pulse_v2/interface.py index 6feb4bc8333..9d781bd6e45 100644 --- a/qiskit/visualization/pulse_v2/interface.py +++ b/qiskit/visualization/pulse_v2/interface.py @@ -365,7 +365,9 @@ def draw( You can partially customize a preset stylesheet when initializing it. - .. code-block:: python + .. plot:: + :include-source: + :nofigs: my_style = { 'formatter.channel_scaling.drive': 5, From cc30af587171672728c4f3a25aefbd8bee8bbda5 Mon Sep 17 00:00:00 2001 From: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:51:47 -0500 Subject: [PATCH 4/5] Show missing type hints & inline class base class in API docs (#13483) * Show missing type hints & inline class values in API docs * Fix fmt, oops * Fix density matrix use of Circuit --- docs/conf.py | 15 ++++++--- qiskit/quantum_info/operators/channel/chi.py | 18 +++++------ qiskit/quantum_info/operators/channel/choi.py | 18 +++++------ qiskit/quantum_info/operators/channel/ptm.py | 18 +++++------ .../operators/channel/quantum_channel.py | 6 ++-- .../operators/channel/stinespring.py | 18 +++++------ .../quantum_info/operators/channel/superop.py | 14 +++----- qiskit/quantum_info/states/densitymatrix.py | 32 ++++++++++--------- qiskit/quantum_info/states/stabilizerstate.py | 13 ++++---- qiskit/quantum_info/states/statevector.py | 20 ++++++++---- 10 files changed, 93 insertions(+), 79 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 1c188de24be..3bd1fd6516d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,14 +102,21 @@ # documentation created by autosummary uses a template file (in autosummary in the templates path), # which likely overrides the autodoc defaults. +# These options impact when using `.. autoclass::` manually. +# They do not impact the `.. autosummary::` templates. +autodoc_default_options = { + "show-inheritance": True, +} + # Move type hints from signatures to the parameter descriptions (except in overload cases, where # that's not possible). autodoc_typehints = "description" -# Only add type hints from signature to description body if the parameter has documentation. The -# return type is always added to the description (if in the signature). -autodoc_typehints_description_target = "documented_params" - autoclass_content = "both" +# Some type hints are too long to be understandable. So, we set up aliases to be used instead. +autodoc_type_aliases = { + "EstimatorPubLike": "EstimatorPubLike", + "SamplerPubLike": "SamplerPubLike", +} autosummary_generate = True autosummary_generate_overwrite = False diff --git a/qiskit/quantum_info/operators/channel/chi.py b/qiskit/quantum_info/operators/channel/chi.py index ee0ddaa4538..f0cdd99d970 100644 --- a/qiskit/quantum_info/operators/channel/chi.py +++ b/qiskit/quantum_info/operators/channel/chi.py @@ -18,6 +18,8 @@ from __future__ import annotations import copy as _copy import math +from typing import TYPE_CHECKING + import numpy as np from qiskit import _numpy_compat @@ -31,6 +33,9 @@ from qiskit.quantum_info.operators.mixins import generate_apidocs from qiskit.quantum_info.operators.base_operator import BaseOperator +if TYPE_CHECKING: + from qiskit import circuit + class Chi(QuantumChannel): r"""Pauli basis Chi-matrix representation of a quantum channel. @@ -59,21 +64,16 @@ class Chi(QuantumChannel): def __init__( self, - data: QuantumCircuit | Instruction | BaseOperator | np.ndarray, + data: QuantumCircuit | circuit.instruction.Instruction | BaseOperator | np.ndarray, input_dims: int | tuple | None = None, output_dims: int | tuple | None = None, ): """Initialize a quantum channel Chi-matrix operator. Args: - data (QuantumCircuit or - Instruction or - BaseOperator or - matrix): data to initialize superoperator. - input_dims (tuple): the input subsystem dimensions. - [Default: None] - output_dims (tuple): the output subsystem dimensions. - [Default: None] + data: data to initialize superoperator. + input_dims: the input subsystem dimensions. + output_dims: the output subsystem dimensions. Raises: QiskitError: if input data is not an N-qubit channel or diff --git a/qiskit/quantum_info/operators/channel/choi.py b/qiskit/quantum_info/operators/channel/choi.py index 1c9579e4560..f49c9ee495d 100644 --- a/qiskit/quantum_info/operators/channel/choi.py +++ b/qiskit/quantum_info/operators/channel/choi.py @@ -18,6 +18,8 @@ from __future__ import annotations import copy as _copy import math +from typing import TYPE_CHECKING + import numpy as np from qiskit import _numpy_compat @@ -32,6 +34,9 @@ from qiskit.quantum_info.operators.mixins import generate_apidocs from qiskit.quantum_info.operators.base_operator import BaseOperator +if TYPE_CHECKING: + from qiskit import circuit + class Choi(QuantumChannel): r"""Choi-matrix representation of a Quantum Channel. @@ -64,21 +69,16 @@ class Choi(QuantumChannel): def __init__( self, - data: QuantumCircuit | Instruction | BaseOperator | np.ndarray, + data: QuantumCircuit | circuit.instruction.Instruction | BaseOperator | np.ndarray, input_dims: int | tuple | None = None, output_dims: int | tuple | None = None, ): """Initialize a quantum channel Choi matrix operator. Args: - data (QuantumCircuit or - Instruction or - BaseOperator or - matrix): data to initialize superoperator. - input_dims (tuple): the input subsystem dimensions. - [Default: None] - output_dims (tuple): the output subsystem dimensions. - [Default: None] + data: data to initialize superoperator. + input_dims: the input subsystem dimensions. + output_dims: the output subsystem dimensions. Raises: QiskitError: if input data cannot be initialized as a diff --git a/qiskit/quantum_info/operators/channel/ptm.py b/qiskit/quantum_info/operators/channel/ptm.py index 84db071121f..9a90a7c3a7a 100644 --- a/qiskit/quantum_info/operators/channel/ptm.py +++ b/qiskit/quantum_info/operators/channel/ptm.py @@ -18,6 +18,8 @@ from __future__ import annotations import copy as _copy import math +from typing import TYPE_CHECKING + import numpy as np from qiskit import _numpy_compat @@ -30,6 +32,9 @@ from qiskit.quantum_info.operators.mixins import generate_apidocs from qiskit.quantum_info.operators.base_operator import BaseOperator +if TYPE_CHECKING: + from qiskit import circuit + class PTM(QuantumChannel): r"""Pauli Transfer Matrix (PTM) representation of a Quantum Channel. @@ -67,21 +72,16 @@ class PTM(QuantumChannel): def __init__( self, - data: QuantumCircuit | Instruction | BaseOperator | np.ndarray, + data: QuantumCircuit | circuit.instruction.Instruction | BaseOperator | np.ndarray, input_dims: int | tuple | None = None, output_dims: int | tuple | None = None, ): """Initialize a PTM quantum channel operator. Args: - data (QuantumCircuit or - Instruction or - BaseOperator or - matrix): data to initialize superoperator. - input_dims (tuple): the input subsystem dimensions. - [Default: None] - output_dims (tuple): the output subsystem dimensions. - [Default: None] + data: data to initialize superoperator. + input_dims: the input subsystem dimensions. + output_dims: the output subsystem dimensions. Raises: QiskitError: if input data is not an N-qubit channel or diff --git a/qiskit/quantum_info/operators/channel/quantum_channel.py b/qiskit/quantum_info/operators/channel/quantum_channel.py index ff20feb5bf4..3c22fb705ea 100644 --- a/qiskit/quantum_info/operators/channel/quantum_channel.py +++ b/qiskit/quantum_info/operators/channel/quantum_channel.py @@ -53,9 +53,9 @@ def __init__( """Initialize a quantum channel Superoperator operator. Args: - data (array or list): quantum channel data array. - op_shape (OpShape): the operator shape of the channel. - num_qubits (int): the number of qubits if the channel is N-qubit. + data: quantum channel data array. + op_shape: the operator shape of the channel. + num_qubits: the number of qubits if the channel is N-qubit. Raises: QiskitError: if arguments are invalid. diff --git a/qiskit/quantum_info/operators/channel/stinespring.py b/qiskit/quantum_info/operators/channel/stinespring.py index 68bbf846d38..7200f382e3f 100644 --- a/qiskit/quantum_info/operators/channel/stinespring.py +++ b/qiskit/quantum_info/operators/channel/stinespring.py @@ -17,6 +17,8 @@ import copy import math from numbers import Number +from typing import TYPE_CHECKING + import numpy as np from qiskit.circuit.quantumcircuit import QuantumCircuit @@ -32,6 +34,9 @@ from qiskit.quantum_info.operators.mixins import generate_apidocs from qiskit.quantum_info.operators.base_operator import BaseOperator +if TYPE_CHECKING: + from qiskit import circuit + class Stinespring(QuantumChannel): r"""Stinespring representation of a quantum channel. @@ -64,21 +69,16 @@ class Stinespring(QuantumChannel): def __init__( self, - data: QuantumCircuit | Instruction | BaseOperator | np.ndarray, + data: QuantumCircuit | circuit.instruction.Instruction | BaseOperator | np.ndarray, input_dims: int | tuple | None = None, output_dims: int | tuple | None = None, ): """Initialize a quantum channel Stinespring operator. Args: - data (QuantumCircuit or - Instruction or - BaseOperator or - matrix): data to initialize superoperator. - input_dims (tuple): the input subsystem dimensions. - [Default: None] - output_dims (tuple): the output subsystem dimensions. - [Default: None] + data: data to initialize superoperator. + input_dims: the input subsystem dimensions. + output_dims: the output subsystem dimensions. Raises: QiskitError: if input data cannot be initialized as a diff --git a/qiskit/quantum_info/operators/channel/superop.py b/qiskit/quantum_info/operators/channel/superop.py index f07652e22d7..50f9ff9e2d3 100644 --- a/qiskit/quantum_info/operators/channel/superop.py +++ b/qiskit/quantum_info/operators/channel/superop.py @@ -33,6 +33,7 @@ from qiskit.quantum_info.operators.operator import Operator if TYPE_CHECKING: + from qiskit import circuit from qiskit.quantum_info.states.densitymatrix import DensityMatrix from qiskit.quantum_info.states.statevector import Statevector @@ -62,21 +63,16 @@ class SuperOp(QuantumChannel): def __init__( self, - data: QuantumCircuit | Instruction | BaseOperator | np.ndarray, + data: QuantumCircuit | circuit.instruction.Instruction | BaseOperator | np.ndarray, input_dims: tuple | None = None, output_dims: tuple | None = None, ): """Initialize a quantum channel Superoperator operator. Args: - data (QuantumCircuit or - Instruction or - BaseOperator or - matrix): data to initialize superoperator. - input_dims (tuple): the input subsystem dimensions. - [Default: None] - output_dims (tuple): the output subsystem dimensions. - [Default: None] + data: data to initialize superoperator. + input_dims: the input subsystem dimensions. + output_dims: the output subsystem dimensions. Raises: QiskitError: if input data cannot be initialized as a diff --git a/qiskit/quantum_info/states/densitymatrix.py b/qiskit/quantum_info/states/densitymatrix.py index 875a67baacf..29170e75dec 100644 --- a/qiskit/quantum_info/states/densitymatrix.py +++ b/qiskit/quantum_info/states/densitymatrix.py @@ -17,6 +17,8 @@ from __future__ import annotations import copy as _copy from numbers import Number +from typing import TYPE_CHECKING + import numpy as np from qiskit import _numpy_compat @@ -37,27 +39,27 @@ from qiskit._accelerate.pauli_expval import density_expval_pauli_no_x, density_expval_pauli_with_x from qiskit.quantum_info.states.statevector import Statevector +if TYPE_CHECKING: + from qiskit import circuit + class DensityMatrix(QuantumState, TolerancesMixin): """DensityMatrix class""" def __init__( self, - data: np.ndarray | list | QuantumCircuit | Instruction | QuantumState, + data: np.ndarray | list | QuantumCircuit | circuit.instruction.Instruction | QuantumState, dims: int | tuple | list | None = None, ): """Initialize a density matrix object. Args: - data (np.ndarray or list or matrix_like or QuantumCircuit or - qiskit.circuit.Instruction): - A statevector, quantum instruction or an object with a ``to_operator`` or + data: A statevector, quantum instruction or an object with a ``to_operator`` or ``to_matrix`` method from which the density matrix can be constructed. If a vector the density matrix is constructed as the projector of that vector. If a quantum instruction, the density matrix is constructed by assuming all qubits are initialized in the zero state. - dims (int or tuple or list): Optional. The subsystem dimension - of the state (See additional information). + dims: The subsystem dimension of the state (See additional information). Raises: QiskitError: if input data is not valid. @@ -303,19 +305,17 @@ def _multiply(self, other): def evolve( self, - other: Operator | QuantumChannel | Instruction | QuantumCircuit, + other: Operator | QuantumChannel | circuit.instruction.Instruction | QuantumCircuit, qargs: list[int] | None = None, ) -> DensityMatrix: """Evolve a quantum state by an operator. Args: - other (Operator or QuantumChannel - or Instruction or Circuit): The operator to evolve by. - qargs (list): a list of QuantumState subsystem positions to apply - the operator on. + other: The operator to evolve by. + qargs: a list of QuantumState subsystem positions to apply the operator on. Returns: - DensityMatrix: the output density matrix. + The output density matrix. Raises: QiskitError: if the operator dimension does not match the @@ -602,7 +602,9 @@ def from_int(i: int, dims: int | tuple | list) -> DensityMatrix: return DensityMatrix(state, dims=dims) @classmethod - def from_instruction(cls, instruction: Instruction | QuantumCircuit) -> DensityMatrix: + def from_instruction( + cls, instruction: circuit.instruction.Instruction | QuantumCircuit + ) -> DensityMatrix: """Return the output density matrix of an instruction. The statevector is initialized in the state :math:`|{0,\\ldots,0}\\rangle` of @@ -610,10 +612,10 @@ def from_instruction(cls, instruction: Instruction | QuantumCircuit) -> DensityM by the input instruction, and the output statevector returned. Args: - instruction (qiskit.circuit.Instruction or QuantumCircuit): instruction or circuit + instruction: instruction or circuit Returns: - DensityMatrix: the final density matrix. + The final density matrix. Raises: QiskitError: if the instruction contains invalid instructions for diff --git a/qiskit/quantum_info/states/stabilizerstate.py b/qiskit/quantum_info/states/stabilizerstate.py index 5fb9859ad8d..b6bc8243b40 100644 --- a/qiskit/quantum_info/states/stabilizerstate.py +++ b/qiskit/quantum_info/states/stabilizerstate.py @@ -17,6 +17,7 @@ from __future__ import annotations from collections.abc import Collection +from typing import TYPE_CHECKING import numpy as np @@ -28,6 +29,9 @@ from qiskit.quantum_info.states.quantum_state import QuantumState from qiskit.circuit import QuantumCircuit, Instruction +if TYPE_CHECKING: + from qiskit import circuit + class StabilizerState(QuantumState): """StabilizerState class. @@ -83,17 +87,14 @@ class StabilizerState(QuantumState): def __init__( self, - data: StabilizerState | Clifford | Pauli | QuantumCircuit | Instruction, + data: StabilizerState | Clifford | Pauli | QuantumCircuit | circuit.instruction.Instruction, validate: bool = True, ): """Initialize a StabilizerState object. Args: - data (StabilizerState or Clifford or Pauli or QuantumCircuit or - qiskit.circuit.Instruction): - Data from which the stabilizer state can be constructed. - validate (boolean): validate that the stabilizer state data is - a valid Clifford. + data: Data from which the stabilizer state can be constructed. + validate: validate that the stabilizer state data is a valid Clifford. """ # Initialize from another StabilizerState diff --git a/qiskit/quantum_info/states/statevector.py b/qiskit/quantum_info/states/statevector.py index 2bbaf4e3c55..087d942cba4 100644 --- a/qiskit/quantum_info/states/statevector.py +++ b/qiskit/quantum_info/states/statevector.py @@ -18,6 +18,7 @@ import math import re from numbers import Number +from typing import TYPE_CHECKING import numpy as np @@ -37,27 +38,34 @@ expval_pauli_with_x, ) +if TYPE_CHECKING: + from qiskit import circuit + class Statevector(QuantumState, TolerancesMixin): """Statevector class""" def __init__( self, - data: np.ndarray | list | Statevector | Operator | QuantumCircuit | Instruction, + data: ( + np.ndarray + | list + | Statevector + | Operator + | QuantumCircuit + | circuit.instruction.Instruction + ), dims: int | tuple | list | None = None, ): """Initialize a statevector object. Args: - data (np.array or list or Statevector or Operator or QuantumCircuit or - qiskit.circuit.Instruction): - Data from which the statevector can be constructed. This can be either a complex + data: Data from which the statevector can be constructed. This can be either a complex vector, another statevector, a ``Operator`` with only one column or a ``QuantumCircuit`` or ``Instruction``. If the data is a circuit or instruction, the statevector is constructed by assuming that all qubits are initialized to the zero state. - dims (int or tuple or list): Optional. The subsystem dimension of - the state (See additional information). + dims: The subsystem dimension of the state (See additional information). Raises: QiskitError: if input data is not valid. From 8e2aaad6518e6354780174a593dcc559553443ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:49:40 -0500 Subject: [PATCH 5/5] Bump indexmap from 2.6.0 to 2.7.0 (#13513) Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.6.0 to 2.7.0. - [Changelog](https://github.com/indexmap-rs/indexmap/blob/master/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.6.0...2.7.0) --- updated-dependencies: - dependency-name: indexmap dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b1bbde626b5..2170ee3a994 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -576,9 +576,9 @@ checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.0", diff --git a/Cargo.toml b/Cargo.toml index 52a9471497b..14b2504000a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ license = "Apache-2.0" # Each crate can add on specific features freely as it inherits. [workspace.dependencies] bytemuck = "1.20" -indexmap.version = "2.6.0" +indexmap.version = "2.7.0" hashbrown.version = "0.14.5" num-bigint = "0.4" num-complex = "0.4"