From 27f820cac337c81dbc037b5e3e0381b7e31db5b3 Mon Sep 17 00:00:00 2001 From: Daisy Smith Date: Fri, 20 Dec 2019 12:26:05 +0000 Subject: [PATCH] Work in progress, is commutable --- projectq/cengines/_optimize.py | 20 +++++++++++++++++++- projectq/cengines/_optimize_test.py | 23 ++++++++++++++++++++++- projectq/ops/_basics.py | 3 ++- projectq/ops/_command.py | 16 ++++++++++++++++ projectq/ops/_metagates.py | 2 +- 5 files changed, 60 insertions(+), 4 deletions(-) diff --git a/projectq/cengines/_optimize.py b/projectq/cengines/_optimize.py index 24ab986e7..ad18b935b 100755 --- a/projectq/cengines/_optimize.py +++ b/projectq/cengines/_optimize.py @@ -125,7 +125,10 @@ def _optimize(self, idx, lim=None): i = 0 new_gateloc = 0 limit = len(self._l[idx]) - if lim is not None: + if lim is not None: # the argument for the limit of number + # of operations is not None, then set the + # limit to this number, otherwise the limit + # is the number of commands on this qubit limit = lim new_gateloc = limit @@ -136,6 +139,7 @@ def _optimize(self, idx, lim=None): # determine index of this gate on all qubits qubitids = [qb.id for sublist in self._l[idx][i].all_qubits for qb in sublist] + print([str(qubitid) for qubitid in qubitids]) gid = self._get_gate_indices(idx, i, qubitids) for j in range(len(qubitids)): new_list = (self._l[qubitids[j]][0:gid[j]] + @@ -147,6 +151,7 @@ def _optimize(self, idx, lim=None): except: pass + # can be dropped if two in a row are self-inverses inv = self._l[idx][i].get_inverse() @@ -171,8 +176,20 @@ def _optimize(self, idx, lim=None): limit -= 2 continue + # Gates are not mergeable, see if they are commutable + #try: + command1 = self._l[idx][i] + command2 = self._l[idx][i + 1] + print("Command1") + print(command1) + print("Command2") + print(command2) + commutable = command1.is_commutable(command2) # gates are not each other's inverses --> check if they're # mergeable + # except: + # pass # gates not commutable. + try: merged_command = self._l[idx][i].get_merged( self._l[idx][i + 1]) @@ -200,6 +217,7 @@ def _optimize(self, idx, lim=None): pass # can't merge these two commands. i += 1 # next iteration: look at next gate + return limit def _check_and_send(self): diff --git a/projectq/cengines/_optimize_test.py b/projectq/cengines/_optimize_test.py index ce8f937e5..ded37810a 100755 --- a/projectq/cengines/_optimize_test.py +++ b/projectq/cengines/_optimize_test.py @@ -15,10 +15,11 @@ """Tests for projectq.cengines._optimize.py.""" import pytest +import math from projectq import MainEngine from projectq.cengines import DummyEngine -from projectq.ops import (CNOT, H, Rx, Ry, AllocateQubitGate, X, +from projectq.ops import (CNOT, H, Rx, Ry, Rxx, AllocateQubitGate, X, FastForwardingGate, ClassicalInstructionGate) from projectq.cengines import _optimize @@ -145,3 +146,23 @@ def test_local_optimizer_identity_gates(): # Expect allocate, one Rx gate, and flush gate assert len(backend.received_commands) == 3 assert backend.received_commands[1].gate == Rx(0.5) + +def test_local_optimizer_commutable_gates(): + #local_optimizer = _optimize.LocalOptimizer(m=4) + backend = DummyEngine(save_commands=True) + eng = MainEngine(backend=backend) + # # Test that it commutes commutable gates such as Rx, Rxx + qb0 = eng.allocate_qubit() + qb1 = eng.allocate_qubit() + Rx(math.pi/2) | qb0 + Rxx(math.pi/2) | (qb0, qb1) + Rx(math.pi/2) | qb0 + eng.flush() + command1 = backend.received_commands[0] + command2 = backend.received_commands[1] + commutable = command1.is_commutable(command2) + print("commutable") + print(commutable) + #print("Commands") + #print([str(cmd) for cmd in backend.received_commands]) + return 0 \ No newline at end of file diff --git a/projectq/ops/_basics.py b/projectq/ops/_basics.py index eec6c562c..45aba5fa3 100755 --- a/projectq/ops/_basics.py +++ b/projectq/ops/_basics.py @@ -232,6 +232,8 @@ def __hash__(self): def is_identity(self): return False + def is_commutable(self, other): + return False class MatrixGate(BasicGate): """ @@ -409,7 +411,6 @@ def __hash__(self): def is_identity(self): return self.angle == 0. or self.angle==2*math.pi - class BasicPhaseGate(BasicGate): """ Defines a base class of a phase gate. diff --git a/projectq/ops/_command.py b/projectq/ops/_command.py index 87deab827..57110c019 100755 --- a/projectq/ops/_command.py +++ b/projectq/ops/_command.py @@ -156,6 +156,22 @@ def is_identity(self): Returns: True if the gate is equivalent to an Identity gate, False otherwise """ return projectq.ops.is_identity(self.gate) + + def is_commutable(self, other): + """ + Evaluate if the gate called in the command object is commutable with the next + gate. + + Returns: True if the gates are commutable, False otherwise + """ + if (self.qubits != other.qubits): + return False + print("self.gate") + print(self.gate) + print("other.gate") + print(other.gate) + return 0 #self.gate.is_commutable(self.gate, other.gate) + def get_merged(self, other): """ diff --git a/projectq/ops/_metagates.py b/projectq/ops/_metagates.py index 72d262de4..8d03330dc 100755 --- a/projectq/ops/_metagates.py +++ b/projectq/ops/_metagates.py @@ -149,7 +149,7 @@ def is_identity(gate): """ try: return gate.is_identity() - except : + except: return False class ControlledGate(BasicGate):