Skip to content

Commit

Permalink
use a list of Gate for a Gate.definition, decompose based on that
Browse files Browse the repository at this point in the history
  • Loading branch information
ajavadia committed Mar 12, 2019
1 parent 5543cd8 commit 3968684
Show file tree
Hide file tree
Showing 34 changed files with 212 additions and 258 deletions.
76 changes: 49 additions & 27 deletions qiskit/circuit/gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,50 +21,67 @@ def __init__(self, name, num_qubits, params, circuit=None):
params = list of real parameters (will be converted to symbolic)
circuit = QuantumCircuit containing this gate
"""
# list of instructions (and their contexts) that this instruction is composed of
# self.definition=None means opaque or fundamental
self._definition = None
self._matrix_rep = None

super().__init__(name, num_qubits, 0, params, circuit)

def reverse(self):
"""For a composite gate, reverse the order of sub-gates.
This is done by recursively reversing all sub-gates. It does
not invert any gate.
Returns:
Gate: a fresh gate with sub-gates reversed
"""
if not self._definition:
return self.copy()

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

def inverse(self):
"""Invert this gate.
If the gate is composite (i.e. has decomposition rules), then those
rules will be recursively inverted.
If the gate is composite (i.e. has a definition), then its definition
will be recursively inverted.
Special gates inheriting from Gate can implement their own inverse
(e.g. T and Tdg)
Returns:
Gate: the inverted gate
Gate: a fresh gate for the inverse
Raises:
NotImplementedError: if the gate is not composite and an inverse
has not been implemented for it.
"""
from qiskit.circuit import QuantumCircuit
from qiskit.converters import dag_to_circuit, circuit_to_dag
if not self._decompositions:
raise NotImplementedError("inverse not implemented")
inverse_inst = self.copy(name=self.name+'_dg')
new_decompositions = []
for decomposition in self._decompositions:
circ = dag_to_circuit(decomposition)
new_circ = QuantumCircuit(*circ.qregs, *circ.cregs)
for inst, qargs, cargs in reversed(circ.data):
new_circ.append(inst.inverse(), qargs, cargs)
new_decompositions.append(circuit_to_dag(new_circ))
inverse_inst._decompositions = new_decompositions
return inverse_inst

def decompositions(self):
"""Returns a list of possible decompositions. """
if self._decompositions is None:
self._define_decompositions()
return self._decompositions

def _define_decompositions(self):
"""Populates self.decompositions with way to decompose this instruction."""
raise NotImplementedError("No decomposition rules defined for %s" % self.name)
if not self.definition:
raise NotImplementedError("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))
return inverse_gate

@property
def definition(self):
"""Return definition in terms of other basic gates."""
if self._definition is None:
self._define()
return self._definition

@definition.setter
def definition(self, array):
"""Set matrix representation"""
self._definition = array

@property
def matrix_rep(self):
Expand All @@ -75,3 +92,8 @@ def matrix_rep(self):
def matrix_rep(self, matrix):
"""Set matrix representation"""
self._matrix_rep = matrix

def _define(self):
"""Populates self.definition with a decomposition of this gate."""
raise NotImplementedError("No definition for %s (cannot decompose)." %
self.name)
31 changes: 3 additions & 28 deletions qiskit/circuit/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ def __init__(self, name, num_qubits, num_clbits, params, circuit=None):
else:
raise QiskitError("invalid param type {0} in instruction "
"{1}".format(type(single_param), name))
self.control = None # tuple (ClassicalRegister, int) for "if"
# tuple (ClassicalRegister, int) when the instruction has a conditional ("if")
self.control = None
# reference to the circuit containing this instruction
self.circuit = circuit
self._decompositions = None

def __eq__(self, other):
"""Two instructions are the same if they have the same name and same
Expand Down Expand Up @@ -127,32 +128,6 @@ def copy(self, name=None):
cpy.name = name
return cpy

