Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
214d880
add sqrt x and controlled version
Cryoris Jul 2, 2020
f958aae
add to inits
Cryoris Jul 2, 2020
e32cc98
add to equivalence lib
Cryoris Jul 2, 2020
8826707
add to qelib
Cryoris Jul 2, 2020
7a60a5e
add circuit methods
Cryoris Jul 2, 2020
8dd8b78
add to label test
Cryoris Jul 2, 2020
2fd9221
Merge branch 'master' into sx
Cryoris Jul 2, 2020
e3f600a
add reno
Cryoris Jul 2, 2020
ea0a329
fix missing qubit in qelub
Cryoris Jul 2, 2020
6d62d0e
change SX definition to use only one H
Cryoris Jul 3, 2020
25452ce
update decomp in gate and add default label
Cryoris Jul 3, 2020
be6221b
fix test by accounting for global phase diff
Cryoris Jul 3, 2020
22b84e1
handle case of 1 ctrl qubit separately
Cryoris Jul 3, 2020
df9269c
account for global phase in CSX test
Cryoris Jul 6, 2020
c575589
Merge branch 'master' into sx
Cryoris Jul 6, 2020
fe5c2d5
change to new gate def
Cryoris Jul 6, 2020
7b3876a
ignore cyclic import
Cryoris Jul 6, 2020
6cb5812
add SXdg gate
Cryoris Jul 13, 2020
621d781
fix U3 equivalence, add rz to sx ry
Cryoris Jul 14, 2020
010e50c
equivalences: replace RX by SX, add SX->RX
Cryoris Jul 15, 2020
30c5074
Merge branch 'master' into sx
Cryoris Jul 15, 2020
faa28a9
Apply suggestions from code review
Cryoris Jul 25, 2020
caa95c8
Merge branch 'master' into sx
Cryoris Jul 25, 2020
5481928
update to accomodate global phases
Cryoris Jul 25, 2020
8d6c200
change to case where phase is not 1
Cryoris Jul 25, 2020
7cd4b71
mention SXdg in the reno
Cryoris Jul 25, 2020
b5e291d
Merge branch 'master' into sx
Cryoris Jul 27, 2020
d4279e9
Merge branch 'master' into sx
Cryoris Jul 28, 2020
575702f
ignore global phase for now
Cryoris Jul 28, 2020
5483125
Merge branch 'sx' of github.com:Cryoris/qiskit-terra into sx
Cryoris Jul 28, 2020
f4cd163
update text and mpl drawer
Cryoris Jul 28, 2020
58e897a
add sx and sxdg to standard gates in matplotlib.py
Cryoris Jul 28, 2020
117f16d
Merge branch 'master' into sx
Cryoris Jul 28, 2020
03d0945
dagger is unsupported ascii char
Cryoris Jul 29, 2020
36067ad
Merge branch 'sx' of github.com:Cryoris/qiskit-terra into sx
Cryoris Jul 29, 2020
872123b
Merge branch 'master' into sx
Cryoris Jul 29, 2020
54836c0
use mathmode in qcstyle
Cryoris Jul 29, 2020
3359e4e
Merge branch 'master' into sx
Cryoris Jul 30, 2020
ad7b92a
add u2 to u1/sx equivalence
Cryoris Jul 31, 2020
8fce279
Merge branch 'master' into sx
Cryoris Aug 3, 2020
ec40da9
Merge branch 'master' into sx
Cryoris Aug 4, 2020
f50d47e
Merge branch 'master' into sx
Cryoris Aug 4, 2020
76329f4
Merge branch 'sx' of github.com:Cryoris/qiskit-terra into sx
Cryoris Aug 4, 2020
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
3 changes: 3 additions & 0 deletions qiskit/circuit/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
CRYGate
CRZGate
CSwapGate
CSXGate
CU1Gate
CU3Gate
CXGate
Expand All @@ -58,6 +59,8 @@
SdgGate
SwapGate
iSwapGate
SXGate
SXdgGate
TGate
TdgGate
U1Gate
Expand Down
4 changes: 4 additions & 0 deletions qiskit/circuit/library/standard_gates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
CRYGate
CRZGate
CSwapGate
CSXGate
CU1Gate
CU3Gate
CXGate
Expand All @@ -50,6 +51,8 @@
SdgGate
SwapGate
iSwapGate
SXGate
SXdgGate
TGate
TdgGate
U1Gate
Expand All @@ -75,6 +78,7 @@
from .s import SGate, SdgGate
from .swap import SwapGate, CSwapGate
from .iswap import iSwapGate
from .sx import SXGate, SXdgGate, CSXGate
from .dcx import DCXGate
from .t import TGate, TdgGate
from .u1 import U1Gate, CU1Gate, MCU1Gate
Expand Down
38 changes: 38 additions & 0 deletions qiskit/circuit/library/standard_gates/equivalence_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
SwapGate,
CSwapGate,
iSwapGate,
SXGate,
CSXGate,
DCXGate,
TGate,
TdgGate,
Expand Down Expand Up @@ -289,6 +291,30 @@
def_iswap.append(inst, qargs, cargs)
_sel.add_equivalence(iSwapGate(), def_iswap)

