• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qiskit / qiskit / 13540158629

26 Feb 2025 09:01AM UTC coverage: 87.854% (-0.7%) from 88.599%
13540158629

Pull #12814

github

web-flow
Merge f02a7b9b8 into 7169f6db0
Pull Request #12814: Light Cone Transpiler Pass

79 of 81 new or added lines in 2 files covered. (97.53%)

2576 existing lines in 133 files now uncovered.

77200 of 87873 relevant lines covered (87.85%)

339322.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.55
/qiskit/primitives/base/validation.py
1
# This code is part of Qiskit.
2
#
3
# (C) Copyright IBM 2022.
4
#
5
# This code is licensed under the Apache License, Version 2.0. You may
6
# obtain a copy of this license in the LICENSE.txt file in the root directory
7
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8
#
9
# Any modifications or derivative works of this code must retain this
10
# copyright notice, and modified files need to carry a notice indicating
11
# that they have been altered from the originals.
12

13
"""Primitive validation methods.
14

15
Note that these are not intended to be part of the public API of base primitives
16
but are here for backwards compatibility with deprecated functions.
17
"""
18

19
from __future__ import annotations
1✔
20

21
from collections.abc import Sequence
1✔
22
import typing
1✔
23
import numpy as np
1✔
24

25
from qiskit.circuit import QuantumCircuit, ControlFlowOp, Measure
1✔
26
from qiskit.quantum_info.operators import SparsePauliOp
1✔
27
from qiskit.quantum_info.operators.base_operator import BaseOperator
1✔
28

29
from ..utils import init_observable
1✔
30

31
if typing.TYPE_CHECKING:
1✔
32
    from qiskit.opflow import PauliSumOp
×
33

34

35
def _validate_estimator_args(
1✔
36
    circuits: Sequence[QuantumCircuit] | QuantumCircuit,
37
    observables: Sequence[BaseOperator | PauliSumOp | str] | BaseOperator | PauliSumOp | str,
38
    parameter_values: Sequence[Sequence[float]] | Sequence[float] | float | None = None,
39
) -> tuple[tuple[QuantumCircuit], tuple[BaseOperator], tuple[tuple[float]]]:
40
    """Validate run arguments for a reference Estimator.
41

42
    Args:
43
        circuits: one or more circuit objects.
44
        observables: one or more observable objects.
45
        parameter_values: concrete parameters to be bound.
46

47
    Returns:
48
        The formatted arguments ``(circuits, observables, parameter_values)``.
49

50
    Raises:
51
        TypeError: If input arguments are invalid types.
52
        ValueError: if input arguments are invalid values.
53
    """
54
    # Singular validation
55
    circuits = _validate_circuits(circuits)
1✔
56
    observables = _validate_observables(observables)
1✔
57
    parameter_values = _validate_parameter_values(
1✔
58
        parameter_values,
59
        default=[()] * len(circuits),
60
    )
61

62
    # Cross-validation
63
    _cross_validate_circuits_parameter_values(circuits, parameter_values)
1✔
64
    _cross_validate_circuits_observables(circuits, observables)
1✔
65

66
    return circuits, observables, parameter_values
1✔
67

68

69
def _validate_sampler_args(
1✔
70
    circuits: Sequence[QuantumCircuit] | QuantumCircuit,
71
    parameter_values: Sequence[Sequence[float]] | Sequence[float] | float | None = None,
72
) -> tuple[tuple[QuantumCircuit], tuple[BaseOperator], tuple[tuple[float]]]:
73
    """Validate run arguments for a reference Sampler.
74

75
    Args:
76
        circuits: one or more circuit objects.
77
        parameter_values: concrete parameters to be bound.
78

79
    Returns:
80
        The formatted arguments ``(circuits, parameter_values)``.
81

82
    Raises:
83
        TypeError: If input arguments are invalid types.
84
        ValueError: if input arguments are invalid values.
85
    """
86
    # Singular validation
87
    circuits = _validate_circuits(circuits, requires_measure=True)
1✔
88
    parameter_values = _validate_parameter_values(
1✔
89
        parameter_values,
90
        default=[()] * len(circuits),
91
    )
92

93
    # Cross-validation
94
    _cross_validate_circuits_parameter_values(circuits, parameter_values)
1✔
95

96
    return circuits, parameter_values
1✔
97

98

99
def _validate_circuits(
1✔
100
    circuits: Sequence[QuantumCircuit] | QuantumCircuit,
101
    requires_measure: bool = False,
102
) -> tuple[QuantumCircuit, ...]:
103
    if isinstance(circuits, QuantumCircuit):
1✔
104
        circuits = (circuits,)
1✔
105
    elif not isinstance(circuits, Sequence) or not all(
1✔
106
        isinstance(cir, QuantumCircuit) for cir in circuits
107
    ):
108
        raise TypeError("Invalid circuits, expected Sequence[QuantumCircuit].")
1✔
109
    elif not isinstance(circuits, tuple):
1✔
110
        circuits = tuple(circuits)
1✔
111
    if len(circuits) == 0:
1✔
112
        raise ValueError("No circuits were provided.")
1✔
113

114
    if requires_measure:
1✔
115
        for i, circuit in enumerate(circuits):
1✔
116
            if circuit.num_clbits == 0:
1✔
117
                raise ValueError(
1✔
118
                    f"The {i}-th circuit does not have any classical bit. "
119
                    "Sampler requires classical bits, plus measurements "
120
                    "on the desired qubits."
121
                )
