Skip to content

Commit

Permalink
override control of standard gates where possible (Qiskit#3631)
Browse files Browse the repository at this point in the history
* move controlled gate class definitions into base gate module.

* fix cyclic imports

* update for new crx and cry

* linting

* linting

* linting

* minor

* wrong import of U3Gate

* module level pylint cyclic-import disable

* update mapper ground truth

* hack to get tox to work

* solve bug associated with ToffoliGate import.

* avoid multiple definitions

* update warning category.

* change stack level

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
ewinston and mergify[bot] authored Jan 30, 2020
1 parent 4377ff8 commit 7e8ead4
Show file tree
Hide file tree
Showing 46 changed files with 807 additions and 697 deletions.
73 changes: 8 additions & 65 deletions qiskit/circuit/add_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,77 +31,20 @@ def add_control(operation, num_ctrl_qubits, label):
uses num_ctrl_qubits-1 ancillae qubits so returns a gate of size
num_qubits + 2*num_ctrl_qubits - 1.
"""
import qiskit.extensions.standard as standard
if isinstance(operation, standard.RZGate) or operation.name == 'rz':
# num_ctrl_qubits > 1
# the condition matching 'name' above is to catch a test case,
# 'TestControlledGate.test_rotation_gates', where the rz gate
# gets converted to a circuit before becoming a generic Gate object.
cgate = standard.CrzGate(*operation.params)
return cgate.control(num_ctrl_qubits - 1)
if isinstance(operation, UnitaryGate):
# attempt decomposition
operation._define()
if _control_definition_known(operation, num_ctrl_qubits):
return _control_predefined(operation, num_ctrl_qubits)
return control(operation, num_ctrl_qubits=num_ctrl_qubits, label=label)


def _control_definition_known(operation, num_ctrl_qubits):
if num_ctrl_qubits == 2 and operation.name == 'x':
return True
elif num_ctrl_qubits == 1:
return operation.name in {'x', 'y', 'z', 'h', 'rx', 'ry', 'rz', 'swap', 'u1', 'u3', 'cx'}
elif operation.name == 'rz' and num_ctrl_qubits > 1:
return True
else:
return False


def _control_predefined(operation, num_ctrl_qubits):
"""Returns controlled gates with hard-coded definitions in
the standard extensions."""
if operation.name == 'x' and num_ctrl_qubits in [1, 2]:
if num_ctrl_qubits == 1:
import qiskit.extensions.standard.cx
cgate = qiskit.extensions.standard.cx.CnotGate()
else:
import qiskit.extensions.standard.ccx
cgate = qiskit.extensions.standard.ccx.ToffoliGate()
elif operation.name == 'y':
import qiskit.extensions.standard.cy
cgate = qiskit.extensions.standard.cy.CyGate()
elif operation.name == 'z':
import qiskit.extensions.standard.cz
cgate = qiskit.extensions.standard.cz.CzGate()
elif operation.name == 'h':
import qiskit.extensions.standard.ch
cgate = qiskit.extensions.standard.ch.CHGate()
elif operation.name in {'rx', 'ry', 'rz'}:
if operation.name == 'rx':
import qiskit.extensions.standard.crx
cgate = qiskit.extensions.standard.crx.CrxGate(*operation.params)
elif operation.name == 'ry':
import qiskit.extensions.standard.cry
cgate = qiskit.extensions.standard.cry.CryGate(*operation.params)
else: # operation.name == 'rz'
import qiskit.extensions.standard.crz
cgate = qiskit.extensions.standard.crz.CrzGate(*operation.params)
if num_ctrl_qubits == 1:
return cgate
else:
# only predefined for one control qubit
return cgate.control(num_ctrl_qubits - 1)
elif operation.name == 'swap':
import qiskit.extensions.standard.cswap
cgate = qiskit.extensions.standard.cswap.FredkinGate()
elif operation.name == 'u1':
import qiskit.extensions.standard.cu1
cgate = qiskit.extensions.standard.cu1.Cu1Gate(*operation.params)
elif operation.name == 'u3':
import qiskit.extensions.standard.cu3
cgate = qiskit.extensions.standard.cu3.Cu3Gate(*operation.params)
elif operation.name == 'cx':
import qiskit.extensions.standard.ccx
cgate = qiskit.extensions.standard.ccx.ToffoliGate()
else:
raise QiskitError('No standard controlled gate for "{}"'.format(
operation.name))
return cgate


def control(operation, num_ctrl_qubits=1, label=None):
"""Return controlled version of gate using controlled rotations
Expand Down
22 changes: 11 additions & 11 deletions qiskit/converters/ast_to_dag.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
from qiskit.circuit.measure import Measure
from qiskit.circuit.reset import Reset
from qiskit.extensions.standard.barrier import Barrier
from qiskit.extensions.standard.ccx import ToffoliGate
from qiskit.extensions.standard.cswap import FredkinGate
from qiskit.extensions.standard.cx import CnotGate
from qiskit.extensions.standard.cy import CyGate
from qiskit.extensions.standard.cz import CzGate
from qiskit.extensions.standard.x import ToffoliGate
from qiskit.extensions.standard.swap import FredkinGate
from qiskit.extensions.standard.x import CnotGate
from qiskit.extensions.standard.y import CyGate
from qiskit.extensions.standard.z import CzGate
from qiskit.extensions.standard.swap import SwapGate
from qiskit.extensions.standard.h import HGate
from qiskit.extensions.standard.iden import IdGate
Expand All @@ -46,12 +46,12 @@
from qiskit.extensions.standard.rx import RXGate
from qiskit.extensions.standard.ry import RYGate
from qiskit.extensions.standard.rz import RZGate
from qiskit.extensions.standard.cu1 import Cu1Gate
from qiskit.extensions.standard.ch import CHGate
from qiskit.extensions.standard.crx import CrxGate
from qiskit.extensions.standard.cry import CryGate
from qiskit.extensions.standard.crz import CrzGate
from qiskit.extensions.standard.cu3 import Cu3Gate
from qiskit.extensions.standard.u1 import Cu1Gate
from qiskit.extensions.standard.h import CHGate
from qiskit.extensions.standard.rx import CrxGate
from qiskit.extensions.standard.ry import CryGate
from qiskit.extensions.standard.rz import CrzGate
from qiskit.extensions.standard.u3 import Cu3Gate
from qiskit.extensions.standard.rxx import RXXGate
from qiskit.extensions.standard.rzz import RZZGate

Expand Down
2 changes: 1 addition & 1 deletion qiskit/extensions/quantum_initializer/initializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister
from qiskit.circuit import Instruction
from qiskit.extensions.standard.cx import CnotGate
from qiskit.extensions.standard.x import CnotGate
from qiskit.extensions.standard.ry import RYGate
from qiskit.extensions.standard.rz import RZGate
from qiskit.circuit.reset import Reset
Expand Down
43 changes: 15 additions & 28 deletions qiskit/extensions/standard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,21 @@

"""Standard gates."""
from .barrier import Barrier
from .ccx import ToffoliGate
from .cswap import FredkinGate
from .cx import CnotGate
from .cy import CyGate
from .cz import CzGate
from .swap import SwapGate
from .h import HGate
from .h import HGate, CHGate
from .iden import IdGate
from .s import SGate
from .s import SdgGate
from .t import TGate
from .t import TdgGate
from .u1 import U1Gate
from .u2 import U2Gate
from .u3 import U3Gate
from .x import XGate
from .y import YGate
from .z import ZGate
from .ms import MSGate
from .r import RGate
from .rx import RXGate
from .ry import RYGate
from .rz import RZGate
from .cu1 import Cu1Gate
from .ch import CHGate
from .crx import CrxGate
from .cry import CryGate
from .crz import CrzGate
from .cu3 import Cu3Gate
from .rzz import RZZGate
from .rx import RXGate, CrxGate
from .rxx import RXXGate
from .ms import MSGate
from .ry import RYGate, CryGate
from .rz import RZGate, CrzGate
from .rzz import RZZGate
from .s import SGate, SdgGate
from .swap import SwapGate, FredkinGate
from .t import TGate, TdgGate
from .u1 import U1Gate, Cu1Gate
from .u2 import U2Gate
from .u3 import U3Gate, Cu3Gate
from .x import XGate, CnotGate, ToffoliGate
from .y import YGate, CyGate
from .z import ZGate, CzGate
80 changes: 5 additions & 75 deletions qiskit/extensions/standard/ccx.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,79 +16,9 @@
Toffoli gate. Controlled-Controlled-X.
"""

import numpy
import warnings
# pylint: disable=unused-import
from qiskit.extensions.standard.x import ToffoliGate, ccx

from qiskit.circuit import ControlledGate
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister
from qiskit.extensions.standard.x import XGate
from qiskit.extensions.standard.h import HGate
from qiskit.extensions.standard.cx import CnotGate
from qiskit.extensions.standard.t import TGate
from qiskit.extensions.standard.t import TdgGate


class ToffoliGate(ControlledGate):
"""Toffoli gate."""

def __init__(self):
"""Create new Toffoli gate."""
super().__init__("ccx", 3, [], num_ctrl_qubits=2)
self.base_gate = XGate
self.base_gate_name = "x"

def _define(self):
"""
gate ccx a,b,c
{
h c; cx b,c; tdg c; cx a,c;
t c; cx b,c; tdg c; cx a,c;
t b; t c; h c; cx a,b;
t a; tdg b; cx a,b;}
"""
definition = []
q = QuantumRegister(3, "q")
rule = [
(HGate(), [q[2]], []),
(CnotGate(), [q[1], q[2]], []),
(TdgGate(), [q[2]], []),
(CnotGate(), [q[0], q[2]], []),
(TGate(), [q[2]], []),
(CnotGate(), [q[1], q[2]], []),
(TdgGate(), [q[2]], []),
(CnotGate(), [q[0], q[2]], []),
(TGate(), [q[1]], []),
(TGate(), [q[2]], []),
(HGate(), [q[2]], []),
(CnotGate(), [q[0], q[1]], []),
(TGate(), [q[0]], []),
(TdgGate(), [q[1]], []),
(CnotGate(), [q[0], q[1]], [])
]
for inst in rule:
definition.append(inst)
self.definition = definition

def inverse(self):
"""Invert this gate."""
return ToffoliGate() # self-inverse

def to_matrix(self):
"""Return a Numpy.array for the Toffoli gate."""
return numpy.array([[1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 0]], dtype=complex)


def ccx(self, ctl1, ctl2, tgt):
"""Apply Toffoli to ctl1 and ctl2 to tgt."""
return self.append(ToffoliGate(), [ctl1, ctl2, tgt], [])


QuantumCircuit.ccx = ccx
QuantumCircuit.toffoli = ccx
warnings.warn('This module is deprecated. The ToffoliGate can now be found in x.py',
category=DeprecationWarning, stacklevel=2)
69 changes: 5 additions & 64 deletions qiskit/extensions/standard/ch.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,68 +15,9 @@
"""
controlled-H gate.
"""
import numpy as np
import warnings
# pylint: disable=unused-import
from qiskit.extensions.standard.h import HGate, ch

from qiskit.circuit import ControlledGate
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister
from qiskit.extensions.standard.h import HGate
from qiskit.extensions.standard.cx import CnotGate
from qiskit.extensions.standard.t import TGate, TdgGate
from qiskit.extensions.standard.s import SGate, SdgGate


class CHGate(ControlledGate):
"""controlled-H gate."""

def __init__(self):
"""Create new CH gate."""
super().__init__("ch", 2, [], num_ctrl_qubits=1)
self.base_gate = HGate
self.base_gate_name = "h"

def _define(self):
"""
gate ch a,b {
s b;
h b;
t b;
cx a, b;
tdg b;
h b;
sdg b;
}
"""
definition = []
q = QuantumRegister(2, "q")
rule = [
(SGate(), [q[1]], []),
(HGate(), [q[1]], []),
(TGate(), [q[1]], []),
(CnotGate(), [q[0], q[1]], []),
(TdgGate(), [q[1]], []),
(HGate(), [q[1]], []),
(SdgGate(), [q[1]], [])
]
for inst in rule:
definition.append(inst)
self.definition = definition

def inverse(self):
"""Invert this gate."""
return CHGate() # self-inverse

def to_matrix(self):
"""Return a Numpy.array for the Ch gate."""
return np.array([[1, 0, 0, 0],
[0, 1/np.sqrt(2), 0, 1/np.sqrt(2)],
[0, 0, 1, 0],
[0, 1/np.sqrt(2), 0, -1/np.sqrt(2)]], dtype=complex)


def ch(self, ctl, tgt): # pylint: disable=invalid-name
"""Apply CH from ctl to tgt."""
return self.append(CHGate(), [ctl, tgt], [])


QuantumCircuit.ch = ch
warnings.warn('This module is deprecated. The CHGate can now be found in h.py',
category=DeprecationWarning, stacklevel=2)
Loading

0 comments on commit 7e8ead4

Please sign in to comment.