# SXGate

q = QuantumRegister(1, 'q')
def_sx = QuantumCircuit(q)
for inst, qargs, cargs in [
(RZGate(-pi / 2), [q[0]], []),
Comment thread
Cryoris marked this conversation as resolved.
Outdated
(HGate(), [q[0]], []),
(RZGate(-pi / 2), [q[0]], [])
Comment thread
Cryoris marked this conversation as resolved.
Outdated
]:
def_sx.append(inst, qargs, cargs)
_sel.add_equivalence(SXGate(), def_sx)

# CSXGate

q = QuantumRegister(2, 'q')
def_csx = QuantumCircuit(q)
for inst, qargs, cargs in [
(HGate(), [q[1]], []),
(CU1Gate(pi / 2), [q[0], q[1]], []),
(HGate(), [q[1]], [])
]:
def_csx.append(inst, qargs, cargs)
_sel.add_equivalence(CSXGate(), def_csx)

# DCXGate

q = QuantumRegister(2, 'q')
Expand Down Expand Up @@ -384,6 +410,18 @@
u3_qasm_def.rz(phi+3*pi, 0)
_sel.add_equivalence(U3Gate(theta, phi, lam), u3_qasm_def)

q = QuantumRegister(1, 'q')
theta = Parameter('theta')
phi = Parameter('phi')
lam = Parameter('lam')
u3_qasm_def = QuantumCircuit(q)
u3_qasm_def.rz(lam, 0)
u3_qasm_def.sxdg(0)
u3_qasm_def.rz(theta+pi, 0)
u3_qasm_def.sxdg(0)
Comment thread
Cryoris marked this conversation as resolved.
Outdated
u3_qasm_def.rz(phi+3*pi, 0)
_sel.add_equivalence(U3Gate(theta, phi, lam), u3_qasm_def)

# CU3Gate

q = QuantumRegister(2, 'q')
Expand Down
258 changes: 258 additions & 0 deletions qiskit/circuit/library/standard_gates/sx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Sqrt(X) and C-Sqrt(X) gates."""

import numpy
from qiskit.qasm import pi
from qiskit.circuit.controlledgate import ControlledGate
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister


class SXGate(Gate):
r"""The single-qubit Sqrt(X) gate (:math:`\sqrt{X}`).

**Matrix Representation:**

.. math::

\sqrt{X} = \frac{1}{2} \begin{pmatrix}
1 + i & 1 - i \\
1 - i & 1 + i
\end{pmatrix}

**Circuit symbol:**

.. parsed-literal::

┌────┐
q_0: ┤ √X ├
└────┘

.. note::

A global phase difference exists between the definitions of
:math:`RX(\pi/2)` and :math:`\sqrt{X}`.

.. math::

RX(\pi/2) = \frac{1}{\sqrt{2}} \begin{pmatrix}
1 & -i \\
-i & 1
\end{pmatrix}
= e^{-i pi/4} \sqrt{X}

