Skip to content
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
1 change: 1 addition & 0 deletions qiskit/circuit/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

Barrier
C3XGate
C3SXGate
C4XGate
CCXGate
DCXGate
Expand Down
3 changes: 2 additions & 1 deletion qiskit/circuit/library/standard_gates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
:toctree: ../stubs/

C3XGate
C3SXGate
C4XGate
CCXGate
DCXGate
Expand Down Expand Up @@ -89,7 +90,7 @@
from .u1 import U1Gate, CU1Gate, MCU1Gate
from .u2 import U2Gate
from .u3 import U3Gate, CU3Gate
from .x import XGate, CXGate, CCXGate, C3XGate, C4XGate, RCCXGate, RC3XGate
from .x import XGate, CXGate, CCXGate, C3XGate, C3SXGate, C4XGate, RCCXGate, RC3XGate
from .x import MCXGate, MCXGrayCode, MCXRecursive, MCXVChain
from .y import YGate, CYGate
from .z import ZGate, CZGate
Expand Down
181 changes: 142 additions & 39 deletions qiskit/circuit/library/standard_gates/x.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

"""X, CX, CCX and multi-controlled X gates."""

import warnings
from math import ceil
import numpy
from qiskit.circuit.controlledgate import ControlledGate
Expand All @@ -23,6 +24,7 @@
from .t import TGate, TdgGate
from .u1 import U1Gate
from .u2 import U2Gate
from .sx import SXGate


class XGate(Gate):
Expand Down Expand Up @@ -416,53 +418,62 @@ def __array__(self, dtype=None):
[0, 0, 0, 1j, 0, 0, 0, 0]], dtype=dtype)


class C3XGate(ControlledGate):
"""The 3-qubit controlled X gate.
class C3SXGate(ControlledGate):
"""The 3-qubit controlled sqrt-X gate.

This implementation is based on Page 17 of [1].

References:
[1] Barenco et al., 1995. https://arxiv.org/pdf/quant-ph/9503016.pdf
"""

def __init__(self, angle=numpy.pi/4, label=None, ctrl_state=None):
"""Create a new 3-qubit controlled X gate.
def __init__(self, label=None, ctrl_state=None, *, angle=None):
"""Create a new 3-qubit controlled sqrt-X gate.

Args:
angle (float): The angle used in the controlled-U1 gates. An angle of π/4 yields the
3-qubit controlled X gate, an angle of π/8 the 3-qubit controlled sqrt(X) gate.
label (str or None): An optional label for the gate [Default: None]
ctrl_state (int or str or None): control state expressed as integer,
string (e.g. '110'), or None. If None, use all 1s.
angle (float): DEPRECATED. The angle used in the controlled-U1 gates. An angle of π/8
yields the sqrt(X) gates, an angle of π/4 the 3-qubit controlled X gate.
"""
super().__init__('mcx', 4, [], num_ctrl_qubits=3, label=label,
ctrl_state=ctrl_state, base_gate=XGate())
super().__init__('c3sx', 4, [], num_ctrl_qubits=3, label=label,
ctrl_state=ctrl_state, base_gate=SXGate())

if angle is not None:
warnings.warn('The angle argument is deprecated as of Qiskit Terra 0.17.0 and will '
'be removed no earlier than 3 months after the release date.',
DeprecationWarning, stacklevel=2)

if angle is None:
angle = numpy.pi / 8

self._angle = angle

