1515from functools import cached_property
1616from typing import Dict , Iterator , List , Optional , Sequence , Tuple , TYPE_CHECKING , Union
1717
18- import attrs
1918import cirq
2019import numpy as np
2120import sympy
3231 CtrlSpec ,
3332 DecomposeTypeError ,
3433 GateWithRegisters ,
35- QAny ,
3634 QInt ,
3735 QMontgomeryUInt ,
3836 QUInt ,
4341 SoquetT ,
4442)
4543from qualtran .bloqs .basic_gates import CNOT
44+ from qualtran .bloqs .bookkeeping import Always
4645from qualtran .bloqs .mcmt .and_bloq import And
4746from qualtran .bloqs .mcmt .specialized_ctrl import get_ctrl_system_1bit_cv
4847from qualtran .cirq_interop import decompose_from_cirq_style_method
@@ -404,7 +403,6 @@ class AddK(Bloq):
404403 Args:
405404 dtype: data type of the input register `x`
406405 k: The classical integer value to be added to x.
407- is_controlled: if True, construct a singly-controlled bloq.
408406
409407 Registers:
410408 x: register of type `self.dtype`
@@ -416,7 +414,6 @@ class AddK(Bloq):
416414
417415 dtype : Union [QInt , QUInt , QMontgomeryUInt ]
418416 k : 'SymbolicInt'
419- is_controlled : bool = False
420417
421418 def __attrs_post_init__ (self ):
422419 if not isinstance (self .dtype , (QInt , QUInt , QMontgomeryUInt )):
@@ -426,19 +423,18 @@ def __attrs_post_init__(self):
426423
427424 @cached_property
428425 def signature (self ) -> 'Signature' :
429- return Signature .build_from_dtypes (ctrl = QAny ( 1 if self . is_controlled else 0 ), x = self .dtype )
426+ return Signature .build_from_dtypes (x = self .dtype )
430427
431428 def on_classical_vals (
432429 self , x : 'ClassicalValT' , ** vals : 'ClassicalValT'
433430 ) -> Dict [str , 'ClassicalValT' ]:
434431 if is_symbolic (self .k ) or is_symbolic (self .dtype ):
435432 raise ValueError (f"Classical simulation isn't supported for symbolic block { self } " )
436433
437- if not self .is_controlled or vals ['ctrl' ]:
438- is_signed = isinstance (self .dtype , QInt )
439- x = add_ints (int (x ), int (self .k ), num_bits = self .dtype .num_qubits , is_signed = is_signed )
434+ is_signed = isinstance (self .dtype , QInt )
435+ x = add_ints (int (x ), int (self .k ), num_bits = self .dtype .num_qubits , is_signed = is_signed )
440436
441- return vals | {'x' : x }
437+ return {'x' : x }
442438
443439 @cached_property
444440 def _load_k_bloq (self ) -> Bloq :
@@ -449,55 +445,36 @@ def _load_k_bloq(self) -> Bloq:
449445 # Since this is unsigned addition, adding `-v` is equivalent to adding `2**bitsize - v`
450446 k %= 2 ** self .dtype .bitsize
451447
452- xork = XorK (self .dtype , k )
453- return xork .controlled () if self .is_controlled else xork
448+ return XorK (self .dtype , k )
454449
455- def build_composite_bloq (
456- self , bb : 'BloqBuilder' , x : Soquet , ** soqs : Soquet
457- ) -> Dict [str , 'SoquetT' ]:
450+ def build_composite_bloq (self , bb : 'BloqBuilder' , x : Soquet ) -> Dict [str , 'SoquetT' ]:
458451 if is_symbolic (self .k ) or is_symbolic (self .dtype ):
459452 raise DecomposeTypeError (f"Cannot decompose symbolic { self } ." )
460453
461- # load `k` (conditional on ctrl if present)
454+ # load `k`
462455 k = bb .allocate (dtype = self .dtype )
463- load_soqs = {'x' : k }
464- if self .is_controlled :
465- load_soqs |= {'ctrl' : soqs .pop ('ctrl' )}
466- load_soqs = bb .add_d (self ._load_k_bloq , ** load_soqs )
467- k = load_soqs .pop ('x' )
456+ k = bb .add (self ._load_k_bloq , x = k )
468457
469- # quantum-quantum addition
470- k , x = bb .add (Add (self .dtype , self .dtype ), a = k , b = x )
458+ # perform the quantum-quantum addition
459+ # we always perform this addition (even when controlled), so we wrap in `Always`
460+ # controlling the data loading is sufficient to control this bloq.
461+ k , x = bb .add (Always (Add (self .dtype , self .dtype )), a = k , b = x )
471462
472463 # unload `k`
473- load_soqs ['x' ] = k
474- load_soqs = bb .add_d (self ._load_k_bloq .adjoint (), ** load_soqs )
475- k = load_soqs .pop ('x' )
476- assert isinstance (k , Soquet )
464+ k = bb .add (self ._load_k_bloq .adjoint (), x = k )
477465 bb .free (k )
478466
479- return {'x' : x } | load_soqs
467+ return {'x' : x }
480468
481469 def build_call_graph (self , ssa : 'SympySymbolAllocator' ) -> 'BloqCountDictT' :
482470 counts = Counter [Bloq ]()
483471
484472 counts [self ._load_k_bloq ] += 1
485- counts [Add (self .dtype , self .dtype )] += 1
473+ counts [Always ( Add (self .dtype , self .dtype ) )] += 1
486474 counts [self ._load_k_bloq .adjoint ()] += 1
487475
488476 return counts
489477
490- def get_ctrl_system (self , ctrl_spec : 'CtrlSpec' ) -> Tuple ['Bloq' , 'AddControlledT' ]:
491- from qualtran .bloqs .mcmt .specialized_ctrl import get_ctrl_system_1bit_cv_from_bloqs
492-
493- return get_ctrl_system_1bit_cv_from_bloqs (
494- self ,
495- ctrl_spec ,
496- current_ctrl_bit = 1 if self .is_controlled else None ,
497- bloq_with_ctrl = attrs .evolve (self , is_controlled = True ),
498- ctrl_reg_name = 'ctrl' ,
499- )
500-
501478
502479@bloq_example (generalizer = ignore_split_join )
503480def _add_k () -> AddK :
0 commit comments