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

Fix qft-plugins for custom 'qft' gates (backport #13181) #13189

Merged
merged 1 commit into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 16 additions & 6 deletions qiskit/transpiler/passes/synthesis/high_level_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,10 @@ class QFTSynthesisFull(HighLevelSynthesisPlugin):
This plugin name is :``qft.full`` which can be used as the key on
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.

Note that the plugin mechanism is not applied if the gate is called ``qft`` but
is not an instance of ``QFTGate``. This allows users to create custom gates with
name ``qft``.

The plugin supports the following additional options:

* reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``,
Expand Down Expand Up @@ -995,10 +999,11 @@ class QFTSynthesisFull(HighLevelSynthesisPlugin):

def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
"""Run synthesis for the given QFTGate."""

# Even though the gate is called "qft", it's not a QFTGate,
# and we should not synthesize it using the plugin.
if not isinstance(high_level_object, QFTGate):
raise TranspilerError(
"The synthesis plugin 'qft.full` only applies to objects of type QFTGate."
)
return None

reverse_qubits = options.get("reverse_qubits", False)
approximation_degree = options.get("approximation_degree", 0)
Expand All @@ -1023,6 +1028,10 @@ class QFTSynthesisLine(HighLevelSynthesisPlugin):
This plugin name is :``qft.line`` which can be used as the key on
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.

Note that the plugin mechanism is not applied if the gate is called ``qft`` but
is not an instance of ``QFTGate``. This allows users to create custom gates with
name ``qft``.

The plugin supports the following additional options:

* reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``,
Expand All @@ -1047,10 +1056,11 @@ class QFTSynthesisLine(HighLevelSynthesisPlugin):

def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
"""Run synthesis for the given QFTGate."""

# Even though the gate is called "qft", it's not a QFTGate,
# and we should not synthesize it using the plugin.
if not isinstance(high_level_object, QFTGate):
raise TranspilerError(
"The synthesis plugin 'qft.line` only applies to objects of type QFTGate."
)
return None

reverse_qubits = options.get("reverse_qubits", False)
approximation_degree = options.get("approximation_degree", 0)
Expand Down
9 changes: 9 additions & 0 deletions releasenotes/notes/fix-qft-plugins-7106029d33c44b96.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
fixes:
- |
The ``HighLevelSynthesis`` transpiler pass no longer raises an exception when
encountering a custom gate that is called "qft" but is not an instance of
:class:`~qiskit.circuit.library.QFTGate`. Instead, the synthesis plugins for
QFT gates ignore such a gate, and the gate's definition is used (if provided).
16 changes: 16 additions & 0 deletions test/python/transpiler/test_high_level_synthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2136,6 +2136,22 @@ def test_qft_line_plugin_annotated_qft(self, qft_plugin_name):
ops = set(qct.count_ops().keys())
self.assertEqual(ops, {"u", "cx"})

@data("line", "full")
def test_skip_non_qft(self, qft_plugin_name):
"""Test that synthesis plugins are not applied on gates that are called `qft`, yet
that are not of type `QFTGate`.
"""
qc = QuantumCircuit(1)
qc2 = QuantumCircuit(1, name="qft")
qc2.s(0)
qc.append(qc2.to_instruction(), qc.qregs[0])
hls_config = HLSConfig(qft=[qft_plugin_name])
hls_pass = HighLevelSynthesis(hls_config=hls_config)
qct = hls_pass(qc)
# HighLevelSynthesis should replace the custom gate called "qft"
# by the user-provided definition.
self.assertEqual(Operator(qc2), Operator(qct))


if __name__ == "__main__":
unittest.main()
Loading