-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
207 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"id": "0", | ||
"metadata": {}, | ||
"source": [ | ||
"## Bloqs with specialized controlled implementations\n", | ||
"\n", | ||
"In some cases, a bloq may have a specialized singly-controlled version (e.g. `LCUBlockEncoding`).\n", | ||
"Qualtran provides a convenience methods `get_ctrl_system_1bit_cv` and `get_ctrl_system_1bit_cv_from_bloqs` to override the `get_ctrl_system`. These methods ensure that multiply-controlled bloqs are correctly reduced to the provided singly-controlled variants.\n", | ||
"\n", | ||
"- `get_ctrl_system_1bit_cv_from_bloqs` - Override when a specialized controlled-by-1 implementation is available.\n", | ||
"- `get_ctrl_system_1bit_cv` - Override when both specialized controlled-by-1 and controlled-by-0 implementations are available.\n", | ||
"\n", | ||
"The following demonstrates an example for a bloq implementing $T^\\dagger X T$, where the controlled version only needs to control the $X$." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "1", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import attrs\n", | ||
"from qualtran import Bloq, BloqBuilder, Soquet, SoquetT, Signature, CtrlSpec, AddControlledT\n", | ||
"from qualtran.bloqs.basic_gates import TGate, XGate, CNOT\n", | ||
"\n", | ||
"\n", | ||
"@attrs.frozen\n", | ||
"class BloqWithSpecializedCtrl(Bloq):\n", | ||
" \"\"\"Bloq implementing $T^\\dagger X T$\"\"\"\n", | ||
" is_controlled: bool = False\n", | ||
"\n", | ||
" @property\n", | ||
" def signature(self) -> 'Signature':\n", | ||
" n_ctrls = 1 if self.is_controlled else 0\n", | ||
" return Signature.build(ctrl=n_ctrls, q=1)\n", | ||
" \n", | ||
" def build_composite_bloq(self, bb: 'BloqBuilder', q: 'Soquet', **soqs) -> dict[str, 'SoquetT']:\n", | ||
" ctrl = soqs.pop('ctrl', None)\n", | ||
" \n", | ||
" q = bb.add(TGate(), q=q)\n", | ||
" if self.is_controlled:\n", | ||
" ctrl, q = bb.add(CNOT(), ctrl=ctrl, target=q)\n", | ||
" else:\n", | ||
" ctrl, q = bb.add(XGate(), ctrl=ctrl, target=q)\n", | ||
" q = bb.add(TGate().adjoint(), q=q)\n", | ||
" \n", | ||
" out_soqs = {'q': q}\n", | ||
" if ctrl:\n", | ||
" out_soqs |= {'ctrl': ctrl}\n", | ||
" return out_soqs\n", | ||
" \n", | ||
" def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']:\n", | ||
" from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv_from_bloqs\n", | ||
"\n", | ||
" return get_ctrl_system_1bit_cv_from_bloqs(\n", | ||
" self,\n", | ||
" ctrl_spec,\n", | ||
" current_ctrl_bit=1 if self.is_controlled else None,\n", | ||
" bloq_with_ctrl=attrs.evolve(self, is_controlled=True),\n", | ||
" ctrl_reg_name='ctrl',\n", | ||
" )" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "2", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from qualtran.drawing import show_bloq, show_call_graph\n", | ||
"\n", | ||
"bloq = BloqWithSpecializedCtrl().controlled().controlled()\n", | ||
"show_bloq(bloq.decompose_bloq().flatten())\n", | ||
"show_call_graph(bloq)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "3", | ||
"metadata": {}, | ||
"source": [ | ||
"## Propagating the Adjoint\n", | ||
"\n", | ||
"In the above bloq, calling controlled on the adjoint does not push the controls into the bloq, and therefore does not use the specialized implementation provided." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "4", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"BloqWithSpecializedCtrl().adjoint().controlled()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "5", | ||
"metadata": {}, | ||
"source": [ | ||
"This can be fixed by overriding the adjoint using a special wrapper for this case - `AdjointWithSpecializedCtrl`. This is a subclass of the default `Adjoint` metabloq, and ensures that single-qubit controls are pushed into the underlying bloq." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "6", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"@attrs.frozen\n", | ||
"class BloqWithSpecializedCtrlWithAdjoint(Bloq):\n", | ||
" \"\"\"Bloq implementing $T^\\dagger X T$\"\"\"\n", | ||
" is_controlled: bool = False\n", | ||
"\n", | ||
" @property\n", | ||
" def signature(self) -> 'Signature':\n", | ||
" n_ctrls = 1 if self.is_controlled else 0\n", | ||
" return Signature.build(ctrl=n_ctrls, q=1)\n", | ||
" \n", | ||
" def build_composite_bloq(self, bb: 'BloqBuilder', q: 'Soquet', **soqs) -> dict[str, 'SoquetT']:\n", | ||
" ctrl = soqs.pop('ctrl', None)\n", | ||
" \n", | ||
" q = bb.add(TGate(), q=q)\n", | ||
" if self.is_controlled:\n", | ||
" ctrl, q = bb.add(CNOT(), ctrl=ctrl, target=q)\n", | ||
" else:\n", | ||
" ctrl, q = bb.add(XGate(), ctrl=ctrl, target=q)\n", | ||
" q = bb.add(TGate().adjoint(), q=q)\n", | ||
" \n", | ||
" out_soqs = {'q': q}\n", | ||
" if ctrl:\n", | ||
" out_soqs |= {'ctrl': ctrl}\n", | ||
" return out_soqs\n", | ||
" \n", | ||
" def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']:\n", | ||
" from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv_from_bloqs\n", | ||
"\n", | ||
" return get_ctrl_system_1bit_cv_from_bloqs(\n", | ||
" self,\n", | ||
" ctrl_spec,\n", | ||
" current_ctrl_bit=1 if self.is_controlled else None,\n", | ||
" bloq_with_ctrl=attrs.evolve(self, is_controlled=True),\n", | ||
" ctrl_reg_name='ctrl',\n", | ||
" )\n", | ||
"\n", | ||
" def adjoint(self):\n", | ||
" from qualtran.bloqs.mcmt.specialized_ctrl import AdjointWithSpecializedCtrl, SpecializeOnCtrlBit\n", | ||
" \n", | ||
" return AdjointWithSpecializedCtrl(self, SpecializeOnCtrlBit.ONE)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "7", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"BloqWithSpecializedCtrlWithAdjoint().adjoint().controlled()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "8", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"assert BloqWithSpecializedCtrlWithAdjoint().adjoint().controlled() == BloqWithSpecializedCtrlWithAdjoint(is_controlled=True).adjoint()" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3 (ipykernel)", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.11.9" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 5 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters