Source code for pennylane.transforms.optimization.relative_phases
# Copyright 2018-2021 Xanadu Quantum Technologies Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Transforms lowering gates and series of gates involving relative phases.
Transformations first published in:
Maslov, Dmitri. "On the Advantages of Using Relative Phase Toffolis with an Application to
Multiple Control Toffoli Optimization", arXiv:1508.03273, arXiv, 2016.
doi:10.48550/arXiv.1508.03273.
Giles, Brett, and Peter Selinger. "Exact Synthesis of Multiqubit Clifford+T Circuits",
arXiv:1212.0506, arXiv, 2013. doi:10.48550/arXiv.1212.0506.
"""
import pennylane as qml
from pennylane.tape import QuantumScript, QuantumScriptBatch
from pennylane.transforms import transform
from pennylane.typing import PostprocessingFn
from .pattern_matching import pattern_matching_optimization
[docs]
@transform
def match_relative_phase_toffoli(
tape: QuantumScript,
) -> tuple[QuantumScriptBatch, PostprocessingFn]:
"""Quantum transform to replace 4-qubit relative phase Toffoli gates, given in
Maslov, Dmitri. "On the Advantages of Using Relative Phase Toffolis with an Application to
Multiple Control Toffoli Optimization", arXiv:1508.03273, arXiv, 2016.
`doi:10.48550/arXiv.1508.03273 <https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.022311>`_.
.. note::
Will also replace any subcircuits from the full pattern (composed of the 4-qubit relative phase Toffoli
and its decomposition) that can replaced by the rest of the pattern.
Args:
tape (QNode or QuantumScript or Callable): A quantum circuit.
Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[.QuantumScript], function]:
The transformed circuit as described in :func:`qml.transform <pennylane.transform>`.
**Example**
.. code-block:: python
def qfunc():
qml.CCZ(wires=[0, 1, 3])
qml.ctrl(qml.S(wires=[1]), control=[0])
qml.ctrl(qml.S(wires=[2]), control=[0, 1])
qml.MultiControlledX(wires=[0, 1, 2, 3])
return qml.expval(qml.Z(0))
The circuit (a 4-qubit relative phase Toffoli) before decomposition:
>>> dev = qml.device('default.qubit', wires=4)
>>> qnode = qml.QNode(qfunc, dev)
>>> lowered_qnode = match_relative_phase_toffoli(qnode)
>>> print(qml.draw(lowered_qnode, level=0)())
0: ─╭●─╭●─╭●─╭●─┤ <Z>
1: ─├●─╰S─├●─├●─┤
2: ─│─────╰S─├●─┤
3: ─╰Z───────╰X─┤
We can replace the relative phase 4-qubit Toffoli by running the transform:
>>> print(qml.draw(lowered_qnode, level=1)())
0: ─────────────────╭●───────────╭●───────────────────────────┤ <Z>
1: ─────────────────│─────╭●─────│─────╭●─────────────────────┤
2: ───────╭●────────│─────│──────│─────│────────────╭●────────┤
3: ──H──T─╰X──T†──H─╰X──T─╰X──T†─╰X──T─╰X──T†──H──T─╰X──T†──H─┤
.. details::
:title: Usage Details
Consider the following quantum function:
.. code-block:: python
@match_relative_phase_toffoli
@qml.qnode(device=dev)
def circuit():
qml.Hadamard(wires=0)
qml.Hadamard(wires=1)
qml.Barrier(wires=[0,1])
qml.X(0)
# begin relative phase 4-qubit Toffoli
qml.CCZ(wires=[0, 1, 3])
qml.ctrl(qml.S(wires=[1]), control=[0])
qml.ctrl(qml.S(wires=[2]), control=[0, 1])
qml.MultiControlledX(wires=[0, 1, 2, 3])
# end relative phase 4-qubit Toffoli
qml.Hadamard(wires=1)
qml.Barrier(wires=[0,1])
qml.X(0)
return qml.expval(qml.Z(0))
The relative phase 4-qubit Toffoli is then replaced before execution.
"""
pattern_ops = [
qml.CCZ([0, 1, 3]),
qml.ctrl(qml.S(1), control=[0]),
qml.ctrl(qml.S(2), control=[0, 1]),
qml.MultiControlledX([0, 1, 2, 3]),
# ------------
qml.Hadamard(3),
qml.T(3),
qml.CNOT([2, 3]),
qml.adjoint(qml.T(3)),
qml.Hadamard(3),
qml.T(3),
qml.CNOT([1, 3]),
qml.adjoint(qml.T(3)),
qml.CNOT([0, 3]),
qml.T(3),
qml.CNOT([1, 3]),
qml.adjoint(qml.T(3)),
qml.CNOT([0, 3]),
qml.Hadamard(3),
qml.T(3),
qml.CNOT([2, 3]),
qml.adjoint(qml.T(3)),
qml.Hadamard(3),
]
pattern = QuantumScript(pattern_ops)
return pattern_matching_optimization(tape, pattern_tapes=[pattern])
[docs]
@transform
def match_controlled_iX_gate(
tape: QuantumScript, num_controls=1
) -> tuple[QuantumScriptBatch, PostprocessingFn]:
"""Quantum transform to replace controlled iX gates. An iX gate is a controlled-S and a Toffoli. The
equivalency used is given in Giles, Brett, and Peter Selinger. "Exact Synthesis of Multiqubit Clifford+T Circuits",
arXiv:1212.0506, arXiv, 2013. `doi:10.48550/arXiv.1212.0506 <https://journals.aps.org/pra/abstract/10.1103/PhysRevA.87.032332>`_.
.. note::
Will also replace any subcircuits from the full pattern (composed of the controlled iX gate
and its decomposition) that can replaced by the rest of the pattern.
Args:
tape (QNode or QuantumScript or Callable): A quantum circuit.
num_controls (int): The number of controls on the CS gate.
Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[.QuantumScript], function]:
The transformed circuit as described in :func:`qml.transform <pennylane.transform>`.
**Example**
Consider the following quantum function:
.. code-block:: python
def qfunc():
qml.ctrl(qml.S(wires=[2]), control=[0, 1])
qml.MultiControlledX(wires=[0, 1, 2, 3])
return qml.expval(qml.Z(0))
The circuit (a controlled iX gate) before decomposition:
>>> dev = qml.device('default.qubit', wires=4)
>>> qnode = qml.QNode(qfunc, dev)
>>> lowered_qnode = match_controlled_iX_gate(qnode, 2)
>>> print(qml.draw(lowered_qnode, level=0)())
0: ─╭●─╭●─┤ <Z>
1: ─├●─├●─┤
2: ─╰S─├●─┤
3: ────╰X─┤
We can replace the multi-controlled iX gate by running the transform:
>>> print(qml.draw(lowered_qnode, level=1)())
0: ──────────────╭●───────────╭●────┤ <Z>
1: ──────────────├●───────────├●────┤
2: ────────╭●────│──────╭●────│─────┤
3: ──H──T†─╰X──T─╰X──T†─╰X──T─╰X──H─┤
.. details::
:title: Usage Details
.. code-block:: python
@replace_iX_gate
@qml.qnode(device=dev)
def circuit():
qml.Hadamard(wires=0)
qml.Hadamard(wires=1)
qml.Barrier(wires=[0,1])
qml.X(0)
# begin multi-controlled iX gate
qml.ctrl(qml.S(wires=[2]), control=[0, 1])
qml.MultiControlledX(wires=[0, 1, 2, 3])
# end multi-controlled iX gate
qml.Hadamard(wires=1)
qml.Barrier(wires=[0,1])
qml.X(0)
return qml.expval(qml.Z(0))
The relative multi-controlled iX gate (CS, Toffoli) is then replaced before execution.
"""
if num_controls < 1:
raise ValueError(
"There must be at least one control wire for the controlled iX gate decomposition."
)
pattern_ops = [
qml.ctrl(qml.S(num_controls), control=list(range(num_controls))),
qml.MultiControlledX(list(range(num_controls + 2))),
# ------------
qml.Hadamard(num_controls + 1),
qml.MultiControlledX(list(range(num_controls)) + [num_controls + 1]),
qml.adjoint(qml.T(num_controls + 1)),
qml.CNOT([num_controls, num_controls + 1]),
qml.T(num_controls + 1),
qml.MultiControlledX(list(range(num_controls)) + [num_controls + 1]),
qml.adjoint(qml.T(num_controls + 1)),
qml.CNOT([num_controls, num_controls + 1]),
qml.T(num_controls + 1),
qml.Hadamard(num_controls + 1),
]
pattern = QuantumScript(pattern_ops)
return pattern_matching_optimization(tape, pattern_tapes=[pattern])
_modules/pennylane/transforms/optimization/relative_phases
Download Python script
Download Notebook
View on GitHub