def _define(self):
"""
gate c3x a,b,c,d
gate c3sqrtx a,b,c,d
{
h d; cu1(-pi/4) a,d; h d;
h d; cu1(-pi/8) a,d; h d;
cx a,b;
h d; cu1(pi/4) b,d; h d;
h d; cu1(pi/8) b,d; h d;
cx a,b;
h d; cu1(-pi/4) b,d; h d;
h d; cu1(-pi/8) b,d; h d;
cx b,c;
h d; cu1(pi/4) c,d; h d;
h d; cu1(pi/8) c,d; h d;
cx a,c;
h d; cu1(-pi/4) c,d; h d;
h d; cu1(-pi/8) c,d; h d;
cx b,c;
h d; cu1(pi/4) c,d; h d;
h d; cu1(pi/8) c,d; h d;
cx a,c;
h d; cu1(-pi/4) c,d; h d;
h d; cu1(-pi/8) c,d; h d;
}
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .u1 import CU1Gate
q = QuantumRegister(4, name='q')
# pylint: disable=invalid-unary-operand-type
rules = [
(HGate(), [q[3]], []),
(CU1Gate(-self._angle), [q[0], q[3]], []),
Expand Down Expand Up @@ -498,6 +509,109 @@ def _define(self):

self.definition = qc

def inverse(self):
"""Invert this gate. The C3X is its own inverse."""
# pylint: disable=invalid-unary-operand-type
if self._angle is not None:
angle = -self._angle
else:
angle = None

return C3SXGate(angle=angle, ctrl_state=self.ctrl_state)


class C3XGate(ControlledGate):
r"""The 4-qubit controlled X gate.

