Skip to content
27 changes: 17 additions & 10 deletions qiskit/circuit/add_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,18 @@ def control(operation: Union[Gate, ControlledGate],
operation.base_gate.name == 'x'):
qc.mct(q_control[:] + q_target[:-1], q_target[-1], q_ancillae)
elif operation.name == 'rx':
qc.mcrx(operation.definition[0][0].params[0], q_control, q_target[0],
qc.mcrx(operation.definition.data[0][0].params[0], q_control, q_target[0],
use_basis_gates=True)
elif operation.name == 'ry':
qc.mcry(operation.definition[0][0].params[0], q_control, q_target[0],
qc.mcry(operation.definition.data[0][0].params[0], q_control, q_target[0],
q_ancillae, mode='noancilla', use_basis_gates=True)
elif operation.name == 'rz':
qc.mcrz(operation.definition[0][0].params[0], q_control, q_target[0],
qc.mcrz(operation.definition.data[0][0].params[0], q_control, q_target[0],
use_basis_gates=True)
else:
bgate = _unroll_gate(operation, ['u1', 'u3', 'cx'])
# now we have a bunch of single qubit rotation gates and cx
for rule in bgate.definition:
for rule in bgate.definition.data:
if rule[0].name == 'u3':
theta, phi, lamb = rule[0].params
if phi == -pi / 2 and lamb == pi / 2:
Expand All @@ -150,7 +150,6 @@ def control(operation: Union[Gate, ControlledGate],
else:
raise CircuitError('gate contains non-controllable instructions')

instr = qc.to_instruction()
if isinstance(operation, controlledgate.ControlledGate):
new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits
new_ctrl_state = operation.ctrl_state << num_ctrl_qubits | ctrl_state
Expand All @@ -171,11 +170,11 @@ def control(operation: Union[Gate, ControlledGate],
ctrl_substr = ('{0}' * new_num_ctrl_qubits).format('c')
new_name = '{0}{1}'.format(ctrl_substr, base_name)
cgate = controlledgate.ControlledGate(new_name,
instr.num_qubits,
qc.num_qubits,
operation.params,
label=label,
num_ctrl_qubits=new_num_ctrl_qubits,
definition=instr.definition,
definition=qc,
ctrl_state=new_ctrl_state)
cgate.base_gate = base_gate
return cgate
Expand All @@ -185,7 +184,7 @@ def _gate_to_circuit(operation):
qr = QuantumRegister(operation.num_qubits)
qc = QuantumCircuit(qr, name=operation.name)
if hasattr(operation, 'definition') and operation.definition:
for rule in operation.definition:
for rule in operation.definition.data:
if rule[0].name in {'id', 'barrier', 'measure', 'snapshot'}:
raise CircuitError('Cannot make controlled gate with {} instruction'.format(
rule[0].name))
Expand All @@ -194,12 +193,20 @@ def _gate_to_circuit(operation):
qc.append(operation, qargs=qr, cargs=[])
return qc

def _gate_to_dag(operation):
from qiskit.converters.circuit_to_dag import circuit_to_dag
if hasattr(operation, 'definition') and operation.definition:
return circuit_to_dag(operation.definition)
else:
qr = QuantumRegister(operation.num_qubits)
qc = QuantumCircuit(qr, name=operation.name)
qc.append(operation, qr)
return circuit_to_dag(qc)

def _unroll_gate(operation, basis_gates):
from qiskit.converters.circuit_to_dag import circuit_to_dag
from qiskit.converters.dag_to_circuit import dag_to_circuit
from qiskit.transpiler.passes import Unroller
unroller = Unroller(basis_gates)
dag = circuit_to_dag(_gate_to_circuit(operation))
dag = _gate_to_dag(operation)
qc = dag_to_circuit(unroller.run(dag))
return qc.to_gate()
35 changes: 18 additions & 17 deletions qiskit/circuit/controlledgate.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@

"""Controlled unitary gate."""

from typing import Tuple, List, Optional, Union
from typing import List, Optional, Union
from qiskit.circuit.exceptions import CircuitError

from .gate import Gate
from .quantumregister import QuantumRegister
from .quantumregister import Qubit
from .classicalregister import Clbit

# pylint: disable=missing-return-doc

Expand All @@ -30,7 +28,7 @@ class ControlledGate(Gate):

def __init__(self, name: str, num_qubits: int, params: List,
label: Optional[str] = None, num_ctrl_qubits: Optional[int] = 1,
definition: Optional[List[Tuple[Gate, List[Qubit], List[Clbit]]]] = None,
definition: Optional['QuantumCircuit'] = None,
ctrl_state: Optional[Union[int, str]] = None):
"""Create a new ControlledGate. In the new gate the first ``num_ctrl_qubits``
of the gate are the controls.
Expand Down Expand Up @@ -90,8 +88,8 @@ def __init__(self, name: str, num_qubits: int, params: List,
self.base_gate = None
if definition:
self.definition = definition
if len(definition) == 1:
base_gate = definition[0][0]
if len(definition.data) == 1:
base_gate = definition.data[0][0]
if isinstance(base_gate, ControlledGate):
self.base_gate = base_gate.base_gate
else:
Expand All @@ -106,28 +104,31 @@ def definition(self) -> List:
definition is conjugated with X without changing the internal
`_definition`.
"""
# pylint: disable=cyclic-import
from qiskit import QuantumCircuit
if self._open_ctrl:
closed_gate = self.copy()
closed_gate.ctrl_state = None
# pylint: disable=cyclic-import
from qiskit.circuit.library.standard_gates import XGate
bit_ctrl_state = bin(self.ctrl_state)[2:].zfill(self.num_ctrl_qubits)
qreg = QuantumRegister(self.num_qubits, 'q')
definition = [(closed_gate, qreg, [])]
open_rules = []
qc_open_ctrl = QuantumCircuit(qreg)
for qind, val in enumerate(bit_ctrl_state[::-1]):
if val == '0':
open_rules.append([XGate(), [qreg[qind]], []])
if open_rules:
return open_rules + definition + open_rules
else:
return self._definition
qc_open_ctrl.x(qind)
qc_open_ctrl.append(closed_gate, qargs=qreg[:])
for qind, val in enumerate(bit_ctrl_state[::-1]):
if val == '0':
qc_open_ctrl.x(qind)
return qc_open_ctrl
else:
return super().definition

@definition.setter
def definition(self, excited_def: List):
"""Set controlled gate definition with closed controls."""
def definition(self, excited_def: 'QuantumCircuit'):
"""Set controlled gate definition with closed controls.

Args:
excited_def: The circuit with all closed controls."""
super(Gate, self.__class__).definition.fset(self, excited_def)

@property
Expand Down
32 changes: 23 additions & 9 deletions qiskit/circuit/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,14 @@ def definition(self):
return self._definition

@definition.setter
def definition(self, array):
"""Set matrix representation"""
self._definition = array
def definition(self, definition):
"""Set gate representation"""
# pylint: disable=cyclic-import
from qiskit import QuantumCircuit
if not isinstance(definition, QuantumCircuit) and definition is not None:
raise CircuitError('Instruction "{}" definition must be QuantumCircuit. Got {}'.format(
self.name, type(definition)))
self._definition = definition
Comment thread
ewinston marked this conversation as resolved.
Outdated

@property
def decompositions(self):
Expand Down Expand Up @@ -246,9 +251,9 @@ def reverse_ops(self):
return self.copy()

reverse_inst = self.copy(name=self.name + '_reverse')
reverse_inst.definition = []
reverse_inst.definition.data = []
for inst, qargs, cargs in reversed(self._definition):
reverse_inst._definition.append((inst.reverse_ops(), qargs, cargs))
reverse_inst._definition.data.append((inst.reverse_ops(), qargs, cargs))
return reverse_inst

def inverse(self):
Expand All @@ -270,9 +275,9 @@ def inverse(self):
if self.definition is None:
raise CircuitError("inverse() not implemented for %s." % self.name)
inverse_gate = self.copy(name=self.name + '_dg')
inverse_gate._definition = []
for inst, qargs, cargs in reversed(self._definition):
inverse_gate._definition.append((inst.inverse(), qargs, cargs))
inverse_gate._definition.data = []
for inst, qargs, cargs in reversed(self._definition.data):
inverse_gate._definition.data.append((inst.inverse(), qargs, cargs))
return inverse_gate

def c_if(self, classical, val):
Expand Down Expand Up @@ -377,5 +382,14 @@ def repeat(self, n):
qargs = [] if self.num_qubits == 0 else QuantumRegister(self.num_qubits, 'q')
cargs = [] if self.num_clbits == 0 else ClassicalRegister(self.num_clbits, 'c')

instruction.definition = [(self, qargs[:], cargs[:])] * n
if instruction.definition is None:
# pylint: disable=cyclic-import
from qiskit import QuantumCircuit
qc = QuantumCircuit()
if qargs:
qc.add_register(qargs)
if cargs:
qc.add_register(cargs)
qc.data = [(self, qargs[:], cargs[:])] * n
instruction.definition = qc
return instruction
7 changes: 6 additions & 1 deletion qiskit/circuit/library/standard_gates/dcx.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,17 @@ def _define(self):
"""
gate dcx a, b { cx a, b; cx a, b; }
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .x import CXGate
q = QuantumRegister(2, 'q')
self.definition = [
qc = QuantumCircuit(q, name=self.name)
rules = [
(CXGate(), [q[0], q[1]], []),
(CXGate(), [q[1], q[0]], [])
]
qc.data = rules
self.definition = qc

def to_matrix(self):
"""Return a numpy.array for the DCX gate."""
Expand Down
22 changes: 12 additions & 10 deletions qiskit/circuit/library/standard_gates/h.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,16 @@ def _define(self):
"""
gate h a { u2(0,pi) a; }
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .u2 import U2Gate
definition = []
q = QuantumRegister(1, 'q')
rule = [
qc = QuantumCircuit(q, name=self.name)
rules = [
(U2Gate(0, pi), [q[0]], [])
]
for inst in rule:
definition.append(inst)
self.definition = definition
qc.data = rules
self.definition = qc

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Return a (multi-)controlled-H gate.
Expand Down Expand Up @@ -181,10 +182,12 @@ def _define(self):
sdg b;
}
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .x import CXGate # pylint: disable=cyclic-import
definition = []
q = QuantumRegister(2, 'q')
rule = [
qc = QuantumCircuit(q, name=self.name)
rules = [
(SGate(), [q[1]], []),
(HGate(), [q[1]], []),
(TGate(), [q[1]], []),
Expand All @@ -193,9 +196,8 @@ def _define(self):
(HGate(), [q[1]], []),
(SdgGate(), [q[1]], [])
]
for inst in rule:
definition.append(inst)
self.definition = definition
qc.data = rules
self.definition = qc

def inverse(self):
"""Return inverted CH gate (itself)."""
Expand Down
7 changes: 6 additions & 1 deletion qiskit/circuit/library/standard_gates/iswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,23 @@ def _define(self):
h q[1];
}
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .h import HGate
from .s import SGate
from .x import CXGate
q = QuantumRegister(2, 'q')
self.definition = [
qc = QuantumCircuit(q, name=self.name)
rules = [
(SGate(), [q[0]], []),
(SGate(), [q[1]], []),
(HGate(), [q[0]], []),
(CXGate(), [q[0], q[1]], []),
(CXGate(), [q[1], q[0]], []),
(HGate(), [q[1]], [])
]
qc.data = rules
self.definition = qc

def to_matrix(self):
"""Return a numpy.array for the iSWAP gate."""
Expand Down
14 changes: 7 additions & 7 deletions qiskit/circuit/library/standard_gates/ms.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ def __init__(self, num_qubits, theta, *, n_qubits=None, # pylint:disable=unused
super().__init__('ms', num_qubits, [theta], label=label)

def _define(self):
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .rxx import RXXGate
definition = []
q = QuantumRegister(self.num_qubits, 'q')
rule = []
qc = QuantumCircuit(q, name=self.name)
rules = []
for i in range(self.num_qubits):
for j in range(i + 1, self.num_qubits):
rule += [(RXXGate(self.params[0]), [q[i], q[j]], [])]

for inst in rule:
definition.append(inst)
self.definition = definition
rules += [(RXXGate(self.params[0]), [q[i], q[j]], [])]
qc.data = rules
self.definition = qc
11 changes: 6 additions & 5 deletions qiskit/circuit/library/standard_gates/r.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,18 @@ def _define(self):
"""
gate r(θ, φ) a {u3(θ, φ - π/2, -φ + π/2) a;}
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .u3 import U3Gate
definition = []
q = QuantumRegister(1, 'q')
qc = QuantumCircuit(q, name=self.name)
theta = self.params[0]
phi = self.params[1]
rule = [
rules = [
(U3Gate(theta, phi - pi / 2, -phi + pi / 2), [q[0]], [])
]
for inst in rule:
definition.append(inst)
self.definition = definition
qc.data = rules
self.definition = qc

def inverse(self):
"""Invert this gate.
Expand Down
Loading