def reverse(self):
"""For a composite instruction, reverse the order of sub-instructions.
This is done by recursively reversing all sub-instructions. It does
not invert any gate.
Returns:
Instruction: a fresh instruction with sub-instructions reversed
"""
# TODO: this function is ugly and must be redone, possible after
# circuit and DAG merge.
from qiskit.circuit import QuantumCircuit
from qiskit.converters import dag_to_circuit, circuit_to_dag
if not self._decompositions:
return self
reverse_inst = self.copy(name=self.name+'_reverse')
new_decompositions = []
for decomposition in self._decompositions:
circ = dag_to_circuit(decomposition)
new_circ = QuantumCircuit(*circ.qregs, *circ.cregs)
for inst, qargs, cargs in reversed(circ.data):
new_circ.append(inst.reverse(), qargs, cargs)
new_decompositions.append(circuit_to_dag(new_circ))
reverse_inst._decompositions = new_decompositions
return reverse_inst

def _modifiers(self, gate):
"""Apply any modifiers of this instruction to another one."""
if self.control is not None:
Expand Down
9 changes: 2 additions & 7 deletions qiskit/circuit/reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"""
Qubit reset to computational zero.
"""
from qiskit.circuit import QuantumCircuit, QuantumRegister
from qiskit.circuit import Instruction, InstructionSet
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import Instruction
from .decorators import _op_expand


Expand All @@ -24,11 +24,6 @@ def __init__(self, circ=None):
@_op_expand(1)
def reset(self, qubit):
"""Reset q."""
if isinstance(qubit, QuantumRegister):
instructions = InstructionSet()
for sizes in range(qubit.size):
instructions.add(self.reset((qubit, sizes)))
return instructions
return self.append(Reset(self), [qubit], [])


Expand Down
3 changes: 1 addition & 2 deletions qiskit/converters/circuit_to_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from qiskit.exceptions import QiskitError
from qiskit.circuit import Gate
from qiskit.circuit import Reset
from qiskit.converters import circuit_to_dag


def circuit_to_gate(circuit):
Expand Down Expand Up @@ -42,6 +41,6 @@ def circuit_to_gate(circuit):
instruction.control = None
instruction.circuit = None

instruction._decompositions = [circuit_to_dag(circuit)]
instruction.definition = circuit.data

return instruction
6 changes: 2 additions & 4 deletions qiskit/extensions/quantum_initializer/_initializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from qiskit.extensions.standard.cx import CnotGate
from qiskit.extensions.standard.ry import RYGate
from qiskit.extensions.standard.rz import RZGate
from qiskit.converters import circuit_to_dag


_EPS = 1e-10 # global variable used to chop very small numbers to zero
Expand Down Expand Up @@ -54,7 +53,7 @@ def __init__(self, params, circ=None):

super().__init__("init", num_qubits, params, circ)

def _define_decompositions(self):
def _define(self):
"""Calculate a subcircuit that implements this initialization
Implements a recursive initialization algorithm, including optimizations,
Expand All @@ -77,7 +76,7 @@ def _define_decompositions(self):
# TODO: avoid explicit reset if compiler determines a |0> state
initialize_circuit.append(initialize_gate, q[:])

self._decompositions = [circuit_to_dag(initialize_circuit)]
self.definition = initialize_circuit.data

def gates_to_uncompute(self):
"""
Expand Down Expand Up @@ -106,7 +105,6 @@ def gates_to_uncompute(self):
ry_mult = self._multiplex(RYGate, thetas)
circuit.append(rz_mult.to_gate(), q[i:self.num_qubits])
circuit.append(ry_mult.to_gate(), q[i:self.num_qubits])

return circuit

@staticmethod
Expand Down
10 changes: 4 additions & 6 deletions qiskit/extensions/standard/ccx.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister
from qiskit.circuit.decorators import _op_expand
from qiskit.dagcircuit import DAGCircuit
from qiskit.extensions.standard.h import HGate
from qiskit.extensions.standard.cx import CnotGate
from qiskit.extensions.standard.t import TGate
Expand All @@ -27,7 +26,7 @@ def __init__(self, circ=None):
"""Create new Toffoli gate."""
super().__init__("ccx", 3, [], circ)

def _define_decompositions(self):
def _define(self):
"""
gate ccx a,b,c
{
Expand All @@ -36,9 +35,8 @@ def _define_decompositions(self):
t b; t c; h c; cx a,b;
t a; tdg b; cx a,b;}
"""
decomposition = DAGCircuit()
definition = []
q = QuantumRegister(3, "q")
decomposition.add_qreg(q)
rule = [
(HGate(), [q[2]], []),
(CnotGate(), [q[1], q[2]], []),
Expand All @@ -57,8 +55,8 @@ def _define_decompositions(self):
(CnotGate(), [q[0], q[1]], [])
]
for inst in rule:
decomposition.apply_operation_back(*inst)
self._decompositions = [decomposition]
definition.append(inst)
self.definition = definition