This implementation uses :math:`\sqrt{T}` and 14 CNOT gates.
"""

def __new__(cls, angle=None, label=None, ctrl_state=None):
if angle is not None:
return C3SXGate(label, ctrl_state, angle=angle)

instance = super().__new__(cls)
instance.__init__(None, label, ctrl_state)
return instance

# pylint: disable=unused-argument
def __init__(self, angle=None, label=None, ctrl_state=None):
"""Create a new 3-qubit controlled X gate."""
super().__init__('mcx', 4, [], num_ctrl_qubits=3, label=label,
ctrl_state=ctrl_state, base_gate=XGate())

# seems like open controls not hapening?
def _define(self):
"""
gate c3x a,b,c,d
{
h d;
p(pi/8) a;
p(pi/8) b;
p(pi/8) c;
p(pi/8) d;
cx a, b;
p(-pi/8) b;
cx a, b;
cx b, c;
p(-pi/8) c;
cx a, c;
p(pi/8) c;
cx b, c;
p(-pi/8) c;
cx a, c;
cx c, d;
p(-pi/8) d;
cx b, d;
p(pi/8) d;
cx c, d;
p(-pi/8) d;
cx a, d;
p(pi/8) d;
cx c, d;
p(-pi/8) d;
cx b, d;
p(pi/8) d;
cx c, d;
p(-pi/8) d;
cx a, d;
h d;
}
"""
from qiskit.circuit.quantumcircuit import QuantumCircuit
q = QuantumRegister(4, name='q')
qc = QuantumCircuit(q, name=self.name)
qc.h(3)
qc.p(pi / 8, [0, 1, 2, 3])
qc.cx(0, 1)
qc.p(-pi / 8, 1)
qc.cx(0, 1)
qc.cx(1, 2)
qc.p(-pi / 8, 2)
qc.cx(0, 2)
qc.p(pi / 8, 2)
qc.cx(1, 2)
qc.p(-pi / 8, 2)
qc.cx(0, 2)
qc.cx(2, 3)
qc.p(-pi / 8, 3)
qc.cx(1, 3)
qc.p(pi / 8, 3)
qc.cx(2, 3)
qc.p(-pi / 8, 3)
qc.cx(0, 3)
qc.p(pi / 8, 3)
qc.cx(2, 3)
qc.p(-pi / 8, 3)
qc.cx(1, 3)
qc.p(pi / 8, 3)
qc.cx(2, 3)
qc.p(-pi / 8, 3)
qc.cx(0, 3)
qc.h(3)

self.definition = qc

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Controlled version of this gate.

Expand All @@ -517,28 +631,17 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
return gate

def inverse(self):
"""Invert this gate. The C3X is its own inverse."""
return C3XGate(angle=-self._angle, ctrl_state=self.ctrl_state)

# This matrix is only correct if the angle is pi/4
# def __array__(self, dtype=None):
# """Return a numpy.array for the C3X gate."""
# return numpy.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
# [0, 0, 0, 0, 0, 0, 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]], dtype=dtype)
"""Invert this gate. The C4X is its own inverse."""
return C3XGate(ctrl_state=self.ctrl_state)

def __array__(self, dtype=None):
"""Return a numpy.array for the C4X gate."""
mat = _compute_control_matrix(self.base_gate.to_matrix(),
self.num_ctrl_qubits,
ctrl_state=self.ctrl_state)
if dtype:
return numpy.asarray(mat, dtype=dtype)
return mat


class RC3XGate(Gate):
Expand Down Expand Up @@ -686,7 +789,7 @@ def _define(self):
(CU1Gate(numpy.pi / 2), [q[3], q[4]], []),
(HGate(), [q[4]], []),
(RC3XGate().inverse(), [q[0], q[1], q[2], q[3]], []),
(C3XGate(numpy.pi / 8), [q[0], q[1], q[2], q[4]], []),
(C3SXGate(), [q[0], q[1], q[2], q[4]], []),
]
for instr, qargs, cargs in rules:
qc._append(instr, qargs, cargs)
Expand Down
44 changes: 31 additions & 13 deletions qiskit/qasm/libs/qelib1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -206,19 +206,37 @@ gate rc3x a,b,c,d
// 3-controlled X gate
gate c3x a,b,c,d
{
h d; cu1(-pi/4) a,d; h d;
cx a,b;
h d; cu1(pi/4) b,d; h d;
cx a,b;
h d; cu1(-pi/4) b,d; h d;
cx b,c;
h d; cu1(pi/4) c,d; h d;
cx a,c;
h d; cu1(-pi/4) c,d; h d;
cx b,c;
h d; cu1(pi/4) c,d; h d;
cx a,c;
h d; cu1(-pi/4) c,d; h d;
h d;
p(pi/8) a;
p(pi/8) b;
p(pi/8) c;
p(pi/8) d;
cx a, b;
p(-pi/8) b;
cx a, b;
cx b, c;
p(-pi/8) c;
cx a, c;
p(pi/8) c;
cx b, c;
p(-pi/8) c;
cx a, c;
cx c, d;
p(-pi/8) d;
cx b, d;
p(pi/8) d;
cx c, d;
p(-pi/8) d;
cx a, d;
p(pi/8) d;
cx c, d;
p(-pi/8) d;
cx b, d;
p(pi/8) d;
cx c, d;
p(-pi/8) d;
cx a, d;
h d;
}
// 3-controlled sqrt(X) gate, this equals the C3X gate where the CU1 rotations are -pi/8 not -pi/4
gate c3sqrtx a,b,c,d
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
Reduce the number of CX gates in the decomposition of the 3-controlled
X gate, :class:`~qiskit.circuit.library.C3XGate`. Compiled and optimized
in the `U CX` basis, now only 14 CX and 16 U gates are used instead of
20 and 22, respectively.
6 changes: 4 additions & 2 deletions test/python/circuit/test_controlled_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
U3Gate, CHGate, CRZGate, CU3Gate, CUGate,
SXGate, CSXGate, MSGate, Barrier, RCCXGate,
RC3XGate, MCU1Gate, MCXGate, MCXGrayCode,
MCXRecursive, MCXVChain, C3XGate, C4XGate,
MCPhaseGate)
MCXRecursive, MCXVChain, C3XGate, C3SXGate,
C4XGate, MCPhaseGate)
from qiskit.circuit._utils import _compute_control_matrix
import qiskit.circuit.library.standard_gates as allGates
from qiskit.extensions import UnitaryGate
Expand Down Expand Up @@ -1253,6 +1253,7 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class):
base_mat = (np.cos(0.5 * theta) * iden - 1j * np.sin(0.5 * theta) * zgen).data
else:
base_mat = Operator(gate).data

target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits,
ctrl_state=ctrl_state)
self.assertEqual(Operator(cgate), Operator(target_mat))
Expand Down Expand Up @@ -1296,6 +1297,7 @@ class TestControlledGateLabel(QiskitTestCase):
(CXGate, []),
(CCXGate, []),
(C3XGate, []),
(C3SXGate, []),
(C4XGate, []),
(MCXGate, [5]),
(PhaseGate, [0.1]),
Expand Down