122
            if not _has_measure(circuit):
1✔
123
                raise ValueError(
1✔
124
                    f"The {i}-th circuit does not have Measure instruction. "
125
                    "Without measurements, the circuit cannot be sampled from."
126
                )
127
    return circuits
1✔
128

129

130
def _validate_parameter_values(
1✔
131
    parameter_values: Sequence[Sequence[float]] | Sequence[float] | float | None,
132
    default: Sequence[Sequence[float]] | Sequence[float] | None = None,
133
) -> tuple[tuple[float, ...], ...]:
134
    # Allow optional (if default)
135
    if parameter_values is None:
1✔
136
        if default is None:
1✔
137
            raise ValueError("No default `parameter_values`, optional input disallowed.")
1✔
138
        parameter_values = default
1✔
139

140
    # Support numpy ndarray
141
    if isinstance(parameter_values, np.ndarray):
1✔
142
        parameter_values = parameter_values.tolist()
1✔
143
    elif isinstance(parameter_values, Sequence):
1✔
144
        parameter_values = tuple(
1✔
145
            vector.tolist() if isinstance(vector, np.ndarray) else vector
146
            for vector in parameter_values
147
        )
148

149
    # Allow single value
150
    if _isreal(parameter_values):
1✔
151
        parameter_values = ((parameter_values,),)
1✔
152
    elif isinstance(parameter_values, Sequence) and not any(
1✔
153
        isinstance(vector, Sequence) for vector in parameter_values
154
    ):
155
        parameter_values = (parameter_values,)
1✔
156

157
    # Validation
158
    if (
1✔
159
        not isinstance(parameter_values, Sequence)
160
        or not all(isinstance(vector, Sequence) for vector in parameter_values)
161
        or not all(all(_isreal(value) for value in vector) for vector in parameter_values)
162
    ):
163
        raise TypeError("Invalid parameter values, expected Sequence[Sequence[float]].")
1✔
164

165
    return tuple(tuple(float(value) for value in vector) for vector in parameter_values)
1✔
166

167

168
def _validate_observables(
1✔
169
    observables: Sequence[BaseOperator | PauliSumOp | str] | BaseOperator | PauliSumOp | str,
170
) -> tuple[SparsePauliOp, ...]:
171
    if isinstance(observables, str) or not isinstance(observables, Sequence):
1✔
172
        observables = (observables,)
1✔
173
    if len(observables) == 0:
1✔
174
        raise ValueError("No observables were provided.")
1✔
175
    return tuple(init_observable(obs) for obs in observables)
1✔
176

177

178
def _cross_validate_circuits_parameter_values(
1✔
179
    circuits: tuple[QuantumCircuit, ...], parameter_values: tuple[tuple[float, ...], ...]
180
) -> None:
181
    if len(circuits) != len(parameter_values):
1✔
182
        raise ValueError(
1✔
183
            f"The number of circuits ({len(circuits)}) does not match "
184
            f"the number of parameter value sets ({len(parameter_values)})."
185
        )
186
    for i, (circuit, vector) in enumerate(zip(circuits, parameter_values)):
1✔
187
        if len(vector) != circuit.num_parameters:
1✔
188
            raise ValueError(
1✔
189
                f"The number of values ({len(vector)}) does not match "
190
                f"the number of parameters ({circuit.num_parameters}) for the {i}-th circuit."
191
            )
192

193

194
def _cross_validate_circuits_observables(
1✔
195
    circuits: tuple[QuantumCircuit, ...], observables: tuple[BaseOperator | PauliSumOp, ...]
196
) -> None:
197
    if len(circuits) != len(observables):
1✔
198
        raise ValueError(
×
199
            f"The number of circuits ({len(circuits)}) does not match "
200
            f"the number of observables ({len(observables)})."
201
        )
202
    for i, (circuit, observable) in enumerate(zip(circuits, observables)):
1✔
203
        if circuit.num_qubits != observable.num_qubits:
1✔
204
            raise ValueError(
1✔
205
                f"The number of qubits of the {i}-th circuit ({circuit.num_qubits}) does "
206
                f"not match the number of qubits of the {i}-th observable "
207
                f"({observable.num_qubits})."
208
            )
209

210

211
def _isint(obj: Sequence[Sequence[float]] | Sequence[float] | float) -> bool:
1✔
212
    """Check if object is int."""
213
    int_types = (int, np.integer)
1✔
214
    return isinstance(obj, int_types) and not isinstance(obj, bool)
1✔
215

216

217
def _isreal(obj: Sequence[Sequence[float]] | Sequence[float] | float) -> bool:
1✔
218
    """Check if object is a real number: int or float except ``±Inf`` and ``NaN``."""
219
    float_types = (float, np.floating)
1✔
220
    return _isint(obj) or isinstance(obj, float_types) and float("-Inf") < obj < float("Inf")
1✔
221

222

223
def _has_measure(circuit: QuantumCircuit) -> bool:
1✔
224
    for instruction in reversed(circuit):
1✔
225
        if isinstance(instruction.operation, Measure):
1✔
226
            return True
1✔
227
        elif isinstance(instruction.operation, ControlFlowOp):
1✔
228
            for block in instruction.operation.blocks:
1✔
229
                if _has_measure(block):
1✔
UNCOV
230
                    return True
×
231
    return False
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc