Skip to content

Commit 93f2d79

Browse files
dbretaudTakishima
andcommitted
Trapped ion decomposer setup and rotation gates improvement (#346)
* reduced Ry decomposition : modification of restrictedgateset setup to include compiler chooser, extension of available decompositions, new setup based on restrictedgateset but adapted for trapped ion configurations * Addition of test file for the rz2rx decomposition Addition of test file for the rz2rx decomposition and edit to comments in the rz2rx file * Revert "Addition of test file for the rz2rx decomposition" This reverts commit 5aab56b. * Create rz2rx_test file Addition of test file for the rz2rx decomposition * Update rz2rx.py Update to comments * Update rz2rx_test.py Update to comments * Minor update: remove accidental file * Minor update rz2rx.py Corrected an angle. * Minor update rz2rx_test.py Edited comments. * Create h2rx_test.py Updated method for test_decomposition which tests that decomposition produces identical wave-state up to a global phase. * Improvement of the decomposition chooser; Note that basic restricted gate set will fail decomposing into Rxx because of the default chooser * Updates to h2rx and cnot2rxx * Create cnot2rxx_test.py Testing file for cnot2rxx decomposition. Includes updated method for test_decomposition which tests that decomposition produces identical wave-state up to a global phase. * basic rotation gates at an angle of 0 or 2pi are removed by the optimizer. basic rotation gates ignore now the global phase and are defined over 0:2pi * Update and create trapped_ion_decomposer_test.py * Minor update Documentation and comments. * Update on comments regarding Identity gates * Changes 1/2 : command can be printed with unicode symbols only via new to_String method; syntax correction; * Work in progress, is commutable * Update to decomposition test files rz2rx_test now tests each decomposition defined in rz2rx.all_defined_decomposition_rules Similar for cnot2rxx_test and h2rx_test * Revert "Work in progress, is commutable" This reverts commit 27f820c. * minor fixes; revert rotation gates to [0;4pi) * fix comments * Fix a few issues with the trapped-ion setup - Store the sign of the last Ry gate on an engine-by-engine basis - Cleanup of some remaining print statements - Some stylistic issues fixed * Mostly fixing stylistic issues and some code cleanup * h2rx decomposition with correct global phase * cnot2rxx decomposition with correct global phase * Fix non-ASCII character in cnot2rxx.py * Fix some more files for non-ASCII characters * Specify encoding for files with non-ASCII characters * Fix test errors * Fix tests for Python 2.7 * Complete code coverage for trapped-ion setup Co-authored-by: Nguyen Damien <[email protected]>
1 parent 4bd6e6f commit 93f2d79

23 files changed

+1157
-125
lines changed

docs/projectq.setups.decompositions.rst

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@ The decomposition package is a collection of gate decomposition / replacement ru
1010
projectq.setups.decompositions.barrier
1111
projectq.setups.decompositions.carb1qubit2cnotrzandry
1212
projectq.setups.decompositions.cnot2cz
13+
projectq.setups.decompositions.cnot2rxx
1314
projectq.setups.decompositions.cnu2toffoliandcu
1415
projectq.setups.decompositions.crz2cxandrz
1516
projectq.setups.decompositions.entangle
1617
projectq.setups.decompositions.globalphase
18+
projectq.setups.decompositions.h2rx
1719
projectq.setups.decompositions.ph2r
1820
projectq.setups.decompositions.qft2crandhadamard
1921
projectq.setups.decompositions.qubitop2onequbit
2022
projectq.setups.decompositions.r2rzandph
2123
projectq.setups.decompositions.rx2rz
2224
projectq.setups.decompositions.ry2rz
25+
projectq.setups.decompositions.rz2rx
2326
projectq.setups.decompositions.sqrtswap2cnot
2427
projectq.setups.decompositions.stateprep2cnot
2528
projectq.setups.decompositions.swap2cnot
@@ -62,6 +65,13 @@ projectq.setups.decompositions.cnot2cz module
6265
:members:
6366
:undoc-members:
6467

68+
projectq.setups.decompositions.cnot2rxx module
69+
---------------------------------------------
70+
71+
.. automodule:: projectq.setups.decompositions.cnot2rxx
72+
:members:
73+
:undoc-members:
74+
6575
projectq.setups.decompositions.cnu2toffoliandcu module
6676
------------------------------------------------------
6777

@@ -90,7 +100,8 @@ projectq.setups.decompositions.globalphase module
90100
:members:
91101
:undoc-members:
92102

93-
projectq.setups.decompositions.ph2r module
103+
104+
projectq.setups.decompositions.h2rx module
94105
------------------------------------------
95106

96107
.. automodule:: projectq.setups.decompositions.ph2r
@@ -132,6 +143,13 @@ projectq.setups.decompositions.ry2rz module
132143
:members:
133144
:undoc-members:
134145

146+
projectq.setups.decompositions.rz2rx module
147+
-------------------------------------------
148+
149+
.. automodule:: projectq.setups.decompositions.rz2rx
150+
:members:
151+
:undoc-members:
152+
135153
projectq.setups.decompositions.sqrtswap2cnot module
136154
---------------------------------------------------
137155

docs/projectq.setups.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ restrictedgateset
8686
:special-members: __init__
8787
:undoc-members:
8888

89+
trapped_ion_decomposer
90+
----------------------
91+
.. automodule:: projectq.setups.trapped_ion_decomposer
92+
:members:
93+
:special-members: __init__
94+
:undoc-members:
95+
8996
Module contents
9097
---------------
9198

projectq/cengines/_optimize.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def _get_gate_indices(self, idx, i, IDs):
116116

117117
def _optimize(self, idx, lim=None):
118118
"""
119-
Try to merge or even cancel successive gates using the get_merged and
119+
Try to remove identity gates using the is_identity function, then merge or even cancel successive gates using the get_merged and
120120
get_inverse functions of the gate (see, e.g., BasicRotationGate).
121121
122122
It does so for all qubit command lists.
@@ -130,6 +130,20 @@ def _optimize(self, idx, lim=None):
130130
new_gateloc = limit
131131

132132
while i < limit - 1:
133+
# can be dropped if the gate is equivalent to an identity gate
134+
if self._l[idx][i].is_identity():
135+
# determine index of this gate on all qubits
136+
qubitids = [qb.id for sublist in self._l[idx][i].all_qubits
137+
for qb in sublist]
138+
gid = self._get_gate_indices(idx, i, qubitids)
139+
for j in range(len(qubitids)):
140+
new_list = (self._l[qubitids[j]][0:gid[j]] +
141+
self._l[qubitids[j]][gid[j] +1:])
142+
self._l[qubitids[j]] = new_list
143+
i = 0
144+
limit -= 1
145+
continue
146+
133147
# can be dropped if two in a row are self-inverses
134148
inv = self._l[idx][i].get_inverse()
135149

projectq/cengines/_optimize_test.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import pytest
1818

19+
import math
1920
from projectq import MainEngine
2021
from projectq.cengines import DummyEngine
2122
from projectq.ops import (CNOT, H, Rx, Ry, AllocateQubitGate, X,
@@ -127,3 +128,22 @@ def test_local_optimizer_mergeable_gates():
127128
# Expect allocate, one Rx gate, and flush gate
128129
assert len(backend.received_commands) == 3
129130
assert backend.received_commands[1].gate == Rx(10 * 0.5)
131+
132+
133+
def test_local_optimizer_identity_gates():
134+
local_optimizer = _optimize.LocalOptimizer(m=4)
135+
backend = DummyEngine(save_commands=True)
136+
eng = MainEngine(backend=backend, engine_list=[local_optimizer])
137+
# Test that it merges mergeable gates such as Rx
138+
qb0 = eng.allocate_qubit()
139+
for _ in range(10):
140+
Rx(0.0) | qb0
141+
Ry(0.0) | qb0
142+
Rx(4*math.pi) | qb0
143+
Ry(4*math.pi) | qb0
144+
Rx(0.5) | qb0
145+
assert len(backend.received_commands) == 0
146+
eng.flush()
147+
# Expect allocate, one Rx gate, and flush gate
148+
assert len(backend.received_commands) == 3
149+
assert backend.received_commands[1].gate == Rx(0.5)

projectq/cengines/_replacer/_replacer.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ def _process_command(self, cmd):
175175

176176
# use decomposition chooser to determine the best decomposition
177177
chosen_decomp = self._decomp_chooser(cmd, decomp_list)
178-
179178
# the decomposed command must have the same tags
180179
# (plus the ones it gets from meta-statements inside the
181180
# decomposition rule).

projectq/ops/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from ._command import apply_command, Command
2626
from ._metagates import (DaggeredGate,
2727
get_inverse,
28+
is_identity,
2829
ControlledGate,
2930
C,
3031
Tensor,

projectq/ops/_basics.py

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
1514
"""
1615
Defines the BasicGate class, the base class of all gates, the
1716
BasicRotationGate class, the SelfInverseGate, the FastForwardingGate, the
@@ -39,9 +38,10 @@
3938
from projectq.types import BasicQubit
4039
from ._command import Command, apply_command
4140

41+
import unicodedata
4242

4343
ANGLE_PRECISION = 12
44-
ANGLE_TOLERANCE = 10 ** -ANGLE_PRECISION
44+
ANGLE_TOLERANCE = 10**-ANGLE_PRECISION
4545
RTOL = 1e-10
4646
ATOL = 1e-12
4747

@@ -157,7 +157,7 @@ def make_tuple_of_qureg(qubits):
157157
(or list of Qubits) objects.
158158
"""
159159
if not isinstance(qubits, tuple):
160-
qubits = (qubits,)
160+
qubits = (qubits, )
161161

162162
qubits = list(qubits)
163163

@@ -208,8 +208,9 @@ def __eq__(self, other):
208208
Equality comparision
209209
210210
Return True if instance of the same class, unless other is an instance
211-
of :class:MatrixGate, in which case equality is to be checked by testing
212-
for existence and (approximate) equality of matrix representations.
211+
of :class:MatrixGate, in which case equality is to be checked by
212+
testing for existence and (approximate) equality of matrix
213+
representations.
213214
"""
214215
if isinstance(other, self.__class__):
215216
return True
@@ -224,9 +225,21 @@ def __ne__(self, other):
224225
def __str__(self):
225226
raise NotImplementedError('This gate does not implement __str__.')
226227

228+
def to_string(self, symbols):
229+
"""
230+
String representation
231+
232+
Achieve same function as str() but can be extended for configurable
233+
representation
234+
"""
235+
return str(self)
236+
227237
def __hash__(self):
228238
return hash(str(self))
229239

240+
def is_identity(self):
241+
return False
242+
230243

231244
class MatrixGate(BasicGate):
232245
"""
@@ -271,20 +284,19 @@ def __eq__(self, other):
271284
"""
272285
if not hasattr(other, 'matrix'):
273286
return False
274-
if (not isinstance(self.matrix, np.matrix) or
275-
not isinstance(other.matrix, np.matrix)):
287+
if (not isinstance(self.matrix, np.matrix)
288+
or not isinstance(other.matrix, np.matrix)):
276289
raise TypeError("One of the gates doesn't have the correct "
277290
"type (numpy.matrix) for the matrix "
278291
"attribute.")
279-
if (self.matrix.shape == other.matrix.shape and
280-
np.allclose(self.matrix, other.matrix,
281-
rtol=RTOL, atol=ATOL,
282-
equal_nan=False)):
292+
if (self.matrix.shape == other.matrix.shape and np.allclose(
293+
self.matrix, other.matrix, rtol=RTOL, atol=ATOL,
294+
equal_nan=False)):
283295
return True
284296
return False
285297

286298
def __str__(self):
287-
return("MatrixGate(" + str(self.matrix.tolist()) + ")")
299+
return ("MatrixGate(" + str(self.matrix.tolist()) + ")")
288300

289301
def __hash__(self):
290302
return hash(str(self))
@@ -343,7 +355,23 @@ def __str__(self):
343355
344356
[CLASSNAME]([ANGLE])
345357
"""
346-
return str(self.__class__.__name__) + "(" + str(self.angle) + ")"
358+
return self.to_string()
359+
360+
def to_string(self, symbols=False):
361+
"""
362+
Return the string representation of a BasicRotationGate.
363+
364+
Args:
365+
symbols (bool): uses the pi character and round the angle for a
366+
more user friendly display if True, full angle
367+
written in radian otherwise.
368+
"""
369+
if symbols:
370+
angle = ("(" + str(round(self.angle / math.pi, 3))
371+
+ unicodedata.lookup("GREEK SMALL LETTER PI") + ")")
372+
else:
373+
angle = "(" + str(self.angle) + ")"
374+
return str(self.__class__.__name__) + angle
347375

348376
def tex_str(self):
349377
"""
@@ -355,7 +383,8 @@ def tex_str(self):
355383
356384
[CLASSNAME]$_[ANGLE]$
357385
"""
358-
return str(self.__class__.__name__) + "$_{" + str(self.angle) + "}$"
386+
return (str(self.__class__.__name__) + "$_{"
387+
+ str(round(self.angle / math.pi, 3)) + "\\pi}$")
359388

360389
def get_inverse(self):
361390
"""
@@ -401,6 +430,12 @@ def __ne__(self, other):
401430
def __hash__(self):
402431
return hash(str(self))
403432

433+
def is_identity(self):
434+
"""
435+
Return True if the gate is equivalent to an Identity gate
436+
"""
437+
return self.angle == 0. or self.angle == 4 * math.pi
438+
404439

405440
class BasicPhaseGate(BasicGate):
406441
"""
@@ -597,6 +632,7 @@ def math_fun(a):
597632

598633
def math_function(x):
599634
return list(math_fun(*x))
635+
600636
self._math_function = math_function
601637

602638
def __str__(self):

0 commit comments

Comments
 (0)