Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1ff2894
port mcu1 from function to gate
Cryoris Feb 24, 2020
b58ad75
update init, remove old implementation
Cryoris Feb 24, 2020
72ae9c9
fix tests
Cryoris Feb 24, 2020
fdb71fd
fix cyclic import by full path
Cryoris Feb 25, 2020
d321650
Merge branch 'master' of github.com:Qiskit/qiskit-terra into implemen…
Cryoris Feb 25, 2020
79571db
make `control` use MCU1
Cryoris Feb 25, 2020
5fdba01
Merge branch 'master' into implement-mcu1-gate
Cryoris Feb 26, 2020
eb81bb2
mcu1 already importet via u1.py
Cryoris Feb 26, 2020
9222c8d
Merge branch 'master' of github.com:Qiskit/qiskit-terra into implemen…
Cryoris Feb 27, 2020
b0ee263
implement review changes and fix tests
Cryoris Feb 27, 2020
0813029
Merge branch 'master' of github.com:Qiskit/qiskit-terra into implemen…
Cryoris Mar 4, 2020
91b6aac
apply changes of the review
Cryoris Mar 4, 2020
9c6cec2
Merge branch 'master' into implement-mcu1-gate
Cryoris Mar 24, 2020
1dfccda
move MCU1 into CU1
Cryoris Mar 24, 2020
7bb7d12
try to fix docstring error?
Cryoris Mar 24, 2020
9194785
move gray code logic to external function
Cryoris Mar 25, 2020
e6a5c5e
circumvent special case distinction for CU1Gate
Cryoris Mar 25, 2020
1e691ee
Merge branch 'master' into implement-mcu1-gate
Cryoris Mar 25, 2020
f78df2f
keep mode 'noancilla'
Cryoris Mar 25, 2020
d07531d
move generate gray code to u3
Cryoris Mar 25, 2020
6191586
move determination of num free params to utils
Cryoris Mar 25, 2020
ce58bcd
Merge branch 'master' into implement-mcu1-gate
Cryoris Mar 26, 2020
bf0035c
Merge branch 'master' into implement-mcu1-gate
Cryoris Mar 26, 2020
d4457d9
Merge branch 'master' into implement-mcu1-gate
Cryoris Apr 2, 2020
60440eb
revert to MCU1 as own class
Cryoris Apr 2, 2020
5991ba8
Merge branch 'implement-mcu1-gate' of github.com:Cryoris/qiskit-terra…
Cryoris Apr 2, 2020
3fb1091
Merge branch 'master' into implement-mcu1-gate
Cryoris Apr 2, 2020
7278b59
Merge branch 'master' into implement-mcu1-gate
mergify[bot] Apr 2, 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
9 changes: 4 additions & 5 deletions qiskit/circuit/add_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,10 @@ def control(operation: Union[Gate, ControlledGate],
# pylint: disable=unused-import
import qiskit.extensions.standard.multi_control_rotation_gates
import qiskit.extensions.standard.multi_control_toffoli_gate
import qiskit.extensions.standard.multi_control_u1_gate

q_control = QuantumRegister(num_ctrl_qubits, name='control')
q_target = QuantumRegister(operation.num_qubits, name='target')
q_ancillae = None # TODO: add
# q_ancillae = None # TODO: add
qc = QuantumCircuit(q_control, q_target)

if operation.name == 'x' or (
Expand All @@ -109,7 +108,7 @@ def control(operation: Union[Gate, ControlledGate],
use_basis_gates=True)
elif operation.name == 'ry':
qc.mcry(operation.definition[0][0].params[0], q_control, q_target[0],
q_ancillae, use_basis_gates=True)
None, mode='noancilla', use_basis_gates=True)
Comment thread
Cryoris marked this conversation as resolved.
Outdated
elif operation.name == 'rz':
qc.mcrz(operation.definition[0][0].params[0], q_control, q_target[0],
use_basis_gates=True)
Expand All @@ -124,15 +123,15 @@ def control(operation: Union[Gate, ControlledGate],
use_basis_gates=True)
elif phi == 0 and lamb == 0:
qc.mcry(theta, q_control, q_target[rule[1][0].index],
q_ancillae, mode='noancilla', use_basis_gates=True)
None, mode='noancilla', use_basis_gates=True)
elif theta == 0 and phi == 0:
qc.mcrz(lamb, q_control, q_target[rule[1][0].index],
use_basis_gates=True)
else:
qc.mcrz(lamb, q_control, q_target[rule[1][0].index],
use_basis_gates=True)
qc.mcry(theta, q_control, q_target[rule[1][0].index],
q_ancillae, use_basis_gates=True)
None, mode='noancilla', use_basis_gates=True)
qc.mcrz(phi, q_control, q_target[rule[1][0].index],
use_basis_gates=True)
elif rule[0].name == 'u1':
Expand Down
3 changes: 1 addition & 2 deletions qiskit/extensions/standard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@
from .s import SGate, SdgGate
from .swap import SwapGate, CSwapGate
from .t import TGate, TdgGate
from .u1 import U1Gate, CU1Gate
from .u1 import U1Gate, CU1Gate, MCU1Gate
from .u2 import U2Gate
from .u3 import U3Gate, CU3Gate
from .x import XGate, CXGate, CCXGate
from .y import YGate, CYGate
from .z import ZGate, CZGate

