Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove deprecated legacy pulse builder commands #11191

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b7dd20c
deprecated calling gates directly within the pulse builder namespace
MozammilQ Nov 2, 2023
2b9c96c
modified tests
MozammilQ Nov 3, 2023
d86df4f
deprecated active_transpiler_settings, active_circuit_scheduler_setti…
MozammilQ Nov 3, 2023
de5d386
refactor related tests in test/python/transpiler/test_calibrationbuil…
MozammilQ Nov 3, 2023
5048457
added relese note
MozammilQ Nov 3, 2023
48baa23
edited release note
MozammilQ Nov 3, 2023
ff25a61
fixed sphinx error
MozammilQ Nov 3, 2023
0114361
fixed sphinx error
MozammilQ Nov 3, 2023
b8cdf05
changed version from 1.0.0 to 0.46.0
MozammilQ Nov 7, 2023
67f9cca
deprecated arguments default_transpiler_settings, default_circuit_sch…
MozammilQ Nov 7, 2023
a0f791b
deprecated QuantumCircuit type for argument target of qiskit.pulse.bu…
MozammilQ Nov 7, 2023
5fa35ea
altered docstrings
MozammilQ Nov 7, 2023
64d15c1
edited release note
MozammilQ Nov 7, 2023
0019525
altered release note
MozammilQ Nov 8, 2023
b4e6ae3
refactor code
MozammilQ Nov 15, 2023
c980a82
removed deprecated functions, and modified tests
MozammilQ Nov 16, 2023
5153d6e
altered a test
MozammilQ Nov 16, 2023
e02d0c9
modified test
MozammilQ Nov 19, 2023
573fa9a
This commit makrs the complete removal of deprecated functions, and t…
MozammilQ Nov 19, 2023
baf5136
removed deprecated arguments, modified tests, and altered docstrings
MozammilQ Nov 20, 2023
13cca4d
refactor docstrings
MozammilQ Nov 20, 2023
2c85078
refactor code
MozammilQ Nov 20, 2023
43ad34a
lint
MozammilQ Nov 20, 2023
c0734dd
refactor code
MozammilQ Nov 29, 2023
0f333bd
altered release note
MozammilQ Nov 30, 2023
35ffec1
removed circuit_scheduler_settings, with its property, setter and con…
MozammilQ Dec 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 35 additions & 19 deletions qiskit/pulse/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@
from qiskit.pulse.instructions import directives
from qiskit.pulse.schedule import Schedule, ScheduleBlock
from qiskit.pulse.transforms.alignments import AlignmentKind

from qiskit.utils.deprecation import deprecate_func

