From b9b85646eca5b8b27b8818f3fd9bc058a6903308 Mon Sep 17 00:00:00 2001 From: Lev Bishop <18673315+levbishop@users.noreply.github.com> Date: Sun, 25 Jun 2023 15:42:08 -0400 Subject: [PATCH 1/8] pylint enable used-before-assignment (#10335) --- pyproject.toml | 1 - qiskit/circuit/library/standard_gates/x.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f7f8ec4c9286..c24e90cdc702 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,6 @@ disable = [ "use-list-literal", "use-implicit-booleaness-not-comparison", "use-maxsplit-arg", - "used-before-assignment", ] enable = [ diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 659b6ffb4942..bbc5d91815c8 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -575,9 +575,9 @@ def qasm(self): # exporter code (low priority), or we would need to modify 'qelib1.inc' which would be # needlessly disruptive this late in OQ2's lifecycle. The current OQ2 exporter _always_ # outputs the `include 'qelib1.inc' line. ---Jake, 2022-11-21. + old_name = self.name + self.name = "c3sqrtx" try: - old_name = self.name - self.name = "c3sqrtx" return super().qasm() finally: self.name = old_name From d7a7146379ed6b069ddda8d20b05f95e5647ff10 Mon Sep 17 00:00:00 2001 From: Lev Bishop <18673315+levbishop@users.noreply.github.com> Date: Sun, 25 Jun 2023 15:43:28 -0400 Subject: [PATCH 2/8] Pylint: enable pointless-exception-statement (#10336) --- pyproject.toml | 1 - qiskit/pulse/transforms/alignments.py | 4 +++- qiskit/qpy/binary_io/schedules.py | 2 +- qiskit/quantum_info/operators/scalar_op.py | 2 +- qiskit/visualization/pulse_v2/plotters/matplotlib.py | 2 +- qiskit/visualization/timeline/layouts.py | 4 ++-- qiskit/visualization/timeline/plotters/matplotlib.py | 2 +- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c24e90cdc702..8b28ebb93c36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,6 @@ disable = [ "no-value-for-parameter", "non-ascii-name", "not-context-manager", - "pointless-exception-statement", "superfluous-parens", "unknown-option-value", "unexpected-keyword-arg", diff --git a/qiskit/pulse/transforms/alignments.py b/qiskit/pulse/transforms/alignments.py index c4cac6d4b782..d19def4f34b8 100644 --- a/qiskit/pulse/transforms/alignments.py +++ b/qiskit/pulse/transforms/alignments.py @@ -409,7 +409,9 @@ def align(self, schedule: Schedule) -> Schedule: _t_center = self.duration * self.func(ind + 1) _t0 = int(_t_center - 0.5 * child.duration) if _t0 < 0 or _t0 > self.duration: - PulseError("Invalid schedule position t=%d is specified at index=%d" % (_t0, ind)) + raise PulseError( + "Invalid schedule position t=%d is specified at index=%d" % (_t0, ind) + ) aligned.insert(_t0, child, inplace=True) return aligned diff --git a/qiskit/qpy/binary_io/schedules.py b/qiskit/qpy/binary_io/schedules.py index 3ca41722694d..6577e7cec3f8 100644 --- a/qiskit/qpy/binary_io/schedules.py +++ b/qiskit/qpy/binary_io/schedules.py @@ -421,7 +421,7 @@ def read_schedule_block(file_obj, version, metadata_deserializer=None): QiskitError: QPY version is earlier than block support. """ if version < 5: - QiskitError(f"QPY version {version} does not support ScheduleBlock.") + raise QiskitError(f"QPY version {version} does not support ScheduleBlock.") data = formats.SCHEDULE_BLOCK_HEADER._make( struct.unpack( diff --git a/qiskit/quantum_info/operators/scalar_op.py b/qiskit/quantum_info/operators/scalar_op.py index 22bce0ab7026..141189e01653 100644 --- a/qiskit/quantum_info/operators/scalar_op.py +++ b/qiskit/quantum_info/operators/scalar_op.py @@ -47,7 +47,7 @@ def __init__(self, dims=None, coeff=1): QiskitError: If the optional coefficient is invalid. """ if not isinstance(coeff, Number): - QiskitError(f"coeff {coeff} must be a number.") + raise QiskitError(f"coeff {coeff} must be a number.") self._coeff = coeff super().__init__(input_dims=dims, output_dims=dims) diff --git a/qiskit/visualization/pulse_v2/plotters/matplotlib.py b/qiskit/visualization/pulse_v2/plotters/matplotlib.py index d86e169901a3..e92a34189994 100644 --- a/qiskit/visualization/pulse_v2/plotters/matplotlib.py +++ b/qiskit/visualization/pulse_v2/plotters/matplotlib.py @@ -118,7 +118,7 @@ def draw(self): ) self.ax.add_patch(box) else: - VisualizationError( + raise VisualizationError( "Data {name} is not supported " "by {plotter}".format(name=data, plotter=self.__class__.__name__) ) diff --git a/qiskit/visualization/timeline/layouts.py b/qiskit/visualization/timeline/layouts.py index 7bd599fb7430..5c5737c6e1f4 100644 --- a/qiskit/visualization/timeline/layouts.py +++ b/qiskit/visualization/timeline/layouts.py @@ -79,7 +79,7 @@ def qreg_creg_ascending(bits: List[types.Bits]) -> List[types.Bits]: elif isinstance(bit, circuit.Clbit): cregs.append(bit) else: - VisualizationError(f"Unknown bit {bit} is provided.") + raise VisualizationError(f"Unknown bit {bit} is provided.") with warnings.catch_warnings(): warnings.simplefilter("ignore") @@ -109,7 +109,7 @@ def qreg_creg_descending(bits: List[types.Bits]) -> List[types.Bits]: elif isinstance(bit, circuit.Clbit): cregs.append(bit) else: - VisualizationError(f"Unknown bit {bit} is provided.") + raise VisualizationError(f"Unknown bit {bit} is provided.") qregs = sorted(qregs, key=lambda x: x.index, reverse=True) cregs = sorted(cregs, key=lambda x: x.index, reverse=True) diff --git a/qiskit/visualization/timeline/plotters/matplotlib.py b/qiskit/visualization/timeline/plotters/matplotlib.py index f71d72c5ef13..126d0981feda 100644 --- a/qiskit/visualization/timeline/plotters/matplotlib.py +++ b/qiskit/visualization/timeline/plotters/matplotlib.py @@ -131,7 +131,7 @@ def draw(self): self.ax.plot(xvals.repeat(len(offsets)), offsets, **data.styles) else: - VisualizationError( + raise VisualizationError( "Data {name} is not supported by {plotter}" "".format(name=data, plotter=self.__class__.__name__) ) From d67fc2c07a1191f90e2a9313c8487468b7e60ddb Mon Sep 17 00:00:00 2001 From: Junya Nakamura <47435718+junnaka51@users.noreply.github.com> Date: Mon, 26 Jun 2023 22:12:04 +0900 Subject: [PATCH 3/8] Deprecate pulse Call instruction (#10247) * deprecate pulse Call instruction * Update releasenotes/notes/deprecate-pulse-Call-instruction-538802d8fad7e257.yaml Co-authored-by: Naoki Kanazawa * delete spaces in the releasenote --------- Co-authored-by: Naoki Kanazawa --- qiskit/pulse/instructions/call.py | 6 ++++ ...lse-Call-instruction-538802d8fad7e257.yaml | 9 +++++ test/python/pulse/test_block.py | 3 +- test/python/pulse/test_builder.py | 15 ++++++--- test/python/pulse/test_instructions.py | 9 +++-- test/python/pulse/test_parameter_manager.py | 33 ++++++++++++------- test/python/pulse/test_transforms.py | 12 ++++--- 7 files changed, 63 insertions(+), 24 deletions(-) create mode 100644 releasenotes/notes/deprecate-pulse-Call-instruction-538802d8fad7e257.yaml diff --git a/qiskit/pulse/instructions/call.py b/qiskit/pulse/instructions/call.py index 05097ad5b798..49c9a6fe42c0 100644 --- a/qiskit/pulse/instructions/call.py +++ b/qiskit/pulse/instructions/call.py @@ -18,6 +18,7 @@ from qiskit.pulse.channels import Channel from qiskit.pulse.exceptions import PulseError from qiskit.pulse.instructions import instruction +from qiskit.utils.deprecation import deprecate_func class Call(instruction.Instruction): @@ -30,6 +31,11 @@ class Call(instruction.Instruction): # Prefix to use for auto naming. prefix = "call" + @deprecate_func( + since="0.25.0", + additional_msg="Instead, use the pulse builder function " + "qiskit.pulse.builder.call(subroutine) within an active building context.", + ) def __init__( self, subroutine, diff --git a/releasenotes/notes/deprecate-pulse-Call-instruction-538802d8fad7e257.yaml b/releasenotes/notes/deprecate-pulse-Call-instruction-538802d8fad7e257.yaml new file mode 100644 index 000000000000..6ed28e8e6a9d --- /dev/null +++ b/releasenotes/notes/deprecate-pulse-Call-instruction-538802d8fad7e257.yaml @@ -0,0 +1,9 @@ +--- +deprecations: + - | + The :class:`~qiskit.pulse.instructions.Call` has been deprecated and will + be removed in a future release. + Instead, use the `pulse builder + `_ + function :func:`~qiskit.pulse.builder.call` + within an active building context. diff --git a/test/python/pulse/test_block.py b/test/python/pulse/test_block.py index 90441ef917d5..20ec95713a2c 100644 --- a/test/python/pulse/test_block.py +++ b/test/python/pulse/test_block.py @@ -678,7 +678,8 @@ def test_nested_parametrized_instructions(self): test_waveform = pulse.Constant(100, self.amp0) param_sched = pulse.Schedule(pulse.Play(test_waveform, self.d0)) - call_inst = pulse.instructions.Call(param_sched) + with self.assertWarns(DeprecationWarning): + call_inst = pulse.instructions.Call(param_sched) sub_block = pulse.ScheduleBlock() sub_block += call_inst diff --git a/test/python/pulse/test_builder.py b/test/python/pulse/test_builder.py index 1d7f09d5df78..55ff16e2f367 100644 --- a/test/python/pulse/test_builder.py +++ b/test/python/pulse/test_builder.py @@ -212,7 +212,8 @@ def test_scheduler_settings(self): inst_map.add("x", (0,), test_x_sched) ref_sched = pulse.Schedule() - ref_sched += pulse.instructions.Call(test_x_sched) + with self.assertWarns(DeprecationWarning): + ref_sched += pulse.instructions.Call(test_x_sched) x_qc = circuit.QuantumCircuit(2) x_qc.x(0) @@ -961,7 +962,8 @@ def test_call(self): reference += instructions.Delay(20, d1) ref_sched = pulse.Schedule() - ref_sched += pulse.instructions.Call(reference) + with self.assertWarns(DeprecationWarning): + ref_sched += pulse.instructions.Call(reference) with pulse.build() as schedule: with pulse.align_right(): @@ -981,7 +983,8 @@ def test_call_circuit(self): reference = inst_map.get("u1", (0,), 0.0) ref_sched = pulse.Schedule() - ref_sched += pulse.instructions.Call(reference) + with self.assertWarns(DeprecationWarning): + ref_sched += pulse.instructions.Call(reference) u1_qc = circuit.QuantumCircuit(2) u1_qc.append(circuit.library.U1Gate(0.0), [0]) @@ -1009,7 +1012,8 @@ def test_call_circuit_with_cregs(self): reference = compiler.schedule(reference_qc, self.backend) ref_sched = pulse.Schedule() - ref_sched += pulse.instructions.Call(reference) + with self.assertWarns(DeprecationWarning): + ref_sched += pulse.instructions.Call(reference) self.assertScheduleEqual(schedule, ref_sched) @@ -1041,7 +1045,8 @@ def test_call_gate_and_circuit(self): ) reference = pulse.Schedule() - reference += pulse.instructions.Call(h_reference) + with self.assertWarns(DeprecationWarning): + reference += pulse.instructions.Call(h_reference) reference += cx_reference reference += measure_reference << reference.duration diff --git a/test/python/pulse/test_instructions.py b/test/python/pulse/test_instructions.py index c41e0a12080c..892d7f49d033 100644 --- a/test/python/pulse/test_instructions.py +++ b/test/python/pulse/test_instructions.py @@ -361,14 +361,16 @@ def setUp(self): def test_call(self): """Test basic call instruction.""" - call = instructions.Call(subroutine=self.subroutine) + with self.assertWarns(DeprecationWarning): + call = instructions.Call(subroutine=self.subroutine) self.assertEqual(call.duration, 10) self.assertEqual(call.subroutine, self.subroutine) def test_parameterized_call(self): """Test call instruction with parameterized subroutine.""" - call = instructions.Call(subroutine=self.function) + with self.assertWarns(DeprecationWarning): + call = instructions.Call(subroutine=self.function) self.assertTrue(call.is_parameterized()) self.assertEqual(len(call.parameters), 2) @@ -393,7 +395,8 @@ def test_assign_parameters_to_call(self): def test_call_initialize_with_parameter(self): """Test call instruction with parameterized subroutine with initial dict.""" init_dict = {self.param1: 0.1, self.param2: 0.5} - call = instructions.Call(subroutine=self.function, value_dict=init_dict) + with self.assertWarns(DeprecationWarning): + call = instructions.Call(subroutine=self.function, value_dict=init_dict) with pulse.build() as ref_sched: pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0)) diff --git a/test/python/pulse/test_parameter_manager.py b/test/python/pulse/test_parameter_manager.py index 4ffa519c0a8a..d395461ac3b1 100644 --- a/test/python/pulse/test_parameter_manager.py +++ b/test/python/pulse/test_parameter_manager.py @@ -87,7 +87,8 @@ def setUp(self): long_schedule += subroutine long_schedule += pulse.ShiftPhase(self.phi2, self.d2) long_schedule += pulse.Play(self.parametric_waveform2, self.d2) - long_schedule += pulse.Call(sched) + with self.assertWarns(DeprecationWarning): + long_schedule += pulse.Call(sched) long_schedule += pulse.Play(self.parametric_waveform3, self.d3) long_schedule += pulse.Acquire( @@ -152,7 +153,8 @@ def test_get_parameter_from_call(self): sched = pulse.Schedule() sched += pulse.ShiftPhase(self.phi1, self.d1) - test_obj = pulse.Call(subroutine=sched) + with self.assertWarns(DeprecationWarning): + test_obj = pulse.Call(subroutine=sched) visitor = ParameterGetter() visitor.visit(test_obj) @@ -257,7 +259,8 @@ def test_set_parameter_to_call(self): sched = pulse.Schedule() sched += pulse.ShiftPhase(self.phi1, self.d1) - test_obj = pulse.Call(subroutine=sched) + with self.assertWarns(DeprecationWarning): + test_obj = pulse.Call(subroutine=sched) value_dict = {self.phi1: 1.57, self.ch1: 2} @@ -267,7 +270,8 @@ def test_set_parameter_to_call(self): ref_sched = pulse.Schedule() ref_sched += pulse.ShiftPhase(1.57, pulse.DriveChannel(2)) - ref_obj = pulse.Call(subroutine=ref_sched) + with self.assertWarns(DeprecationWarning): + ref_obj = pulse.Call(subroutine=ref_sched) self.assertEqual(assigned, ref_obj) @@ -309,7 +313,8 @@ def test_nested_assignment_partial_bind(self): subroutine += pulse.Play(self.parametric_waveform1, self.d1) nested_block = pulse.ScheduleBlock() - nested_block += pulse.Call(subroutine=subroutine) + with self.assertWarns(DeprecationWarning): + nested_block += pulse.Call(subroutine=subroutine) test_obj = pulse.ScheduleBlock() test_obj += nested_block @@ -451,7 +456,8 @@ def test_set_parameter_to_complex_schedule(self): ref_obj += subroutine ref_obj += pulse.ShiftPhase(2.0, pulse.DriveChannel(2)) ref_obj += pulse.Play(pulse.Gaussian(125, 0.3, 25), pulse.DriveChannel(2)) - ref_obj += pulse.Call(sched) + with self.assertWarns(DeprecationWarning): + ref_obj += pulse.Call(sched) ref_obj += pulse.Play(pulse.Gaussian(150, 0.4, 25), pulse.DriveChannel(4)) ref_obj += pulse.Acquire( @@ -503,12 +509,14 @@ def test_parameters_from_subroutine(self): # from call instruction program_layer1 = pulse.Schedule() - program_layer1 += pulse.instructions.Call(program_layer0) + with self.assertWarns(DeprecationWarning): + program_layer1 += pulse.instructions.Call(program_layer0) self.assertEqual(program_layer1.get_parameters("amp")[0], param1) # from nested call instruction program_layer2 = pulse.Schedule() - program_layer2 += pulse.instructions.Call(program_layer1) + with self.assertWarns(DeprecationWarning): + program_layer2 += pulse.instructions.Call(program_layer1) self.assertEqual(program_layer2.get_parameters("amp")[0], param1) def test_assign_parameter_to_subroutine(self): @@ -522,13 +530,15 @@ def test_assign_parameter_to_subroutine(self): # to call instruction program_layer1 = pulse.Schedule() - program_layer1 += pulse.instructions.Call(program_layer0) + with self.assertWarns(DeprecationWarning): + program_layer1 += pulse.instructions.Call(program_layer0) target = program_layer1.assign_parameters({param1: 0.1}, inplace=False) self.assertEqual(inline_subroutines(target), reference) # to nested call instruction program_layer2 = pulse.Schedule() - program_layer2 += pulse.instructions.Call(program_layer1) + with self.assertWarns(DeprecationWarning): + program_layer2 += pulse.instructions.Call(program_layer1) target = program_layer2.assign_parameters({param1: 0.1}, inplace=False) self.assertEqual(inline_subroutines(target), reference) @@ -546,7 +556,8 @@ def test_assign_parameter_to_subroutine_parameter(self): main_prog = pulse.Schedule() pdict = {param1: param_sub1 + param_sub2} - main_prog += pulse.instructions.Call(subroutine, value_dict=pdict) + with self.assertWarns(DeprecationWarning): + main_prog += pulse.instructions.Call(subroutine, value_dict=pdict) # parameter is overwritten by parameters self.assertEqual(len(main_prog.parameters), 2) diff --git a/test/python/pulse/test_transforms.py b/test/python/pulse/test_transforms.py index 50d6cbd94498..d2d4b3567860 100644 --- a/test/python/pulse/test_transforms.py +++ b/test/python/pulse/test_transforms.py @@ -907,12 +907,14 @@ def test_remove_subroutines(self): subroutine = pulse.Schedule() subroutine.insert(0, pulse.Delay(20, d0), inplace=True) - subroutine.insert(20, pulse.instructions.Call(nested_routine), inplace=True) + with self.assertWarns(DeprecationWarning): + subroutine.insert(20, pulse.instructions.Call(nested_routine), inplace=True) subroutine.insert(50, pulse.Delay(10, d0), inplace=True) main_program = pulse.Schedule() main_program.insert(0, pulse.Delay(10, d0), inplace=True) - main_program.insert(30, pulse.instructions.Call(subroutine), inplace=True) + with self.assertWarns(DeprecationWarning): + main_program.insert(30, pulse.instructions.Call(subroutine), inplace=True) target = transforms.inline_subroutines(main_program) @@ -932,7 +934,8 @@ def test_call_in_nested_schedule(self): subroutine.insert(10, pulse.Delay(10, d0), inplace=True) nested_sched = pulse.Schedule() - nested_sched.insert(0, pulse.instructions.Call(subroutine), inplace=True) + with self.assertWarns(DeprecationWarning): + nested_sched.insert(0, pulse.instructions.Call(subroutine), inplace=True) main_sched = pulse.Schedule() main_sched.insert(0, nested_sched, inplace=True) @@ -956,7 +959,8 @@ def test_call_in_nested_block(self): subroutine.append(pulse.Delay(10, d0), inplace=True) nested_block = pulse.ScheduleBlock() - nested_block.append(pulse.instructions.Call(subroutine), inplace=True) + with self.assertWarns(DeprecationWarning): + nested_block.append(pulse.instructions.Call(subroutine), inplace=True) main_block = pulse.ScheduleBlock() main_block.append(nested_block, inplace=True) From 7b8203f9c2c29afb9e63398dd8a6727754991947 Mon Sep 17 00:00:00 2001 From: thspreetham98 Date: Mon, 26 Jun 2023 19:28:14 +0530 Subject: [PATCH 4/8] 10129 pauli doctring (#10334) * 10129: update pauli docstrings * base pauli docstring update * linting errors fixed --- .../operators/symplectic/base_pauli.py | 16 ++++++++++------ .../quantum_info/operators/symplectic/pauli.py | 17 +++++++++++------ .../operators/symplectic/pauli_list.py | 16 ++++++++++------ 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/qiskit/quantum_info/operators/symplectic/base_pauli.py b/qiskit/quantum_info/operators/symplectic/base_pauli.py index 1a7e8ae1bd26..3ff449c3feb6 100644 --- a/qiskit/quantum_info/operators/symplectic/base_pauli.py +++ b/qiskit/quantum_info/operators/symplectic/base_pauli.py @@ -227,20 +227,24 @@ def commutes(self, other, qargs=None): return a_dot_b == b_dot_a def evolve(self, other, qargs=None, frame="h"): - r"""Heisenberg picture evolution of a Pauli by a Clifford. + r"""Performs either Heisenberg (default) or Schrödinger picture + evolution of the Pauli by a Clifford and returns the evolved Pauli. - This returns the Pauli :math:`P^\prime = C^\dagger.P.C`. + Schrödinger picture evolution can be chosen by passing parameter ``frame='s'``. + This option yields a faster calculation. - By choosing the parameter frame='s', this function returns the Schrödinger evolution of the Pauli - :math:`P^\prime = C.P.C^\dagger`. This option yields a faster calculation. + Heisenberg picture evolves the Pauli as :math:`P^\prime = C^\dagger.P.C`. + + Schrödinger picture evolves the Pauli as :math:`P^\prime = C.P.C^\dagger`. Args: other (BasePauli or QuantumCircuit): The Clifford circuit to evolve by. qargs (list): a list of qubits to apply the Clifford to. - frame (string): 'h' for Heisenberg or 's' for Schrödinger framework. + frame (string): ``'h'`` for Heisenberg or ``'s'`` for Schrödinger framework. Returns: - BasePauli: the Pauli :math:`C^\dagger.P.C`. + BasePauli: the Pauli :math:`C^\dagger.P.C` (Heisenberg picture) + or the Pauli :math:`C.P.C^\dagger` (Schrödinger picture). Raises: QiskitError: if the Clifford number of qubits and ``qargs`` don't match. diff --git a/qiskit/quantum_info/operators/symplectic/pauli.py b/qiskit/quantum_info/operators/symplectic/pauli.py index f8b9c1bffcef..bd0d78bc90af 100644 --- a/qiskit/quantum_info/operators/symplectic/pauli.py +++ b/qiskit/quantum_info/operators/symplectic/pauli.py @@ -567,20 +567,25 @@ def anticommutes(self, other, qargs=None): return np.logical_not(self.commutes(other, qargs=qargs)) def evolve(self, other, qargs=None, frame="h"): - r"""Heisenberg picture evolution of a Pauli by a Clifford. + r"""Performs either Heisenberg (default) or Schrödinger picture + evolution of the Pauli by a Clifford and returns the evolved Pauli. - This returns the Pauli :math:`P^\prime = C^\dagger.P.C`. + Schrödinger picture evolution can be chosen by passing parameter ``frame='s'``. + This option yields a faster calculation. - By choosing the parameter frame='s', this function returns the Schrödinger evolution of the Pauli - :math:`P^\prime = C.P.C^\dagger`. This option yields a faster calculation. + Heisenberg picture evolves the Pauli as :math:`P^\prime = C^\dagger.P.C`. + + Schrödinger picture evolves the Pauli as :math:`P^\prime = C.P.C^\dagger`. Args: other (Pauli or Clifford or QuantumCircuit): The Clifford operator to evolve by. qargs (list): a list of qubits to apply the Clifford to. - frame (string): 'h' for Heisenberg or 's' for Schrödinger framework. + frame (string): ``'h'`` for Heisenberg (default) or ``'s'`` for + Schrödinger framework. Returns: - Pauli: the Pauli :math:`C^\dagger.P.C`. + Pauli: the Pauli :math:`C^\dagger.P.C` (Heisenberg picture) + or the Pauli :math:`C.P.C^\dagger` (Schrödinger picture). Raises: QiskitError: if the Clifford number of qubits and qargs don't match. diff --git a/qiskit/quantum_info/operators/symplectic/pauli_list.py b/qiskit/quantum_info/operators/symplectic/pauli_list.py index 80b95bfa4c0e..9e282b4a34cd 100644 --- a/qiskit/quantum_info/operators/symplectic/pauli_list.py +++ b/qiskit/quantum_info/operators/symplectic/pauli_list.py @@ -901,20 +901,24 @@ def _commutes_with_all(self, other, anti=False): return inds def evolve(self, other, qargs=None, frame="h"): - r"""Evolve the Pauli by a Clifford. + r"""Performs either Heisenberg (default) or Schrödinger picture + evolution of the Pauli by a Clifford and returns the evolved Pauli. - This returns the Pauli :math:`P^\prime = C.P.C^\dagger`. + Schrödinger picture evolution can be chosen by passing parameter ``frame='s'``. + This option yields a faster calculation. - By choosing the parameter frame='s', this function returns the Schrödinger evolution of the Pauli - :math:`P^\prime = C.P.C^\dagger`. This option yields a faster calculation. + Heisenberg picture evolves the Pauli as :math:`P^\prime = C^\dagger.P.C`. + + Schrödinger picture evolves the Pauli as :math:`P^\prime = C.P.C^\dagger`. Args: other (Pauli or Clifford or QuantumCircuit): The Clifford operator to evolve by. qargs (list): a list of qubits to apply the Clifford to. - frame (string): 'h' for Heisenberg or 's' for Schrödinger framework. + frame (string): ``'h'`` for Heisenberg (default) or ``'s'`` for Schrödinger framework. Returns: - Pauli: the Pauli :math:`C.P.C^\dagger`. + PauliList: the Pauli :math:`C^\dagger.P.C` (Heisenberg picture) + or the Pauli :math:`C.P.C^\dagger` (Schrödinger picture). Raises: QiskitError: if the Clifford number of qubits and qargs don't match. From 14ba1659834d9c1695464ad7482c4d3045e00e3e Mon Sep 17 00:00:00 2001 From: Cristian Emiliano Godinez Ramirez <57567043+EmilianoG-byte@users.noreply.github.com> Date: Mon, 26 Jun 2023 18:06:16 +0200 Subject: [PATCH 5/8] fix typo in real_amplitude.py (#10347) --- qiskit/circuit/library/n_local/real_amplitudes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/circuit/library/n_local/real_amplitudes.py b/qiskit/circuit/library/n_local/real_amplitudes.py index 2838c898f2da..5e3f1ba671f9 100644 --- a/qiskit/circuit/library/n_local/real_amplitudes.py +++ b/qiskit/circuit/library/n_local/real_amplitudes.py @@ -24,7 +24,7 @@ class RealAmplitudes(TwoLocal): The ``RealAmplitudes`` circuit is a heuristic trial wave function used as Ansatz in chemistry applications or classification circuits in machine learning. The circuit consists of - of alternating layers of :math:`Y` rotations and :math:`CX` entanglements. The entanglement + alternating layers of :math:`Y` rotations and :math:`CX` entanglements. The entanglement pattern can be user-defined or selected from a predefined set. It is called ``RealAmplitudes`` since the prepared quantum states will only have real amplitudes, the complex part is always 0. From 791a45433a21a5604086bfcd96d804433b8aecfe Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Mon, 26 Jun 2023 17:25:47 +0100 Subject: [PATCH 6/8] Temporarily pin `scipy<1.11` in CI (#10348) The newest Scipy on Windows seems to have caused a convergence error in some of the Weyl-chamber code. This pins Scipy temporarily while we resolve that issue. --- constraints.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/constraints.txt b/constraints.txt index 67572fd19305..026d0e551b6a 100644 --- a/constraints.txt +++ b/constraints.txt @@ -10,3 +10,8 @@ qiskit-aer==0.12.0 # tests to flake. See https://github.com/Qiskit/qiskit-terra/issues/10305, # remove pin when resolving that. numpy<1.25 + +# Scipy 1.11 seems to have caused an instability in the Weyl coordinates +# eigensystem code for one of the test cases. See +# https://github.com/Qiskit/qiskit-terra/issues/10345 for current details. +scipy<1.11 From c6938529b13b3fd1a4260745873f0bc28d038078 Mon Sep 17 00:00:00 2001 From: Simone Gasperini Date: Mon, 26 Jun 2023 20:18:24 +0200 Subject: [PATCH 7/8] Allow multiplication of SparsePauliOp and ParameterExpression (#10264) * Allow multiplication of SparsePauliOp and ParameterExpression * Add unit tests for SparsePauliOp and ParameterExpression multiplication * Add release note for the new feature --- .../operators/symplectic/sparse_pauli_op.py | 4 ++-- ...meter-multiplication-245173f0b232f59b.yaml | 15 +++++++++++++ .../symplectic/test_sparse_pauli_op.py | 22 +++++++++++++++---- 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/support-SparsePauliOp-Parameter-multiplication-245173f0b232f59b.yaml diff --git a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py index 503c29f94689..8ed37c400c9c 100644 --- a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +++ b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py @@ -366,8 +366,8 @@ def _add(self, other, qargs=None): return SparsePauliOp(paulis, coeffs, ignore_pauli_phase=True, copy=False) def _multiply(self, other): - if not isinstance(other, Number): - raise QiskitError("other is not a number") + if not isinstance(other, (Number, ParameterExpression)): + raise QiskitError("other is neither a Number nor a Parameter/ParameterExpression") if other == 0: # Check edge case that we deleted all Paulis # In this case we return an identity Pauli with a zero coefficient diff --git a/releasenotes/notes/support-SparsePauliOp-Parameter-multiplication-245173f0b232f59b.yaml b/releasenotes/notes/support-SparsePauliOp-Parameter-multiplication-245173f0b232f59b.yaml new file mode 100644 index 000000000000..a140e4aed629 --- /dev/null +++ b/releasenotes/notes/support-SparsePauliOp-Parameter-multiplication-245173f0b232f59b.yaml @@ -0,0 +1,15 @@ +features: + - | + Adds support for multiplication of :class:`.SparsePauliOp` objects + with :class:`.Parameter` objects by using the * operator, for example:: + + from qiskit.circuit import Parameter + from qiskit.quantum_info import SparsePauliOp + + param = Parameter("a") + op = SparsePauliOp("X") + param * op + +fixes: + - | + Fixes issue `#10185 `. diff --git a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py index e9c5d6741bd2..afceedada3e3 100644 --- a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py +++ b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py @@ -20,7 +20,7 @@ from ddt import ddt from qiskit import QiskitError -from qiskit.circuit import Parameter, ParameterVector +from qiskit.circuit import ParameterExpression, Parameter, ParameterVector from qiskit.circuit.parametertable import ParameterView from qiskit.quantum_info.operators import Operator, Pauli, PauliList, PauliTable, SparsePauliOp from qiskit.test import QiskitTestCase @@ -588,14 +588,28 @@ def test_sub_qargs(self, num_qubits): self.assertEqual(value, target) np.testing.assert_array_equal(op.paulis.phase, np.zeros(op.size)) - @combine(num_qubits=[1, 2, 3], value=[0, 1, 1j, -3 + 4.4j, np.int64(2)], param=[None, "a"]) + @combine( + num_qubits=[1, 2, 3], + value=[ + 0, + 1, + 1j, + -3 + 4.4j, + np.int64(2), + Parameter("x"), + 0 * Parameter("x"), + (-2 + 1.7j) * Parameter("x"), + ], + param=[None, "a"], + ) def test_mul(self, num_qubits, value, param): """Test * method for {num_qubits} qubits and value {value}.""" spp_op = self.random_spp_op(num_qubits, 2**num_qubits, param) target = value * spp_op.to_matrix() op = value * spp_op value_mat = op.to_matrix() - if value != 0 and param is not None: + has_parameters = isinstance(value, ParameterExpression) or param is not None + if value != 0 and has_parameters: value_mat = bind_parameters_to_one(value_mat) target = bind_parameters_to_one(target) if value == 0: @@ -606,7 +620,7 @@ def test_mul(self, num_qubits, value, param): target = spp_op.to_matrix() * value op = spp_op * value value_mat = op.to_matrix() - if value != 0 and param is not None: + if value != 0 and has_parameters: value_mat = bind_parameters_to_one(value_mat) target = bind_parameters_to_one(target) if value == 0: From d9763523d45a747fd882a7e79cc44c02b5058916 Mon Sep 17 00:00:00 2001 From: Lev Bishop <18673315+levbishop@users.noreply.github.com> Date: Tue, 27 Jun 2023 07:46:40 -0400 Subject: [PATCH 8/8] pylint: enable consider-using-from-import (#10337) --- pyproject.toml | 1 - test/python/quantum_info/test_synthesis.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8b28ebb93c36..fc603f57a652 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,6 @@ disable = [ "consider-using-dict-items", "consider-using-enumerate", "consider-using-f-string", - "consider-using-from-import", "modified-iterating-list", "nested-min-max", "no-member", diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 099ffb87191e..58074995c7a1 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -77,7 +77,7 @@ ) from qiskit.quantum_info.synthesis.ion_decompose import cnot_rxx_decompose -import qiskit.quantum_info.synthesis.qsd as qsd +from qiskit.quantum_info.synthesis import qsd from qiskit.test import QiskitTestCase