Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single-qubit and Controlled Z rotations #1455

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
5 changes: 4 additions & 1 deletion dev_tools/qualtran_dev_tools/notebook_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,9 +577,12 @@
title='Basic Rotation Gates',
module=qualtran.bloqs.basic_gates.rotation,
bloq_specs=[
qualtran.bloqs.basic_gates.rotation._Z_POW_DOC,
qualtran.bloqs.basic_gates.rotation._CZ_POW_DOC,
qualtran.bloqs.basic_gates.rotation._RZ_DOC,
qualtran.bloqs.basic_gates.rotation._CRZ_DOC,
qualtran.bloqs.basic_gates.rotation._X_POW_DOC,
qualtran.bloqs.basic_gates.rotation._Y_POW_DOC,
qualtran.bloqs.basic_gates.rotation._Z_POW_DOC,
],
),
NotebookSpecV2(
Expand Down
31 changes: 31 additions & 0 deletions qualtran/_infra/controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,3 +508,34 @@ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.Circ
)

return _wire_symbol_to_cirq_diagram_info(self, args)

@staticmethod
def get_single_reg_ctrl_system(
ctrl_bloq: 'Bloq', ctrl_reg_name: str
) -> Tuple['Bloq', 'AddControlledT']:
"""A static method for helping explicitly write your own `get_ctrl_system`.

Bloq authors can set up a controlled version of the bloq if the controlled bloq
takes one additional control register with a known name. You can use this function to
easily return the callable required by `get_ctrl_system`.

Args:
ctrl_bloq: The controlled version of the bloq
ctrl_reg_name: The name of the new register that takes a control soquet.

Returns:
ctrl_bloq: The control bloq, per the `Bloq.get_ctrl_system` interface.
add_controlled: A function that adds the controlled version of the bloq to
a composite bloq that is being built, per the `Bloq.get_ctrl_system` interface.
"""

def adder(
bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT']
) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]:
(ctrl_soq,) = ctrl_soqs
soqs = {ctrl_reg_name: ctrl_soq} | in_soqs
soqs = bb.add_d(ctrl_bloq, **soqs)
ctrl_soqs = [soqs.pop(ctrl_reg_name)]
return ctrl_soqs, soqs.values()

return ctrl_bloq, adder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be replaced with the new get_ctrl_system_1bit_cv

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep this is some vestigial code where I wanted to try my hand at factoring it out :) thanks for actually doing it