#: contextvars.ContextVar[BuilderContext]: active builder
BUILDER_CONTEXTVAR = contextvars.ContextVar("backend")
Expand Down Expand Up @@ -1197,6 +1197,7 @@ def _qubits_to_channels(*channels_or_qubits: Union[int, chans.Channel]) -> Set[c
return channels


@deprecate_func(since="1.0.0")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@deprecate_func(since="1.0.0")
@deprecate_func(since="0.46.0")

@mtreinish Is there any guide for deprecation? Do we need to open two PRs? One to https://github.com/Qiskit/qiskit/tree/stable/0.46 with deprecation warning and another one to main branch with code removal?

Copy link
Contributor

@ElePT ElePT Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you will need 2 PRs, one with the deprecation (to 0.46) and one with the removal (to 1.0 == main), and the deprecation warnings should say "since 0.46" (as suggested by @nkanazawa1989). In case you are considering it, I think that there's no need to close and re-open it against stable/0.46, we can merge it to main and backport it to 0.46. (now that I think about it, this might actually be the recommended course of action, because else we would have diverging histories, @mtreinish?). It would be a good idea to write this down and have a sort of "guide" we can refer people to, because I expect it to be confusing for many contributors.

Copy link
Member

@mtreinish mtreinish Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern we've been following is just opening a PR on stable/0.46 for the deprecation paired with a removal PR on main for 1.0.0. This was mostly done to minimize CI time, it's only 2 CI runs instead of 3 to deprecate and remove. They can also be pushed in parallel without any dependency between PRs.

But, I wouldn't say we're committed to that as a general requirement, doing both a deprecation to be backported to stable/0.46 followed by an immediate removal PR to main would also work fine. The only complication is for backport you'd need to use a comment to manually tell mergify to backport to stable/0.46. For example, leaving a comment like: @Mergifyio backport stable/0.46 after the PR merges. Using the stable backport potential tag in this case will trigger a backport to stable/0.45 which is incorrect for new deprecations.

In the interest of documenting this I pushed up #11205 to document the branching versioning strategy and all the general deprecation procedures around this. But I didn't put in specifics around how to handle PRs for this situation. I think we can updating CONTRIBUTING.md after #11205 merges if we feel more guidance is needed on the specifics around this. In general backporting and stable branch policy will be getting more complicated moving forward as we support > 1 stable branch at a time (this is just the first example of it).

def active_transpiler_settings() -> Dict[str, Any]:
"""Return the current active builder context's transpiler settings.

Expand All @@ -1223,6 +1224,7 @@ def active_transpiler_settings() -> Dict[str, Any]:
return dict(_active_builder().transpiler_settings)


@deprecate_func(since="1.0.0")
def active_circuit_scheduler_settings() -> Dict[str, Any]:
"""Return the current active builder context's circuit scheduler settings.

Expand Down Expand Up @@ -1507,6 +1509,7 @@ def general_transforms(alignment_context: AlignmentKind) -> ContextManager[None]
builder.append_subroutine(current)


@deprecate_func(since="1.0.0")
@contextmanager
def transpiler_settings(**settings) -> ContextManager[None]:
"""Set the currently active transpiler settings for this context.
Expand Down Expand Up @@ -2549,14 +2552,18 @@ def delay_qubits(duration: int, *qubits: Union[int, Iterable[int]]):


# Gate instructions
@deprecate_func(
since="1.0.0",
additional_msg="Instead use: ``backend.target['gate_name'][(qubit,)].calibration``",
)
def call_gate(gate: circuit.Gate, qubits: Tuple[int, ...], lazy: bool = True):
"""Call a gate and lazily schedule it to its corresponding
pulse instruction.

.. note::
Calling gates directly within the pulse builder namespace will be
deprecated in the future in favor of tight integration with a circuit
builder interface which is under development.
Calling gates directly within the pulse builder namespace has been
deprecated in favor of tight integration with a circuit
builder interface.

Examples:

Expand Down Expand Up @@ -2602,14 +2609,17 @@ def call_gate(gate: circuit.Gate, qubits: Tuple[int, ...], lazy: bool = True):
_active_builder().call_gate(gate, qubits, lazy=lazy)


@deprecate_func(
since="1.0.0", additional_msg="Instead use: ``backend.target['cx'][(qubit,)].calibration``"
)
def cx(control: int, target: int): # pylint: disable=invalid-name
"""Call a :class:`~qiskit.circuit.library.standard_gates.CXGate` on the
input physical qubits.

.. note::
Calling gates directly within the pulse builder namespace will be
deprecated in the future in favor of tight integration with a circuit
builder interface which is under development.
Calling gates directly within the pulse builder namespace has been
deprecated in favor of tight integration with a circuit
builder interface.

Examples:

Expand All @@ -2627,14 +2637,15 @@ def cx(control: int, target: int): # pylint: disable=invalid-name
call_gate(gates.CXGate(), (control, target))


@deprecate_func(since="1.0.0")
def u1(theta: float, qubit: int): # pylint: disable=invalid-name
"""Call a :class:`~qiskit.circuit.library.standard_gates.U1Gate` on the
input physical qubit.

.. note::
Calling gates directly within the pulse builder namespace will be
deprecated in the future in favor of tight integration with a circuit
builder interface which is under development.
Calling gates directly within the pulse builder namespace has been
deprecated in favor of tight integration with a circuit
builder interface.

Examples:

Expand All @@ -2654,14 +2665,15 @@ def u1(theta: float, qubit: int): # pylint: disable=invalid-name
call_gate(gates.U1Gate(theta), qubit)


@deprecate_func(since="1.0.0")
def u2(phi: float, lam: float, qubit: int): # pylint: disable=invalid-name
"""Call a :class:`~qiskit.circuit.library.standard_gates.U2Gate` on the
input physical qubit.

.. note::
Calling gates directly within the pulse builder namespace will be
deprecated in the future in favor of tight integration with a circuit
builder interface which is under development.
Calling gates directly within the pulse builder namespace has been
deprecated in favor of tight integration with a circuit
builder interface.

Examples:

Expand All @@ -2681,14 +2693,15 @@ def u2(phi: float, lam: float, qubit: int): # pylint: disable=invalid-name
call_gate(gates.U2Gate(phi, lam), qubit)


@deprecate_func(since="1.0.0")
def u3(theta: float, phi: float, lam: float, qubit: int): # pylint: disable=invalid-name
"""Call a :class:`~qiskit.circuit.library.standard_gates.U3Gate` on the
input physical qubit.

.. note::
Calling gates directly within the pulse builder namespace will be
deprecated in the future in favor of tight integration with a circuit
builder interface which is under development.
Calling gates directly within the pulse builder namespace has been
deprecated in favor of tight integration with a circuit
builder interface.

Examples:

Expand All @@ -2708,14 +2721,17 @@ def u3(theta: float, phi: float, lam: float, qubit: int): # pylint: disable=inv
call_gate(gates.U3Gate(theta, phi, lam), qubit)


@deprecate_func(
since="1.0.0", additional_msg="Instead use: ``backend.target['x'][(qubit,)].calibration``"
)
def x(qubit: int):
"""Call a :class:`~qiskit.circuit.library.standard_gates.XGate` on the
input physical qubit.

.. note::
Calling gates directly within the pulse builder namespace will be
deprecated in the future in favor of tight integration with a circuit
builder interface which is under development.
Calling gates directly within the pulse builder namespace has been
deprecated in favor of tight integration with a circuit
builder interface.

Examples:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
deprecations:
- |
Deprecated injecting circuit gate operation into the pulse context.

Deprecated
:func:`qiskit.pulse.builder.call_gate`,
:func:`qiskit.pulse.builder.cx`,
:func:`qiskit.pulse.builder.u1`,
:func:`qiskit.pulse.builder.u2`,
:func:`qiskit.pulse.builder.u3`,
:func:`qiskit.pulse.builder.x`

.. code-block:: python
# This example shows how to get pulse gate instructions.
from qiskit.providers.fake_provider import FakePerth
backend=FakePerth()
sched=backend.target['x'][(qubit,)].calibration

MozammilQ marked this conversation as resolved.
Show resolved Hide resolved
Deprecated
:func:`qiskit.pulse.builder.active_transpiler_settings`
:func:`qiskit.pulse.builder.active_circuit_scheduler_settings`
:func:`qiskit.pulse.builder.transpiler_settings`

Modified related tests in
:file:`test/python/pulse/test_builder.py`,
:file:`test/python/pulse/test_block.py`
:file:`test/python/pulse/test_builder_v2.py`
:file:`test/python/transpiler/test_calibrationbuilder.py`

3 changes: 2 additions & 1 deletion test/python/pulse/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,8 @@ def test_filter_channels_nested_block(self):
pulse.delay(5, self.d0)

with pulse.build(self.backend) as cx_blk:
pulse.cx(0, 1)
with self.assertWarns(DeprecationWarning):
pulse.cx(0, 1)

pulse.call(cx_blk)

Expand Down
74 changes: 46 additions & 28 deletions test/python/pulse/test_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,15 @@ def test_transpiler_settings(self):
twice_cx_qc.cx(0, 1)

with pulse.build(self.backend) as schedule:
with pulse.transpiler_settings(optimization_level=0):
builder.call(twice_cx_qc)
with self.assertWarns(DeprecationWarning):
with pulse.transpiler_settings(optimization_level=0):
builder.call(twice_cx_qc)
self.assertNotEqual(len(schedule.instructions), 0)

with pulse.build(self.backend) as schedule:
with pulse.transpiler_settings(optimization_level=3):
builder.call(twice_cx_qc)
with self.assertWarns(DeprecationWarning):
with pulse.transpiler_settings(optimization_level=3):
builder.call(twice_cx_qc)
self.assertEqual(len(schedule.instructions), 0)

def test_scheduler_settings(self):
Expand All @@ -219,9 +221,10 @@ def test_scheduler_settings(self):
x_qc.x(0)

with pulse.build(backend=self.backend) as schedule:
with pulse.transpiler_settings(basis_gates=["x"]):
with pulse.circuit_scheduler_settings(inst_map=inst_map):
builder.call(x_qc)
with self.assertWarns(DeprecationWarning):
with pulse.transpiler_settings(basis_gates=["x"]):
with pulse.circuit_scheduler_settings(inst_map=inst_map):
builder.call(x_qc)

self.assertScheduleEqual(schedule, ref_sched)

Expand Down Expand Up @@ -606,16 +609,19 @@ def test_qubit_channels(self):
def test_active_transpiler_settings(self):
"""Test setting settings of active builder's transpiler."""
with pulse.build(self.backend):
self.assertFalse(pulse.active_transpiler_settings())
with pulse.transpiler_settings(test_setting=1):
self.assertEqual(pulse.active_transpiler_settings()["test_setting"], 1)
with self.assertWarns(DeprecationWarning):
self.assertFalse(pulse.active_transpiler_settings())
with pulse.transpiler_settings(test_setting=1):
self.assertEqual(pulse.active_transpiler_settings()["test_setting"], 1)

def test_active_circuit_scheduler_settings(self):
"""Test setting settings of active builder's circuit scheduler."""
with pulse.build(self.backend):
self.assertFalse(pulse.active_circuit_scheduler_settings())
with self.assertWarns(DeprecationWarning):
self.assertFalse(pulse.active_circuit_scheduler_settings())
with pulse.circuit_scheduler_settings(test_setting=1):
self.assertEqual(pulse.active_circuit_scheduler_settings()["test_setting"], 1)
with self.assertWarns(DeprecationWarning):
self.assertEqual(pulse.active_circuit_scheduler_settings()["test_setting"], 1)

def test_num_qubits(self):
"""Test builder utility to get number of qubits."""
Expand Down Expand Up @@ -787,7 +793,8 @@ class TestGates(TestBuilder):
def test_cx(self):
"""Test cx gate."""
with pulse.build(self.backend) as schedule:
pulse.cx(0, 1)
with self.assertWarns(DeprecationWarning):
pulse.cx(0, 1)

reference_qc = circuit.QuantumCircuit(2)
reference_qc.cx(0, 1)
Expand All @@ -798,8 +805,9 @@ def test_cx(self):
def test_u1(self):
"""Test u1 gate."""
with pulse.build(self.backend) as schedule:
with pulse.transpiler_settings(layout_method="trivial"):
pulse.u1(np.pi / 2, 0)
with self.assertWarns(DeprecationWarning):
with pulse.transpiler_settings(layout_method="trivial"):
pulse.u1(np.pi / 2, 0)

reference_qc = circuit.QuantumCircuit(1)
reference_qc.append(circuit.library.U1Gate(np.pi / 2), [0])
Expand All @@ -810,7 +818,8 @@ def test_u1(self):
def test_u2(self):
"""Test u2 gate."""
with pulse.build(self.backend) as schedule:
pulse.u2(np.pi / 2, 0, 0)
with self.assertWarns(DeprecationWarning):
pulse.u2(np.pi / 2, 0, 0)

reference_qc = circuit.QuantumCircuit(1)
reference_qc.append(circuit.library.U2Gate(np.pi / 2, 0), [0])
Expand All @@ -821,7 +830,8 @@ def test_u2(self):
def test_u3(self):
"""Test u3 gate."""
with pulse.build(self.backend) as schedule:
pulse.u3(np.pi / 8, np.pi / 16, np.pi / 4, 0)
with self.assertWarns(DeprecationWarning):
pulse.u3(np.pi / 8, np.pi / 16, np.pi / 4, 0)

reference_qc = circuit.QuantumCircuit(1)
reference_qc.append(circuit.library.U3Gate(np.pi / 8, np.pi / 16, np.pi / 4), [0])
Expand All @@ -832,7 +842,8 @@ def test_u3(self):
def test_x(self):
"""Test x gate."""
with pulse.build(self.backend) as schedule:
pulse.x(0)
with self.assertWarns(DeprecationWarning):
pulse.x(0)

reference_qc = circuit.QuantumCircuit(1)
reference_qc.x(0)
Expand All @@ -844,8 +855,9 @@ def test_x(self):
def test_lazy_evaluation_with_transpiler(self):
"""Test that the two cx gates are optimizied away by the transpiler."""
with pulse.build(self.backend) as schedule:
pulse.cx(0, 1)
pulse.cx(0, 1)
with self.assertWarns(DeprecationWarning):
pulse.cx(0, 1)
pulse.cx(0, 1)

reference_qc = circuit.QuantumCircuit(2)
reference = compiler.schedule(reference_qc, self.backend)
Expand All @@ -857,7 +869,8 @@ def test_measure(self):
ensure agreement."""
with pulse.build(self.backend) as schedule:
with pulse.align_sequential():
pulse.x(0)
with self.assertWarns(DeprecationWarning):
pulse.x(0)
pulse.measure(0)

reference_qc = circuit.QuantumCircuit(1, 1)
Expand All @@ -872,7 +885,8 @@ def test_backend_require(self):
"""Test that a backend is required to use a gate."""
with self.assertRaises(exceptions.BackendNotSet):
with pulse.build():
pulse.x(0)
with self.assertWarns(DeprecationWarning):
pulse.x(0)


class TestBuilderComposition(TestBuilder):
Expand All @@ -891,15 +905,18 @@ def test_complex_build(self):
with pulse.build(self.backend) as schedule:
with pulse.align_sequential():
pulse.delay(delay_dur, d0)
pulse.u2(0, pi / 2, 1)
with self.assertWarns(DeprecationWarning):
pulse.u2(0, pi / 2, 1)
with pulse.align_right():
pulse.play(library.Constant(short_dur, 0.1), d1)
pulse.play(library.Constant(long_dur, 0.1), d2)
pulse.u2(0, pi / 2, 1)
with self.assertWarns(DeprecationWarning):
pulse.u2(0, pi / 2, 1)
with pulse.align_left():
pulse.u2(0, pi / 2, 0)
pulse.u2(0, pi / 2, 1)
pulse.u2(0, pi / 2, 0)
with self.assertWarns(DeprecationWarning):
pulse.u2(0, pi / 2, 0)
pulse.u2(0, pi / 2, 1)
pulse.u2(0, pi / 2, 0)
pulse.measure(0)

# prepare and schedule circuits that will be used.
Expand Down Expand Up @@ -1027,7 +1044,8 @@ def test_call_gate_and_circuit(self):
# this is circuit, a subroutine stored as Call instruction
pulse.call(h_control)
# this is instruction, not subroutine
pulse.cx(0, 1)
with self.assertWarns(DeprecationWarning):
pulse.cx(0, 1)
# this is macro, not subroutine
pulse.measure([0, 1])

Expand Down
Loading
Loading