From c6bacb1677d034737496f513eb33cd4c82ec7568 Mon Sep 17 00:00:00 2001 From: nate stemen Date: Wed, 2 Oct 2024 11:30:32 -0700 Subject: [PATCH 1/2] move class init docstrings to class docstring --- docs/source/apidoc.md | 2 +- mitiq/executor/executor.py | 16 ++--- mitiq/interface/mitiq_qiskit/transpiler.py | 9 +-- mitiq/observable/observable.py | 8 +-- mitiq/observable/pauli.py | 77 +++++++++++----------- mitiq/pec/types/types.py | 56 ++++++++-------- mitiq/zne/inference.py | 32 ++++----- 7 files changed, 90 insertions(+), 110 deletions(-) diff --git a/docs/source/apidoc.md b/docs/source/apidoc.md index e9e5fe65ad..b489a3f6d9 100644 --- a/docs/source/apidoc.md +++ b/docs/source/apidoc.md @@ -133,7 +133,6 @@ See Ref. {cite}`Czarnik_2021_Quantum` for more details on these methods. :members: ``` - #### Learning-based PEC ```{eval-rst} @@ -383,6 +382,7 @@ See Ref. {cite}`Czarnik_2021_Quantum` for more details on these methods. .. automodule:: mitiq.interface.mitiq_pyquil.conversions :members: ``` + #### Qibo Conversions ```{eval-rst} diff --git a/mitiq/executor/executor.py b/mitiq/executor/executor.py index 7ace20c78c..3dcef180ef 100644 --- a/mitiq/executor/executor.py +++ b/mitiq/executor/executor.py @@ -57,6 +57,13 @@ class Executor: """Tool for efficiently scheduling/executing quantum programs and storing the results. + + Args: + executor: A function which inputs a program and outputs a + ``mitiq.QuantumResult``, or inputs a sequence of programs and + outputs a sequence of ``mitiq.QuantumResult`` s. + max_batch_size: Maximum number of programs that can be sent in a + single batch (if the executor is batched). """ def __init__( @@ -64,15 +71,6 @@ def __init__( executor: Callable[[Union[QPROGRAM, Sequence[QPROGRAM]]], Any], max_batch_size: int = 75, ) -> None: - """Initializes an Executor. - - Args: - executor: A function which inputs a program and outputs a - ``mitiq.QuantumResult``, or inputs a sequence of programs and - outputs a sequence of ``mitiq.QuantumResult`` s. - max_batch_size: Maximum number of programs that can be sent in a - single batch (if the executor is batched). - """ self._executor = executor executor_annotation = inspect.getfullargspec(executor).annotations diff --git a/mitiq/interface/mitiq_qiskit/transpiler.py b/mitiq/interface/mitiq_qiskit/transpiler.py index 32e72efd2a..1a966d291d 100644 --- a/mitiq/interface/mitiq_qiskit/transpiler.py +++ b/mitiq/interface/mitiq_qiskit/transpiler.py @@ -37,14 +37,12 @@ class ApplyMitiqLayout(TransformationPass): # type: ignore qubits by applying the Layout given in `property_set`. Requires either of passes to set/select Layout, e.g. `SetLayout`, `TrivialLayout`. Assumes the Layout has full physical qubits. + + Args: + new_qregs: The new quantum registers for the circuit. """ def __init__(self, new_qregs: List[QuantumRegister]) -> None: - """ApplyMitiqLayout constructor. - - Args: - new_qregs: The new quantum registers for the circuit. - """ super().__init__() self._new_qregs = new_qregs @@ -104,7 +102,6 @@ class ClearLayout(TransformationPass): # type: ignore """Clears the layout of the DAGCircuit""" def __init__(self) -> None: - """ClearLayout""" super().__init__() def run(self, dag: DAGCircuit) -> None: diff --git a/mitiq/observable/observable.py b/mitiq/observable/observable.py index 09661e29ab..ce7d978bc5 100644 --- a/mitiq/observable/observable.py +++ b/mitiq/observable/observable.py @@ -20,15 +20,11 @@ class Observable: """A quantum observable typically used to compute its mitigated expectation value. + Args: + paulis: PauliStrings used to define the observable. """ def __init__(self, *paulis: PauliString) -> None: - """Initializes an `Observable` with :class:`.PauliString` objects. - - Args: - paulis: PauliStrings used to define the observable. - - """ self._paulis = _combine_duplicate_pauli_strings(paulis) self._groups: List[PauliStringCollection] self._ngroups: int diff --git a/mitiq/observable/pauli.py b/mitiq/observable/pauli.py index 56d4e3a960..6ab5f4fa48 100644 --- a/mitiq/observable/pauli.py +++ b/mitiq/observable/pauli.py @@ -18,9 +18,23 @@ class PauliString: - """A `PauliString` is a (tensor) product of single-qubit Pauli gates I, X, - Y, and Z, with a leading (real or complex) coefficient. `PauliString`s can - be measured in any `mitiq.QPROGRAM`. + """A ``PauliString`` is a (tensor) product of single-qubit Pauli gates + :math:`I, X, Y`, and :math:`Z`, with a leading (real or complex) + coefficient. ``PauliString`` objects can be measured in any + ``mitiq.QPROGRAM``. + + Initialize a PauliString. + + Args: + spec: String specifier of the PauliString. Should only contain + characters 'I', 'X', 'Y', and 'Z'. + coeff: Coefficient of the PauliString. + support: Qubits the ``spec`` acts on, if provided. + + Examples: + >>> PauliString(spec="IXY") # X(1)*Y(2) + >>> PauliString(spec="ZZ", coeff=-0.5) # -0.5*Z(0)*Z(1) + >>> PauliString(spec="XZ", support=(10, 17)) # X(10)*Z(17) """ _string_to_gate_map = {"I": cirq.I, "X": cirq.X, "Y": cirq.Y, "Z": cirq.Z} @@ -31,19 +45,6 @@ def __init__( coeff: complex = 1.0, support: Optional[Sequence[int]] = None, ) -> None: - """Initialize a PauliString. - - Args: - spec: String specifier of the PauliString. Should only contain - characters 'I', 'X', 'Y', and 'Z'. - coeff: Coefficient of the PauliString. - support: Qubits the ``spec`` acts on, if provided. - - Examples: - >>> PauliString(spec="IXY") # X(1)*Y(2) - >>> PauliString(spec="ZZ", coeff=-0.5) # -0.5*Z(0)*Z(1) - >>> PauliString(spec="XZ", support=(10, 17)) # X(10)*Z(17) - """ if not set(spec).issubset(set(self._string_to_gate_map.keys())): raise ValueError( f"One or more invalid characters in spec {spec}. Valid " @@ -181,34 +182,32 @@ def __repr__(self) -> str: class PauliStringCollection: """A collection of PauliStrings that qubit-wise commute and so can be measured with a single circuit. + + Args: + paulis: PauliStrings to add to the collection. + check_precondition: If True, raises an error if some of the + ``PauliString`` objects do not qubit-wise commute. + + Example: + >>> pcol = PauliStringCollection( + >>> PauliString(spec="X"), + >>> PauliString(spec="IZ", coeff=-2.2) + >>> ) + >>> print(pcol) # X(0) + (-2.2+0j)*Z(1) + >>> print(pcol.support()) # {0, 1} + >>> + >>> # XZ qubit-wise commutes with X(0) and Z(1), so can be added. + >>> print(pcol.can_add(PauliString(spec="XZ"))) # True. + >>> pcol.add(PauliString(spec="XZ")) + >>> print(pcol) # X(0) + (-2.2+0j)*Z(1) + X(0)*Z(1) + >>> + >>> # Z(0) doesn't qubit-wise commute with X(0), so can't be added. + >>> print(pcol.can_add(PauliString(spec="Z"))) # False. """ def __init__( self, *paulis: PauliString, check_precondition: bool = True ) -> None: - """Initializes a `PauliStringCollection`. - - Args: - paulis: PauliStrings to add to the collection. - check_precondition: If True, raises an error if some of the - `PauliString`s do not qubit-wise commute. - - Example: - >>> pcol = PauliStringCollection( - >>> PauliString(spec="X"), - >>> PauliString(spec="IZ", coeff=-2.2) - >>> ) - >>> print(pcol) # X(0) + (-2.2+0j)*Z(1) - >>> print(pcol.support()) # {0, 1} - >>> - >>> # XZ qubit-wise commutes with X(0) and Z(1), so can be added. - >>> print(pcol.can_add(PauliString(spec="XZ"))) # True. - >>> pcol.add(PauliString(spec="XZ")) - >>> print(pcol) # X(0) + (-2.2+0j)*Z(1) + X(0)*Z(1) - >>> - >>> # Z(0) doesn't qubit-wise commute with X(0), so can't be added. - >>> print(pcol.can_add(PauliString(spec="Z"))) # False. - """ self._paulis_by_weight: Dict[int, TCounter[PauliString]] = dict() self.add(*paulis, check_precondition=check_precondition) diff --git a/mitiq/pec/types/types.py b/mitiq/pec/types/types.py index 515b323a6a..8325aa33c2 100644 --- a/mitiq/pec/types/types.py +++ b/mitiq/pec/types/types.py @@ -24,7 +24,18 @@ class NoisyOperation: """An operation (or sequence of operations) which a noisy quantum computer - can actually implement.p + can actually implement. + + Args: + circuit: A short circuit which, when executed on a given noisy + quantum computer, generates a noisy channel. It typically + contains a single-gate or a short sequence of gates. + channel_matrix: Superoperator representation of the noisy channel + which is generated when executing the input ``circuit`` on the + noisy quantum computer. + + Raises: + TypeError: If ``ideal`` is not a ``QPROGRAM``. """ def __init__( @@ -32,19 +43,6 @@ def __init__( circuit: QPROGRAM, channel_matrix: Optional[npt.NDArray[np.complex64]] = None, ) -> None: - """Initializes a NoisyOperation. - - Args: - circuit: A short circuit which, when executed on a given noisy - quantum computer, generates a noisy channel. It typically - contains a single-gate or a short sequence of gates. - channel_matrix: Superoperator representation of the noisy channel - which is generated when executing the input ``circuit`` on the - noisy quantum computer. - - Raises: - TypeError: If ``ideal`` is not a ``QPROGRAM``. - """ self._native_circuit = deepcopy(circuit) try: @@ -135,6 +133,20 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class OperationRepresentation: """A decomposition (basis expansion) of an operation or sequence of operations in a basis of noisy, implementable operations. + + Args: + ideal: The ideal operation desired to be implemented. + basis_expansion: Representation of the ideal operation in a basis + of ``NoisyOperation`` objects. + is_qubit_dependent: If True, the representation + corresponds to the operation on the specific qubits defined in + ``ideal``. If False, the representation is valid for the same + gate even if acting on different qubits from those specified in + ``ideal``. + + Raises: + TypeError: If all keys of ``basis_expansion`` are not instances of + ``NoisyOperation`` objects. """ def __init__( @@ -144,22 +156,6 @@ def __init__( coeffs: List[float], is_qubit_dependent: bool = True, ) -> None: - """Initializes an OperationRepresentation. - - Args: - ideal: The ideal operation desired to be implemented. - basis_expansion: Representation of the ideal operation in a basis - of `NoisyOperation`s. - is_qubit_dependent: If True, the representation - corresponds to the operation on the specific qubits defined in - `ideal`. If False, the representation is valid for the same - gate even if acting on different qubits from those specified in - `ideal`. - - Raises: - TypeError: If all keys of `basis_expansion` are not instances of - `NoisyOperation`s. - """ if not all(isinstance(o, NoisyOperation) for o in noisy_operations): raise TypeError( "All elements of `noisy_operations` must be " diff --git a/mitiq/zne/inference.py b/mitiq/zne/inference.py index 87ebb1712c..409b08acf7 100644 --- a/mitiq/zne/inference.py +++ b/mitiq/zne/inference.py @@ -420,6 +420,19 @@ class BatchedFactory(Factory, ABC): Specific (non-adaptive) extrapolation algorithms are derived from this class by defining the `reduce` method. + + Args: + scale_factors: Sequence of noise scale factors at which expectation + values should be measured. + shot_list: Optional sequence of integers corresponding to the + number of samples taken for each expectation value. If this + argument is explicitly passed to the factory, it must have the + same length of scale_factors and the executor function must + accept "shots" as a valid keyword argument. + + Raises: + ValueError: If the number of scale factors is less than 2. + TypeError: If shot_list is provided and has any non-integer values. """ def __init__( @@ -427,21 +440,6 @@ def __init__( scale_factors: Sequence[float], shot_list: Optional[List[int]] = None, ) -> None: - """Constructs a BatchedFactory. - - Args: - scale_factors: Sequence of noise scale factors at which expectation - values should be measured. - shot_list: Optional sequence of integers corresponding to the - number of samples taken for each expectation value. If this - argument is explicitly passed to the factory, it must have the - same length of scale_factors and the executor function must - accept "shots" as a valid keyword argument. - - Raises: - ValueError: If the number of scale factors is less than 2. - TypeError: If shot_list is provided and has any non-integer values. - """ if len(scale_factors) < 2: raise ValueError("At least 2 scale factors are necessary.") @@ -805,7 +803,6 @@ def __init__( order: int, shot_list: Optional[List[int]] = None, ) -> None: - """Instantiates a new object of this Factory class.""" if order > len(scale_factors) - 1: raise ValueError( "The extrapolation order cannot exceed len(scale_factors) - 1." @@ -1127,7 +1124,6 @@ def __init__( avoid_log: bool = False, shot_list: Optional[List[int]] = None, ) -> None: - """Instantiate an new object of this Factory class.""" super(ExpFactory, self).__init__(scale_factors, shot_list) if not (asymptote is None or isinstance(asymptote, float)): raise ValueError( @@ -1247,7 +1243,6 @@ def __init__( avoid_log: bool = False, shot_list: Optional[List[int]] = None, ) -> None: - """Instantiates a new object of this Factory class.""" super(PolyExpFactory, self).__init__(scale_factors, shot_list) if not (asymptote is None or isinstance(asymptote, float)): raise ValueError( @@ -1519,7 +1514,6 @@ def __init__( avoid_log: bool = False, max_scale_factor: float = 6.0, ) -> None: - """Instantiate a new object of this Factory class.""" super(AdaExpFactory, self).__init__() if not (asymptote is None or isinstance(asymptote, float)): raise ValueError( From ef70732dca93bcd42a4d22ec8c6d635117c1cdfc Mon Sep 17 00:00:00 2001 From: nate stemen Date: Wed, 2 Oct 2024 14:22:14 -0700 Subject: [PATCH 2/2] remove redundant line --- mitiq/observable/pauli.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mitiq/observable/pauli.py b/mitiq/observable/pauli.py index 6ab5f4fa48..bf68af671a 100644 --- a/mitiq/observable/pauli.py +++ b/mitiq/observable/pauli.py @@ -23,8 +23,6 @@ class PauliString: coefficient. ``PauliString`` objects can be measured in any ``mitiq.QPROGRAM``. - Initialize a PauliString. - Args: spec: String specifier of the PauliString. Should only contain characters 'I', 'X', 'Y', and 'Z'.