def inverse(self):
"""Invert this gate."""
Expand Down
10 changes: 4 additions & 6 deletions qiskit/extensions/standard/ch.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister
from qiskit.circuit.decorators import _op_expand
from qiskit.dagcircuit import DAGCircuit
from qiskit.extensions.standard.x import XGate
from qiskit.extensions.standard.h import HGate
from qiskit.extensions.standard.cx import CnotGate
Expand All @@ -31,7 +30,7 @@ def __init__(self, circ=None):
"""Create new CH gate."""
super().__init__("ch", 2, [], circ)

def _define_decompositions(self):
def _define(self):
"""
gate ch a,b {
h b;
Expand All @@ -46,9 +45,8 @@ def _define_decompositions(self):
x b;
s a;}
"""
decomposition = DAGCircuit()
definition = []
q = QuantumRegister(2, "q")
decomposition.add_qreg(q)
rule = [
(HGate(), [q[1]], []),
(SdgGate(), [q[1]], []),
Expand All @@ -63,8 +61,8 @@ def _define_decompositions(self):
(SGate(), [q[0]], [])
]
for inst in rule:
decomposition.apply_operation_back(*inst)
self._decompositions = [decomposition]
definition.append(inst)
self.definition = definition

def inverse(self):
"""Invert this gate."""
Expand Down
12 changes: 5 additions & 7 deletions qiskit/extensions/standard/crz.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister
from qiskit.circuit.decorators import _op_expand
from qiskit.dagcircuit import DAGCircuit
from qiskit.extensions.standard.u1 import U1Gate
from qiskit.extensions.standard.cx import CnotGate

Expand All @@ -25,30 +24,29 @@ def __init__(self, theta, circ=None):
"""Create new crz gate."""
super().__init__("crz", 2, [theta], circ)

def _define_decompositions(self):
def _define(self):
"""
gate crz(lambda) a,b
{ u1(lambda/2) b; cx a,b;
u1(-lambda/2) b; cx a,b;
}
"""
decomposition = DAGCircuit()
definition = []
q = QuantumRegister(2, "q")
decomposition.add_qreg(q)
rule = [
(U1Gate(self.params[0]/2), [q[1]], []),
(CnotGate(), [q[0], q[1]], []),
(U1Gate(-self.params[0]/2), [q[1]], []),
(CnotGate(), [q[0], q[1]], [])
]
for inst in rule:
decomposition.apply_operation_back(*inst)
self._decompositions = [decomposition]
definition.append(inst)
self.definition = definition

def inverse(self):
"""Invert this gate."""
self.params[0] = -self.params[0]
self._decompositions = None
self.definition = None
return self


Expand Down
10 changes: 4 additions & 6 deletions qiskit/extensions/standard/cswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from qiskit.circuit import QuantumCircuit
from qiskit.circuit import QuantumRegister
from qiskit.circuit.decorators import _op_expand
from qiskit.dagcircuit import DAGCircuit
from qiskit.extensions.standard.cx import CnotGate
from qiskit.extensions.standard.ccx import ToffoliGate

Expand All @@ -25,25 +24,24 @@ def __init__(self, circ=None):
"""Create new Fredkin gate."""
super().__init__("cswap", 3, [], circ)

def _define_decompositions(self):
def _define(self):
"""
gate cswap a,b,c
{ cx c,b;
ccx a,b,c;
cx c,b;
}
"""
decomposition = DAGCircuit()
definition = []
q = QuantumRegister(3, "q")
decomposition.add_qreg(q)
rule = [
(CnotGate(), [q[2], q[1]], []),
(ToffoliGate(), [q[0], q[1], q[2]], []),
(CnotGate(), [q[2], q[1]], [])
]
for inst in rule:
decomposition.apply_operation_back(*inst)
self._decompositions = [decomposition]
definition.append(inst)
self.definition = definition

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

0 comments on commit 3968684

Please sign in to comment.