"""

def __init__(self, label='√X'):
"""Create new SX gate."""
super().__init__('sx', 1, [], label=label)

def _define(self):
"""
gate sx a { rz(-pi/2) a; h a; rz(-pi/2); }
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .rz import RZGate
from .h import HGate
q = QuantumRegister(1, 'q')
qc = QuantumCircuit(q, name=self.name)
rules = [
(RZGate(-pi / 2), [q[0]], []),
(HGate(), [q[0]], []),
(RZGate(-pi / 2), [q[0]], [])
]
qc.data = rules
self.definition = qc

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Return a (multi-)controlled-SX gate.

One control returns a CSX gate.

Args:
num_ctrl_qubits (int): number of control qubits.
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.

Returns:
ControlledGate: controlled version of this gate.
"""
if num_ctrl_qubits == 1:
gate = CSXGate(label=label, ctrl_state=ctrl_state)
gate.base_gate.label = self.label
return gate
return super().control(num_ctrl_qubits=num_ctrl_qubits, label=label, ctrl_state=ctrl_state)

# Differs by global phase of exp(-i pi/4) with correct RZ.
# If the RZ == U1, then the global phase difference is exp(i pi/4)
# TODO: Restore after allowing phase on circuits.
# def to_matrix(self):
# """Return a numpy.array for the SX gate."""
# return numpy.array([[1 + 1j, 1 - 1j],
# [1 - 1j, 1 + 1j]], dtype=complex) / 2


class SXdgGate(Gate):
r"""The inverse single-qubit Sqrt(X) gate.

.. math::

\sqrt{X}^{\dagger} = \frac{1}{2} \begin{pmatrix}
1 - i & 1 + i \\
1 + i & 1 - i
\end{pmatrix}


.. note::

A global phase difference exists between the definitions of
:math:`RX(-\pi/2)` and :math:`\sqrt{X}^{\dagger}`.

.. math::

RX(-\pi/2) = \frac{1}{\sqrt{2}} \begin{pmatrix}
1 & i \\
i & 1
\end{pmatrix}
= e^{-i pi/4} \sqrt{X}^{\dagger}

"""

def __init__(self, label='√X_dg'):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This would be similar to how sdg and tdg are rendered.

Suggested change
def __init__(self, label='√X_dg'):
def __init__(self, label='√X^†'):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also I noticed this will draw as two columns in the mpl drawer, but you can fix that by adding it to the list of standard gates on line 704 of visualization/matplotlib.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

also it would be good to have some consistency between this and other "daggered" gates in the text drawer.
because Sdg and Tdg don't have labels set, like this one, they draw with their name so they look like:

image

Also since text-drawer doesn't have math mode the exponent doesn't show well. What's the best way to fix this?

I'm being nit-picky on these because they will end up being shown very prominently when we translate to these basis.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not sure about the text drawer, maybe it is really S^†, alternatively S† or -- looking at the list of ascii superscript characters, S⁺ (small plus)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Turns out that the dagger sign causes a test to fail, which says that only Code page 437 symbols are allowed. @1ucian0 is that because other symbols might not get rendered on different machines or what's the reason for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looking at the available symbols from this page I switched back to _dg for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@1ucian0 why can't we support symbols outside of that list?

"""Create new SXdg gate."""
super().__init__('sxdg', 1, [], label=label)

def _define(self):
"""
gate sxdg a { rz(pi/2) a; h a; rz(pi/2); }
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .rz import RZGate
from .h import HGate
q = QuantumRegister(1, 'q')
qc = QuantumCircuit(q, name=self.name)
rules = [
(RZGate(pi / 2), [q[0]], []),
(HGate(), [q[0]], []),
(RZGate(pi / 2), [q[0]], [])
]
qc.data = rules
self.definition = qc

# Differs by global phase of exp(-i pi/4) with correct RZ.
# If the RZ == U1, then the global phase difference is exp(i pi/4)
# TODO: Restore after allowing phase on circuits.
# def to_matrix(self):
# """Return a numpy.array for the SX gate."""
# return numpy.array([[1 - 1j, 1 + 1j],
# [1 + 1j, 1 - 1j]], dtype=complex) / 2


