Skip to content

Commit

Permalink
Merge branch 'develop' into feature/QubitOperator
Browse files Browse the repository at this point in the history
  • Loading branch information
damiansteiger committed Apr 24, 2017
2 parents a2d7836 + 2ae3608 commit 0aa7b4b
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 46 deletions.
3 changes: 1 addition & 2 deletions projectq/backends/_ibm/_ibm_test.py
Expand Up @@ -57,8 +57,7 @@ def test_ibm_backend_is_available_control_not(num_ctrl_qubits, is_available):
qubit1 = eng.allocate_qubit()
qureg = eng.allocate_qureg(num_ctrl_qubits)
ibm_backend = _ibm.IBMBackend()
cmd = Command(eng, NOT, (qubit1,))
cmd.add_control_qubits(qureg)
cmd = Command(eng, NOT, (qubit1,), controls=qureg)
assert ibm_backend.is_available(cmd) == is_available


Expand Down
10 changes: 4 additions & 6 deletions projectq/ops/_basics.py
Expand Up @@ -170,12 +170,10 @@ def generate_command(self, qubits):
"""
qubits = self.make_tuple_of_qureg(qubits)

for i in range(len(qubits)):
for j in range(len(qubits[i]) - 1):
assert(qubits[i][j].engine == qubits[i][j + 1].engine)
if i < len(qubits) - 1:
assert(qubits[i][-1].engine == qubits[i + 1][0].engine)
return Command(qubits[0][0].engine, self, qubits)
engines = [q.engine for reg in qubits for q in reg]
eng = engines[0]
assert all(e is eng for e in engines)
return Command(eng, self, qubits)

def __or__(self, qubits):
""" Operator| overload which enables the syntax Gate | qubits.
Expand Down
56 changes: 32 additions & 24 deletions projectq/ops/_command.py
Expand Up @@ -81,7 +81,7 @@ class Command(object):
all_qubits: A tuple of control_qubits + qubits
"""

def __init__(self, engine, gate, qubits):
def __init__(self, engine, gate, qubits, controls=(), tags=()):
"""
Initialize a Command object.
Expand All @@ -93,18 +93,25 @@ def __init__(self, engine, gate, qubits):
(see WeakQubitRef).
Args:
engine: engine which created the qubit (mostly the MainEngine)
gate: Gate to be executed
qubits: Tuple of quantum registers (to which the gate is applied)
engine (projectq.cengines.BasicEngine):
engine which created the qubit (mostly the MainEngine)
gate (projectq.ops.Gate):
Gate to be executed
qubits (tuple[Qureg]):
Tuple of quantum registers (to which the gate is applied)
controls (Qureg|list[Qubit]):
Qubits that condition the command.
tags (list[object]):
Tags associated with the command.
"""
qubits = tuple([[WeakQubitRef(qubit.engine, qubit.id)
for qubit in qreg]
for qreg in qubits])
qubits = tuple([WeakQubitRef(qubit.engine, qubit.id)
for qubit in qreg]
for qreg in qubits)

self.gate = gate
self.tags = []
self.tags = list(tags)
self.qubits = qubits # property
self._control_qubits = [] # access via self.control_qubits property
self.control_qubits = controls # property
self.engine = engine # property

@property
Expand All @@ -117,10 +124,11 @@ def qubits(self, qubits):

def __deepcopy__(self, memo):
""" Deepcopy implementation. Engine should stay a reference."""
cpy = Command(self.engine, deepcopy(self.gate), self.qubits)
cpy.tags = deepcopy(self.tags)
cpy.add_control_qubits(self.control_qubits)
return cpy
return Command(self.engine,
deepcopy(self.gate),
self.qubits,
list(self.control_qubits),
deepcopy(self.tags))

def get_inverse(self):
"""
Expand All @@ -133,11 +141,11 @@ def get_inverse(self):
NotInvertible: If the gate does not provide an inverse (see
BasicGate.get_inverse)
"""
cmd = Command(self._engine, projectq.ops.get_inverse(self.gate),
self.qubits)
cmd.tags = deepcopy(self.tags)
cmd.add_control_qubits(self.control_qubits)
return cmd
return Command(self._engine,
projectq.ops.get_inverse(self.gate),
self.qubits,
list(self.control_qubits),
deepcopy(self.tags))

def get_merged(self, other):
"""
Expand All @@ -152,12 +160,12 @@ def get_merged(self, other):
or can't be merged for other reasons.
"""
if (self.tags == other.tags and self.all_qubits == other.all_qubits and
self.engine == other.engine):
merged_command = Command(self.engine, self.gate, self.qubits)
merged_command.gate = merged_command.gate.get_merged(other.gate)
merged_command.add_control_qubits(self.control_qubits)
merged_command.tags = deepcopy(self.tags)
return merged_command
self.engine == other.engine):
return Command(self.engine,
self.gate.get_merged(other.gate),
self.qubits,
self.control_qubits,
deepcopy(self.tags))
raise projectq.ops.NotMergeable("Commands not mergeable.")

def _order_qubits(self, qubits):
Expand Down
6 changes: 4 additions & 2 deletions projectq/ops/_gates.py
Expand Up @@ -36,7 +36,8 @@
SelfInverseGate,
BasicRotationGate,
ClassicalInstructionGate,
FastForwardingGate)
FastForwardingGate,
BasicMathGate)


class HGate(SelfInverseGate):
Expand Down Expand Up @@ -113,9 +114,10 @@ def __str__(self):
Tdag = Tdagger = get_inverse(T)


class SwapGate(SelfInverseGate):
class SwapGate(SelfInverseGate, BasicMathGate):
""" Swap gate class (swaps 2 qubits) """
def __init__(self):
BasicMathGate.__init__(self, lambda x, y: (y, x))
SelfInverseGate.__init__(self)
self.interchangeable_qubit_indices = [[0, 1]]

Expand Down
21 changes: 11 additions & 10 deletions projectq/ops/_metagates.py
Expand Up @@ -187,22 +187,23 @@ def __or__(self, qubits):
the gate.
"""
qubits = BasicGate.make_tuple_of_qureg(qubits)
n = self._n

