Skip to content

Commit 16ae80e

Browse files
committed
Display changes for basic bloqs
1 parent 1c6e5e0 commit 16ae80e

12 files changed

Lines changed: 119 additions & 26 deletions

File tree

qualtran/bloqs/arithmetic/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
LinearDepthHalfLessThanEqual,
3030
SingleQubitCompare,
3131
)
32+
from qualtran.bloqs.arithmetic.controlled_add_or_subtract import ControlledAddOrSubtract
3233
from qualtran.bloqs.arithmetic.controlled_addition import CAdd
3334
from qualtran.bloqs.arithmetic.conversions import (
3435
SignedIntegerToTwosComplement,

qualtran/bloqs/arithmetic/addition.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,9 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT':
480480

481481
return counts
482482

483+
def __str__(self):
484+
return f'AddK(k={self.k})'
485+
483486

484487
@bloq_example(generalizer=ignore_split_join)
485488
def _add_k() -> AddK:

qualtran/bloqs/arithmetic/bitwise.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ def on_classical_vals(self, x: 'ClassicalValT') -> Dict[str, 'ClassicalValT']:
231231
x %= 2**self.dtype.bitsize
232232
return {'x': x}
233233

234+
def __str__(self):
235+
return f'BitwiseNot({self.dtype.num_bits})'
236+
234237

235238
@bloq_example
236239
def _bitwise_not() -> BitwiseNot:

qualtran/bloqs/basic_gates/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from .identity import Identity
2929
from .on_each import OnEach
3030
from .power import Power
31-
from .rotation import CRz, CZPowGate, Rx, Ry, Rz, XPowGate, YPowGate, ZPowGate
31+
from .rotation import CRy, CRz, CZPowGate, Rx, Ry, Rz, XPowGate, YPowGate, ZPowGate
3232
from .s_gate import SGate
3333
from .su2_rotation import SU2RotationGate
3434
from .swap import CSwap, Swap, TwoBitCSwap, TwoBitSwap

qualtran/bloqs/basic_gates/global_phase.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def _add_ctrled(
118118
return bloq, _add_ctrled
119119

120120
def __str__(self) -> str:
121-
return f'GPhase({self.coefficient})'
121+
return f'GPhase({self.exponent})'
122122

123123

124124
@bloq_example

qualtran/bloqs/basic_gates/on_each.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,4 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
9696
return super().wire_symbol(reg, idx)
9797

9898
def __str__(self):
99-
return f'{self.gate}{self.n}'
99+
return f'{self.gate}(oneach={self.n})'

qualtran/bloqs/basic_gates/power.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
from functools import cached_property
15-
from typing import Dict, TYPE_CHECKING
15+
from typing import Dict, Optional, Tuple, TYPE_CHECKING
1616

17+
import attrs
1718
import numpy as np
1819
from attrs import frozen
1920

20-
from qualtran import Bloq, BloqBuilder, GateWithRegisters, Side, Signature, SoquetT
21+
from qualtran import Bloq, BloqBuilder, GateWithRegisters, Register, Side, Signature, SoquetT
22+
from qualtran.drawing import LarrowTextBox, RarrowTextBox, Text, TextBox, WireSymbol
2123
from qualtran.symbolics import is_symbolic, SymbolicInt
2224

2325
if TYPE_CHECKING:
@@ -86,3 +88,21 @@ def _circuit_diagram_info_(
8688
wire_symbols = [f'{symbol}^{self.power}' for symbol in info.wire_symbols]
8789

8890
return cirq.CircuitDiagramInfo(wire_symbols=wire_symbols)
91+
92+
def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol':
93+
94+
if reg is None:
95+
sub_title = self.bloq.wire_symbol(None, idx)
96+
if not isinstance(sub_title, Text):
97+
raise ValueError(
98+
f"{self.bloq} should return a `Text` object for reg=None wire symbol."
99+
)
100+
if sub_title.text == '':
101+
return Text('')
102+
103+
return Text(f'{sub_title.text}**{self.power}')
104+
105+
ws = self.bloq.wire_symbol(reg, idx)
106+
if isinstance(ws, (Text, TextBox, RarrowTextBox, LarrowTextBox)):
107+
return attrs.evolve(ws, text=f'{ws.text}**{self.power}')
108+
return ws

qualtran/bloqs/basic_gates/rotation.py

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"""
4444

4545
from 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

4848
import attrs
4949
import 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
492508
class 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:
696720
def _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})'

qualtran/bloqs/basic_gates/rotation_test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,15 +257,15 @@ def test_pl_interop():
257257

258258

259259
def test_str():
260-
assert str(ZPowGate()) == "Z**1.0"
261-
assert str(XPowGate()) == "X**1.0"
262-
assert str(YPowGate()) == "Y**1.0"
260+
assert str(ZPowGate()) == "Z(pow=1.0)"
261+
assert str(XPowGate()) == "X(pow=1.0)"
262+
assert str(YPowGate()) == "Y(pow=1.0)"
263263
assert str(_ry()) == "Ry(0.7853981633974483)"
264264
assert str(_rx()) == "Rx(0.7853981633974483)"
265265
assert str(_rz()) == "Rz(a)"
266266

267-
assert str(CZPowGate(1.0)) == 'CZ**1.0'
268-
assert str(CZPowGate(0.9)) == 'CZ**0.9'
267+
assert str(CZPowGate(1.0)) == 'CZ(pow=1.0)'
268+
assert str(CZPowGate(0.9)) == 'CZ(pow=0.9)'
269269

270270

271271
def test_rx(bloq_autotester):

qualtran/bloqs/basic_gates/swap.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,9 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
393393
if reg is None:
394394
return Text('')
395395
if reg.name == 'x':
396-
return TextBox((x)')
396+
return TextBox('×')
397397
elif reg.name == 'y':
398-
return TextBox((y)')
398+
return TextBox('×')
399399
else:
400400
return Circle(filled=True)
401401

0 commit comments

Comments
 (0)