class CSXGate(ControlledGate):
r"""Controlled-√X gate.

**Circuit symbol:**

.. parsed-literal::

q_0: ──■──
┌─┴──┐
q_1: ┤ √X ├
└────┘

**Matrix representation:**

.. math::

C\sqrt{X} \ q_0, q_1 =
I \otimes |0 \rangle\langle 0| + \sqrt{X} \otimes |1 \rangle\langle 1| =
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & (1 + i) / 2 & 0 & (1 - i) / 2 \\
0 & 0 & 1 & 0 \\
0 & (1 - i) / 2 & 0 & (1 + i) / 2
\end{pmatrix}


.. note::

In Qiskit's convention, higher qubit indices are more significant
(little endian convention). In many textbooks, controlled gates are
presented with the assumption of more significant qubits as control,
which in our case would be `q_1`. Thus a textbook matrix for this
gate will be:

.. parsed-literal::
┌────┐
q_0: ┤ √X ├
└─┬──┘
q_1: ──■──

.. math::

C\sqrt{X}\ q_1, q_0 =
|0 \rangle\langle 0| \otimes I + |1 \rangle\langle 1| \otimes \sqrt{X} =
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & (1 + i) / 2 & (1 - i) / 2 \\
0 & 0 & (1 - i) / 2 & (1 + i) / 2
\end{pmatrix}

"""
# Define class constants. This saves future allocation time.
_matrix1 = numpy.array([[1, 0, 0, 0],
[0, (1 + 1j) / 2, 0, (1 - 1j) / 2],
[0, 0, 1, 0],
[0, (1 - 1j) / 2, 0, (1 + 1j) / 2]], dtype=complex)
_matrix0 = numpy.array([[(1 + 1j) / 2, 0, (1 - 1j) / 2, 0],
[0, 1, 0, 0],
[(1 - 1j) / 2, 0, (1 + 1j) / 2, 0],
[0, 0, 0, 1]], dtype=complex)

def __init__(self, label=None, ctrl_state=None):
"""Create new CSX gate."""
super().__init__('csx', 2, [], num_ctrl_qubits=1, label=label,
ctrl_state=ctrl_state)
self.base_gate = SXGate()

def _define(self):
"""
gate csx a,b { h b; cu1(pi/2) a,b; h b; }
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .h import HGate
from .u1 import CU1Gate
q = QuantumRegister(2, 'q')
qc = QuantumCircuit(q, name=self.name)
rules = [
(HGate(), [q[1]], []),
(CU1Gate(pi/2), [q[0], q[1]], []),
(HGate(), [q[1]], [])
]
qc.data = rules
self.definition = qc

def to_matrix(self):
"""Return a numpy.array for the CSX gate."""
if self.ctrl_state:
return self._matrix1
else:
return self._matrix0
16 changes: 16 additions & 0 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1908,6 +1908,22 @@ def fredkin(self, control_qubit, target_qubit1, target_qubit2,
"""Apply :class:`~qiskit.circuit.library.CSwapGate`."""
return self.cswap(control_qubit, target_qubit1, target_qubit2)

def sx(self, qubit):
"""Apply :class:`~qiskit.circuit.library.SXGate`."""
from .library.standard_gates.sx import SXGate
return self.append(SXGate(), [qubit], [])

def sxdg(self, qubit):
"""Apply :class:`~qiskit.circuit.library.SXdgGate`."""
from .library.standard_gates.sx import SXdgGate
return self.append(SXdgGate(), [qubit], [])

def csx(self, control_qubit, target_qubit, label=None, ctrl_state=None):
"""Apply :class:`~qiskit.circuit.library.CSXGate`."""
from .library.standard_gates.sx import CSXGate
return self.append(CSXGate(label=label, ctrl_state=ctrl_state),
[control_qubit, target_qubit], [])

@deprecate_arguments({'q': 'qubit'})
def t(self, qubit, *, q=None): # pylint: disable=invalid-name,unused-argument
"""Apply :class:`~qiskit.circuit.library.TGate`."""
Expand Down
Loading