ctrl = []
gate_quregs = []
added_ctrl_qubits = 0
for qureg in qubits:
if added_ctrl_qubits < n:
ctrl = ctrl + qureg
added_ctrl_qubits += len(qureg)
adding_to_controls = True
for reg in qubits:
if adding_to_controls:
ctrl += reg
adding_to_controls = len(ctrl) < self._n
else:
gate_quregs.append(qureg)
# Test that there were enough control qubits and that that
gate_quregs.append(reg)
# Test that there were enough control quregs and that that
# the last control qubit was the last qubit in a qureg.
if added_ctrl_qubits != n:
if len(ctrl) != self._n:
raise ControlQubitError("Wrong number of control qubits. "
"First qureg(s) need to contain exactly "
"the required number of control qubits.")
"the required number of control quregs.")

import projectq.meta
with projectq.meta.Control(gate_quregs[0][0].engine, ctrl):
self._gate | tuple(gate_quregs)
Expand Down
13 changes: 11 additions & 2 deletions projectq/ops/_metagates_test.py
Expand Up @@ -123,6 +123,15 @@ def test_controlled_gate_get_inverse():
assert one_control.get_inverse() == expected


def test_controlled_gate_empty_controls():
rec = DummyEngine(save_commands=True)
eng = MainEngine(backend=rec, engine_list=[])

a = eng.allocate_qureg(1)
_metagates.ControlledGate(Y, 0) | ((), a)
assert rec.received_commands[-1] == Command(eng, Y, [a])


def test_controlled_gate_or():
saving_backend = DummyEngine(save_commands=True)
main_engine = MainEngine(backend=saving_backend,
Expand All @@ -132,8 +141,8 @@ def test_controlled_gate_or():
qubit1 = Qubit(main_engine, 1)
qubit2 = Qubit(main_engine, 2)
qubit3 = Qubit(main_engine, 3)
expected_cmd = Command(main_engine, gate, ([qubit3],))
expected_cmd.add_control_qubits([qubit0, qubit1, qubit2])
expected_cmd = Command(main_engine, gate, ([qubit3],),
controls=[qubit0, qubit1, qubit2])
received_commands = []
# Option 1:
_metagates.ControlledGate(gate, 3) | ([qubit1], [qubit0],
Expand Down

0 comments on commit 0aa7b4b

Please sign in to comment.