15
15
from functools import cached_property
16
16
from typing import Dict , Iterator , List , Optional , Sequence , Tuple , TYPE_CHECKING , Union
17
17
18
- import attrs
19
18
import cirq
20
19
import numpy as np
21
20
import sympy
32
31
CtrlSpec ,
33
32
DecomposeTypeError ,
34
33
GateWithRegisters ,
35
- QAny ,
36
34
QInt ,
37
35
QMontgomeryUInt ,
38
36
QUInt ,
43
41
SoquetT ,
44
42
)
45
43
from qualtran .bloqs .basic_gates import CNOT
44
+ from qualtran .bloqs .bookkeeping import Always
46
45
from qualtran .bloqs .mcmt .and_bloq import And
47
46
from qualtran .bloqs .mcmt .specialized_ctrl import get_ctrl_system_1bit_cv
48
47
from qualtran .cirq_interop import decompose_from_cirq_style_method
@@ -404,7 +403,6 @@ class AddK(Bloq):
404
403
Args:
405
404
dtype: data type of the input register `x`
406
405
k: The classical integer value to be added to x.
407
- is_controlled: if True, construct a singly-controlled bloq.
408
406
409
407
Registers:
410
408
x: register of type `self.dtype`
@@ -416,7 +414,6 @@ class AddK(Bloq):
416
414
417
415
dtype : Union [QInt , QUInt , QMontgomeryUInt ]
418
416
k : 'SymbolicInt'
419
- is_controlled : bool = False
420
417
421
418
def __attrs_post_init__ (self ):
422
419
if not isinstance (self .dtype , (QInt , QUInt , QMontgomeryUInt )):
@@ -426,19 +423,18 @@ def __attrs_post_init__(self):
426
423
427
424
@cached_property
428
425
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 )
430
427
431
428
def on_classical_vals (
432
429
self , x : 'ClassicalValT' , ** vals : 'ClassicalValT'
433
430
) -> Dict [str , 'ClassicalValT' ]:
434
431
if is_symbolic (self .k ) or is_symbolic (self .dtype ):
435
432
raise ValueError (f"Classical simulation isn't supported for symbolic block { self } " )
436
433
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 )
440
436
441
- return vals | {'x' : x }
437
+ return {'x' : x }
442
438
443
439
@cached_property
444
440
def _load_k_bloq (self ) -> Bloq :
@@ -449,55 +445,36 @@ def _load_k_bloq(self) -> Bloq:
449
445
# Since this is unsigned addition, adding `-v` is equivalent to adding `2**bitsize - v`
450
446
k %= 2 ** self .dtype .bitsize
451
447
452
- xork = XorK (self .dtype , k )
453
- return xork .controlled () if self .is_controlled else xork
448
+ return XorK (self .dtype , k )
454
449
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' ]:
458
451
if is_symbolic (self .k ) or is_symbolic (self .dtype ):
459
452
raise DecomposeTypeError (f"Cannot decompose symbolic { self } ." )
460
453
461
- # load `k` (conditional on ctrl if present)
454
+ # load `k`
462
455
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 )
468
457
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 )
471
462
472
463
# 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 )
477
465
bb .free (k )
478
466
479
- return {'x' : x } | load_soqs
467
+ return {'x' : x }
480
468
481
469
def build_call_graph (self , ssa : 'SympySymbolAllocator' ) -> 'BloqCountDictT' :
482
470
counts = Counter [Bloq ]()
483
471
484
472
counts [self ._load_k_bloq ] += 1
485
- counts [Add (self .dtype , self .dtype )] += 1
473
+ counts [Always ( Add (self .dtype , self .dtype ) )] += 1
486
474
counts [self ._load_k_bloq .adjoint ()] += 1
487
475
488
476
return counts
489
477
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
-
501
478
502
479
@bloq_example (generalizer = ignore_split_join )
503
480
def _add_k () -> AddK :
0 commit comments