# to be converted to gates
from .multi_control_u1_gate import mcu1
from .multi_control_toffoli_gate import mct
from .multi_control_rotation_gates import mcrx, mcry, mcrz

Expand Down
111 changes: 0 additions & 111 deletions qiskit/extensions/standard/multi_control_u1_gate.py

This file was deleted.

152 changes: 152 additions & 0 deletions qiskit/extensions/standard/u1.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
if ctrl_state is None:
if num_ctrl_qubits == 1:
return CU1Gate(*self.params)
return MCU1Gate(*self.params, num_ctrl_qubits)
return super().control(num_ctrl_qubits=num_ctrl_qubits, label=label,
ctrl_state=ctrl_state)

Expand Down Expand Up @@ -143,6 +144,23 @@ def _define(self):
definition.append(inst)
self.definition = definition

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Controlled version of this 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 ctrl_state is None:
return MCU1Gate(*self.params, num_ctrl_qubits + 1)
return super().control(num_ctrl_qubits=num_ctrl_qubits, label=label,
ctrl_state=ctrl_state)

def inverse(self):
"""Invert this gate."""
return CU1Gate(-self.params[0])
Expand Down Expand Up @@ -185,3 +203,137 @@ def cu1(self, theta, control_qubit, target_qubit,


QuantumCircuit.cu1 = cu1


class MCU1Gate(ControlledGate):
"""The multi-controlled U1 gate."""

def __init__(self, lam, num_ctrl_qubits):
"""Create a new MCU1s gate."""
super().__init__('mcu1', num_ctrl_qubits + 1, [lam], num_ctrl_qubits=num_ctrl_qubits)
self.base_gate = U1Gate(lam)

def _define(self):
"""The gate definition of the multi-controlled U1 gate.

Ported from Aqua (github.com/Qiskit/qiskit-aqua),
commit 769ca8d, file qiskit/aqua/circuits/gates/multi_control_u1_gate.py.
"""
definition = []
q = QuantumRegister(self.num_qubits, 'q')
q_controls = q[:self.num_ctrl_qubits]
q_target = q[self.num_ctrl_qubits]
lam = self.params[0]
if self.num_ctrl_qubits == 0:
definition.append(
(U1Gate(lam), [q_target], [])
)
elif self.num_ctrl_qubits == 1:
definition.append(
(CU1Gate(lam), q_controls + [q_target], [])
)
else:
from qiskit.extensions.standard.x import CXGate
from sympy.combinatorics.graycode import GrayCode
gray_code = list(GrayCode(self.num_ctrl_qubits).generate_gray())
last_pattern = None

lam_angle = lam * (1 / (2**(self.num_ctrl_qubits - 1)))

for pattern in gray_code:
if '1' not in pattern:
continue
if last_pattern is None:
last_pattern = pattern
# find left most set bit
lm_pos = list(pattern).index('1')

# find changed bit
comp = [i != j for i, j in zip(pattern, last_pattern)]
if True in comp:
pos = comp.index(True)
else:
pos = None
if pos is not None:
if pos != lm_pos:
definition.append(
(CXGate(), [q_controls[pos], q_controls[lm_pos]], [])
)
else:
indices = [i for i, x in enumerate(pattern) if x == '1']
for idx in indices[1:]:
definition.append(
(CXGate(), [q_controls[idx], q_controls[lm_pos]], [])
)
# check parity
if pattern.count('1') % 2 == 0:
# inverse
definition.append(
(CU1Gate(-lam_angle), [q_controls[lm_pos], q_target], [])
)
else:
definition.append(
(CU1Gate(lam_angle), [q_controls[lm_pos], q_target], [])
)
last_pattern = pattern

self.definition = definition

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Controlled version of this 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 ctrl_state is None:
return MCU1Gate(*self.params, self.num_ctrl_qubits + num_ctrl_qubits)
return super().control(num_ctrl_qubits=self.num_ctrl_qubits + num_ctrl_qubits,
label=label,
ctrl_state=ctrl_state)

def inverse(self):
"""Invert this gate."""
return MCU1Gate(-self.params[0], self.num_ctrl_qubits)

def to_matrix(self):
"""Return a numpy.array for the multi-controlled U1 gate."""
lam = self.params[0]
if self.num_ctrl_qubits == 0:
return U1Gate(lam).to_matrix()
if self.num_ctrl_qubits == 1:
return CU1Gate(lam).to_matrix()

from qiskit.extensions.unitary import _compute_control_matrix
base_mat = U1Gate(lam).to_matrix()
return _compute_control_matrix(base_mat, self.num_ctrl_qubits)
Comment thread
Cryoris marked this conversation as resolved.
Outdated


def mcu1(self, lam, control_qubits, target_qubit):
"""Apply multi-cU1 gate from specified controls (control_qubits) to target (target_qubit) qubit
with angle ``lam``. A multi-cU1 gate implements a ``lam`` radian rotation of the qubit state
vector about the z axis of the Bloch sphere when the control qubits are all in state |1>.

Examples:

Circuit Representation:

.. jupyter-execute::

from qiskit.circuit import QuantumCircuit, Parameter

lam = Parameter('λ')
circuit = QuantumCircuit(4)
circuit.mcu1(lam, [0, 1, 2], 3)
circuit.draw()
"""
num_ctrl_qubits = len(control_qubits)
return self.append(MCU1Gate(lam, num_ctrl_qubits), control_qubits[:] + [target_qubit], [])


QuantumCircuit.mcu1 = mcu1
Loading