1- # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
1+ # Copyright 2020 ProjectQ-Framework (www.projectq.ch)
22#
33# Licensed under the Apache License, Version 2.0 (the "License");
44# you may not use this file except in compliance with the License.
@@ -62,6 +62,22 @@ class NotInvertible(Exception):
6262 pass
6363
6464
65+ def _round_angle (angle , mod_pi ):
66+ rounded_angle = round (float (angle ) % (mod_pi * math .pi ), ANGLE_PRECISION )
67+ if rounded_angle > mod_pi * math .pi - ANGLE_TOLERANCE :
68+ rounded_angle = 0.
69+ return rounded_angle
70+
71+
72+ def _angle_to_str (angle , symbols ):
73+ if symbols :
74+ return ('{}{}' .format (round (angle / math .pi , 3 ),
75+ unicodedata .lookup ("GREEK SMALL LETTER PI" )))
76+ else :
77+ return "{}" .format (angle )
78+
79+
80+
6581class BasicGate (object ):
6682 """
6783 Base class of all gates. (Don't use it directly but derive from it)
@@ -340,10 +356,7 @@ def __init__(self, angle):
340356 angle (float): Angle of rotation (saved modulo 4 * pi)
341357 """
342358 BasicGate .__init__ (self )
343- rounded_angle = round (float (angle ) % (4. * math .pi ), ANGLE_PRECISION )
344- if rounded_angle > 4 * math .pi - ANGLE_TOLERANCE :
345- rounded_angle = 0.
346- self .angle = rounded_angle
359+ self .angle = _round_angle (angle , 4 )
347360
348361 def __str__ (self ):
349362 """
@@ -366,12 +379,8 @@ def to_string(self, symbols=False):
366379 more user friendly display if True, full angle
367380 written in radian otherwise.
368381 """
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
382+ return (str (self .__class__ .__name__ ) + '(' + _angle_to_str (
383+ self .angle , symbols ) + ')' )
375384
376385 def tex_str (self ):
377386 """
@@ -437,6 +446,127 @@ def is_identity(self):
437446 return self .angle == 0. or self .angle == 4 * math .pi
438447
439448
449+ class U3Gate (BasicGate ):
450+ """
451+ Defines a base class for a general unitary single-qubit gate.
452+
453+ All three angles are continuous parameters. The inverse is the same gate
454+ with the negated argument. Rotation gates of the same class can be merged
455+ by adding the angles. The continuous parameter are modulo 4 * pi.
456+ """
457+ def __init__ (self , theta , phi , lamda ):
458+ """
459+ Initialize a general unitary single-qubit gate.
460+
461+ Args:
462+ theta (float): Angle of rotation (saved modulo 4 * pi)
463+ phi (float): Angle of rotation (saved modulo 4 * pi)
464+ lamda (float): Angle of rotation (saved modulo 4 * pi)
465+ """
466+ BasicGate .__init__ (self )
467+ self .theta = _round_angle (theta , 4 )
468+ self .phi = _round_angle (phi , 4 )
469+ self .lamda = _round_angle (lamda , 4 )
470+
471+ def __str__ (self ):
472+ """
473+ Return the string representation of a U3Gate.
474+
475+ Returns the class name and the angle as
476+
477+ .. code-block:: python
478+
479+ [CLASSNAME]([ANGLE])
480+ """
481+ return self .to_string ()
482+
483+ def to_string (self , symbols = False ):
484+ """
485+ Return the string representation of a U3Gate.
486+
487+ Args:
488+ symbols (bool): uses the pi character and round the angle for a
489+ more user friendly display if True, full angle
490+ written in radian otherwise.
491+ """
492+ return (str (self .__class__ .__name__ ) + '({},{},{})' .format (
493+ _angle_to_str (self .theta , symbols ),
494+ _angle_to_str (self .phi , symbols ),
495+ _angle_to_str (self .lamda , symbols )))
496+
497+ def tex_str (self ):
498+ """
499+ Return the Latex string representation of a BasicRotationGate.
500+
501+ Returns the class name and the angle as a subscript, i.e.
502+
503+ .. code-block:: latex
504+
505+ [CLASSNAME]$_[ANGLE]$
506+ """
507+ return str (self .__class__ .__name__ ) + "$({}\\ pi,{}\\ pi,{}\\ pi)$" .format (
508+ round (self .theta / math .pi , 3 ),
509+ round (self .phi / math .pi , 3 ),
510+ round (self .lamda / math .pi , 3 ))
511+
512+ def get_inverse (self ):
513+ """
514+ Return the inverse of this rotation gate (negate the angle, return new
515+ object).
516+ """
517+ if (self .theta , self .phi , self .lamda ) == (0 , 0 , 0 ):
518+ return self .__class__ (0 , 0 , 0 )
519+ else :
520+ return self .__class__ (- self .theta + 4 * math .pi ,
521+ - self .phi + 4 * math .pi ,
522+ - self .lamda + 4 * math .pi )
523+
524+ def get_merged (self , other ):
525+ """
526+ Return self merged with another gate.
527+
528+ Default implementation handles rotation gate of the same type, where
529+ angles are simply added.
530+
531+ Args:
532+ other: Rotation gate of same type.
533+
534+ Raises:
535+ NotMergeable: For non-rotation gates or rotation gates of
536+ different type.
537+
538+ Returns:
539+ New object representing the merged gates.
540+ """
541+ if isinstance (other , self .__class__ ):
542+ return self .__class__ (self .theta + other .theta ,
543+ self .phi + other .phi ,
544+ self .lamda + other .lamda )
545+ raise NotMergeable ("Can't merge different types of rotation gates." )
546+
547+ def __eq__ (self , other ):
548+ """ Return True if same class and same rotation angle. """
549+ if isinstance (other , self .__class__ ):
550+ return ((self .theta , self .phi , self .lamda )
551+ == (other .theta , other .phi , other .lamda ))
552+ else :
553+ return False
554+
555+ def __ne__ (self , other ):
556+ return not self .__eq__ (other )
557+
558+ def __hash__ (self ):
559+ return hash (str (self ))
560+
561+ def is_identity (self ):
562+ """
563+ Return True if the gate is equivalent to an Identity gate
564+ """
565+ return ((self .theta == 0. or self .theta == 4 * math .pi )
566+ and (self .phi == 0. or self .phi == 4 * math .pi )
567+ and (self .lamda == 0. or self .lamda == 4 * math .pi ))
568+
569+
440570class BasicPhaseGate (BasicGate ):
441571 """
442572 Defines a base class of a phase gate.
@@ -455,10 +585,7 @@ def __init__(self, angle):
455585 angle (float): Angle of rotation (saved modulo 2 * pi)
456586 """
457587 BasicGate .__init__ (self )
458- rounded_angle = round (float (angle ) % (2. * math .pi ), ANGLE_PRECISION )
459- if rounded_angle > 2 * math .pi - ANGLE_TOLERANCE :
460- rounded_angle = 0.
461- self .angle = rounded_angle
588+ self .angle = _round_angle (angle , 2 )
462589
463590 def __str__ (self ):
464591 """
0 commit comments