2 changes: 1 addition & 1 deletion qualtran/bloqs/basic_gates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from .identity import Identity
from .on_each import OnEach
from .power import Power
from .rotation import CZPowGate, Rx, Ry, Rz, XPowGate, YPowGate, ZPowGate
from .rotation import CRz, CZPowGate, Rx, Ry, Rz, XPowGate, YPowGate, ZPowGate
from .s_gate import SGate
from .su2_rotation import SU2RotationGate
from .swap import CSwap, Swap, TwoBitCSwap, TwoBitSwap
Expand Down
45 changes: 13 additions & 32 deletions qualtran/bloqs/basic_gates/global_phase.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,22 @@
"## `GlobalPhase`\n",
"Applies a global phase to the circuit as a whole.\n",
"\n",
"The unitary effect is to multiply the state vector by the complex scalar\n",
"$e^{i pi t}$ for `exponent` $t$.\n",
"For an exponent $t$, the unitary effect is to multiply the state vector by the complex scalar\n",
"$$\n",
"(-1)^t = e^{i \\pi t}\n",
"$$\n",
"\n",
"The global phase of a state or circuit does not affect any observable quantity, but\n",
"keeping track of it can be a useful bookkeeping mechanism for testing circuit identities.\n",
"The global phase becomes important if the gate becomes controlled.\n",
"keeping track of it can be a useful bookkeeping mechanism for testing circuit identities, and\n",
"the global phase becomes important when controlling an operation.\n",
"\n",
"This is fundamentally an atomic operation and this bloq has no decomposition in Qualtran.\n",
"\n",
"The single-qubit controlled version of `GlobalPhase` is `ZPowGate`.\n",
"\n",
"#### Parameters\n",
" - `exponent`: the exponent $t$ of the global phase $e^{i pi t}$ to apply.\n",
" - `eps`: precision\n"
" - `exponent`: the exponent t of the global phase (-1)^t to apply.\n",
" - `eps`: The precision of the rotation. This parameter is for bookkeeping and does not affect e.g. the tensor representation of this gate.\n"
]
},
{
Expand Down Expand Up @@ -108,31 +114,6 @@
" ['`global_phase`'])"
]
},
{
"cell_type": "markdown",
"id": "facc4a57",
"metadata": {
"cq.autogen": "GlobalPhase.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94dfefb2",
"metadata": {
"cq.autogen": "GlobalPhase.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"global_phase_g, global_phase_sigma = global_phase.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(global_phase_g)\n",
"show_counts_sigma(global_phase_sigma)"
]
},
{
"cell_type": "markdown",
"id": "c183275c-cc9c-477d-888c-d8b850f67a2e",
Expand All @@ -158,7 +139,7 @@
"id": "b737b871-9c61-4d54-860a-d9928f18808b",
"metadata": {},
"source": [
"When a global phase is controlled, it is equivalent to a ZPowGate"
"When a global phase is controlled, it is equivalent to a `ZPowGate`"
]
},
{
Expand Down
40 changes: 23 additions & 17 deletions qualtran/bloqs/basic_gates/global_phase.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import attrs
import cirq
from attrs import field, frozen
from attrs import frozen

from qualtran import (
AddControlledT,
Expand All @@ -30,7 +30,6 @@
DecomposeTypeError,
SoquetT,
)
from qualtran.bloqs.basic_gates.rotation import ZPowGate
from qualtran.cirq_interop import CirqGateAsBloqBase
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
from qualtran.symbolics import pi, sarg, sexp, SymbolicComplex, SymbolicFloat
Expand All @@ -39,23 +38,30 @@
import quimb.tensor as qtn


@frozen
@frozen(kw_only=True)
class GlobalPhase(CirqGateAsBloqBase):
r"""Applies a global phase to the circuit as a whole.

The unitary effect is to multiply the state vector by the complex scalar
$e^{i pi t}$ for `exponent` $t$.
For an exponent $t$, the unitary effect is to multiply the state vector by the complex scalar
$$
(-1)^t = e^{i \pi t}
$$

The global phase of a state or circuit does not affect any observable quantity, but
keeping track of it can be a useful bookkeeping mechanism for testing circuit identities.
The global phase becomes important if the gate becomes controlled.
keeping track of it can be a useful bookkeeping mechanism for testing circuit identities, and
the global phase becomes important when controlling an operation.

This is fundamentally an atomic operation and this bloq has no decomposition in Qualtran.

The single-qubit controlled version of `GlobalPhase` is `ZPowGate`.

Args:
exponent: the exponent $t$ of the global phase $e^{i pi t}$ to apply.
eps: precision
exponent: the exponent t of the global phase (-1)^t to apply.
eps: The precision of the rotation. This parameter is for bookkeeping and does
not affect e.g. the tensor representation of this gate.
"""

exponent: SymbolicFloat = field(kw_only=True)
exponent: SymbolicFloat
eps: SymbolicFloat = 1e-11

@cached_property
Expand Down Expand Up @@ -88,14 +94,12 @@ def my_tensors(

def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']:
# Delegate to superclass logic for more than one control.
if not (ctrl_spec == CtrlSpec() or ctrl_spec == CtrlSpec(cvs=0)):
if ctrl_spec != CtrlSpec():
return super().get_ctrl_system(ctrl_spec=ctrl_spec)

# Otherwise, it's a ZPowGate
if ctrl_spec == CtrlSpec(cvs=0):
bloq = ZPowGate(exponent=-self.exponent, global_shift=-1, eps=self.eps)
else:
bloq = ZPowGate(exponent=self.exponent, eps=self.eps)
from qualtran.bloqs.basic_gates import ZPowGate

bloq = ZPowGate(exponent=self.exponent, eps=self.eps)

def _add_ctrled(
bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT']
Expand All @@ -119,4 +123,6 @@ def _global_phase() -> GlobalPhase:
return global_phase


_GLOBAL_PHASE_DOC = BloqDocSpec(bloq_cls=GlobalPhase, examples=[_global_phase])
_GLOBAL_PHASE_DOC = BloqDocSpec(
bloq_cls=GlobalPhase, examples=[_global_phase], call_graph_example=None
)
Loading
Loading