4343"""
4444
4545from functools import cached_property
46- from typing import Dict , Iterable , Optional , Sequence , Tuple , TYPE_CHECKING , Union
46+ from typing import Callable , Dict , Iterable , Optional , Sequence , Tuple , Type , TYPE_CHECKING , Union
4747
4848import attrs
4949import cirq
@@ -163,7 +163,7 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
163163 return TextBox (f'Z^{ self .exponent } ' )
164164
165165 def __str__ (self ):
166- return f'Z** { self .exponent } '
166+ return f'Z(pow= { self .exponent } ) '
167167
168168
169169@bloq_example
@@ -231,7 +231,7 @@ def adjoint(self) -> 'CZPowGate':
231231 return attrs .evolve (self , exponent = - self .exponent )
232232
233233 def __str__ (self ):
234- return f'CZ** { self .exponent } '
234+ return f'CZ(pow= { self .exponent } ) '
235235
236236
237237@bloq_example
@@ -306,7 +306,7 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
306306 return TextBox (f'X^{ self .exponent } ' )
307307
308308 def __str__ (self ):
309- return f'X** { self .exponent } '
309+ return f'X(pow= { self .exponent } ) '
310310
311311
312312@bloq_example
@@ -381,7 +381,7 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
381381 return TextBox (f'Y^{ self .exponent } ' )
382382
383383 def __str__ (self ):
384- return f'Y** { self .exponent } '
384+ return f'Y(pow= { self .exponent } ) '
385385
386386
387387@bloq_example
@@ -487,6 +487,22 @@ def _rz() -> Rz:
487487
488488_RZ_DOC = BloqDocSpec (bloq_cls = Rz , examples = [_rz ], call_graph_example = None )
489489
490+ _PowClsT = Union [Type [XPowGate ], Type [YPowGate ], Type [ZPowGate ]]
491+
492+
493+ def _controlled_rp_circuit (
494+ bb : 'BloqBuilder' , / , * , single_q_pow_cls : _PowClsT , angle : float , eps : float , ctrl , q
495+ ) -> Dict [str , Soquet ]:
496+ from qualtran .bloqs .basic_gates import CNOT
497+
498+ t = angle / np .pi
499+ q = bb .add (single_q_pow_cls (t / 2 , eps = eps / 2 ), q = q )
500+ ctrl , q = bb .add (CNOT (), ctrl = ctrl , target = q )
501+ q = bb .add (single_q_pow_cls (- t / 2 , eps = eps / 2 ), q = q )
502+ ctrl , q = bb .add (CNOT (), ctrl = ctrl , target = q )
503+
504+ return {'ctrl' : ctrl , 'q' : q }
505+
490506
491507@frozen
492508class CRz (Bloq ):
@@ -532,15 +548,9 @@ def signature(self) -> 'Signature':
532548 def build_composite_bloq (
533549 self , bb : 'BloqBuilder' , ctrl : 'Soquet' , q : 'Soquet'
534550 ) -> Dict [str , 'SoquetT' ]:
535- from qualtran .bloqs .basic_gates import CNOT
536-
537- t = self .angle / np .pi
538- q = bb .add (ZPowGate (t / 2 , eps = self .eps / 2 ), q = q )
539- ctrl , q = bb .add (CNOT (), ctrl = ctrl , target = q )
540- q = bb .add (ZPowGate (- t / 2 , eps = self .eps / 2 ), q = q )
541- ctrl , q = bb .add (CNOT (), ctrl = ctrl , target = q )
542-
543- return {'ctrl' : ctrl , 'q' : q }
551+ return _controlled_rp_circuit (
552+ bb , single_q_pow_cls = ZPowGate , angle = self .angle , eps = self .eps , ctrl = ctrl , q = q
553+ )
544554
545555 def __str__ (self ):
546556 return f'CRz({ self .angle } )'
@@ -677,6 +687,20 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation':
677687 def adjoint (self ) -> 'Ry' :
678688 return attrs .evolve (self , angle = - self .angle )
679689
690+ def get_ctrl_system (self , ctrl_spec : 'CtrlSpec' ) -> Tuple ['Bloq' , 'AddControlledT' ]:
691+ if ctrl_spec != CtrlSpec ():
692+ return super ().get_ctrl_system (ctrl_spec )
693+
694+ from qualtran .bloqs .mcmt .specialized_ctrl import get_ctrl_system_1bit_cv_from_bloqs
695+
696+ return get_ctrl_system_1bit_cv_from_bloqs (
697+ bloq = self ,
698+ ctrl_spec = ctrl_spec ,
699+ current_ctrl_bit = None ,
700+ bloq_with_ctrl = CRy (self .angle , eps = self .eps ),
701+ ctrl_reg_name = 'ctrl' ,
702+ )
703+
680704 def wire_symbol (self , reg : Optional [Register ], idx : Tuple [int , ...] = tuple ()) -> 'WireSymbol' :
681705 if reg is None :
682706 return Text ('' )
@@ -696,3 +720,36 @@ def _rx() -> Rx:
696720def _ry () -> Ry :
697721 ry = Ry (angle = np .pi / 4.0 )
698722 return ry
723+
724+
725+ @frozen
726+ class CRy (Bloq ):
727+ r"""A controlled Ry rotation.
728+
729+ Args:
730+ angle: The rotation angle in radians.
731+ eps: The precision of the rotation. This parameter is for bookkeeping and does
732+ not affect e.g. the tensor representation of this gate. When synthesizing
733+ a rotation from a discrete gate set, you must fix a precision `eps`.
734+
735+ Registers:
736+ ctrl: Whether the rotation is active.
737+ q: The qubit on which we optionally perform the rotation.
738+ """
739+
740+ angle : SymbolicFloat
741+ eps : SymbolicFloat = 1e-11
742+
743+ @cached_property
744+ def signature (self ) -> 'Signature' :
745+ return Signature .build (ctrl = 1 , q = 1 )
746+
747+ def build_composite_bloq (
748+ self , bb : 'BloqBuilder' , ctrl : 'Soquet' , q : 'Soquet'
749+ ) -> Dict [str , 'SoquetT' ]:
750+ return _controlled_rp_circuit (
751+ bb , single_q_pow_cls = YPowGate , angle = self .angle , eps = self .eps , ctrl = ctrl , q = q
752+ )
753+
754+ def __str__ (self ):
755+ return f'CRy({ self .angle } )'
0 commit comments