Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion dev_tools/qualtran_dev_tools/make_reference_docs/_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@
]
MINIMAL = True

DEFINED_IN_CONTAINER_EXCEPTIONS = ['qualtran.dtype', 'qualtran.exception', 'qualtran.cirq_interop']
DEFINED_IN_CONTAINER_EXCEPTIONS = [
'qualtran.dtype',
'qualtran.exception',
'qualtran.cirq_interop',
'qualtran.l1.nodes',
]


def _get_all_aliases(obj: Union[griffe.Object, griffe.Alias]) -> Set[str]:
Expand Down
28 changes: 28 additions & 0 deletions qualtran/_infra/composite_bloq.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@

from qualtran.bloqs.bookkeeping.auto_partition import Unused
from qualtran.cirq_interop._cirq_to_bloq import CirqQuregInT, CirqQuregT
from qualtran.drawing import WireSymbol
from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator
from qualtran.simulation.classical_sim import ClassicalValT
from qualtran.symbolics import SymbolicInt
Expand Down Expand Up @@ -122,12 +123,20 @@ class CompositeBloq(Bloq):
should correspond to the dangling `Soquets` in the `cxns`.
bloq_instances: Optionally specify the unique bloq instances. Otherwise, deduce them from
the connections.
decomposed_from: Optionally include a reference to the bloq from whence this
`CompositeBloq` was decomposed. This can be used for debugging and error
reporting, but is never used for deriving any properties.
bloq_key: An optional string key for this bloq. This can be used for debugging and
error reporting, but is never used for deriving any properties.
"""

connections: Tuple[Connection, ...] = attrs.field(converter=_to_tuple)
signature: Signature
bloq_instances: FrozenSet[BloqInstance] = attrs.field(converter=_to_set)

decomposed_from: Optional[Bloq] = attrs.field(default=None, kw_only=True)
bloq_key: Optional[str] = attrs.field(default=None, kw_only=True)

@bloq_instances.default
def _default_bloq_instances(self):
return {
Expand Down Expand Up @@ -505,7 +514,23 @@ def debug_text(self) -> str:
delimited_gens = ('\n' + '-' * 20 + '\n').join(gen_texts)
return delimited_gens

def wire_symbol(
self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple()
) -> 'WireSymbol':
from qualtran.drawing import Text

if reg is None:
if self.decomposed_from is not None:
return self.decomposed_from.wire_symbol(None)
if self.bloq_key is not None:
return Text(self.bloq_key)
return Text('cbloq')

return super().wire_symbol(reg, idx)

def __str__(self):
if self.bloq_key is not None:
return self.bloq_key
return f'CompositeBloq([{len(self.bloq_instances)} subbloqs...])'


Expand Down Expand Up @@ -535,6 +560,9 @@ def _binst_to_cxns(
binst: Union[BloqInstance, DanglingT], binst_graph: nx.DiGraph
) -> Tuple[List[Connection], List[Connection]]:
"""Helper method to extract all predecessor and successor Connections for a binst."""
if binst not in binst_graph.nodes:
return [], []

pred_cxns: List[Connection] = []
for pred in binst_graph.pred[binst]:
pred_cxns.extend(binst_graph.edges[pred, binst]['cxns'])
Expand Down
178 changes: 178 additions & 0 deletions qualtran/l1/L1-Text-IR.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "83e446f6-4f99-4a93-a854-0423e4421b35",
"metadata": {},
"source": [
"# Qualtran-L1 Intermediate Representation\n",
"\n",
"The L1 intermediate representation (IR) for Qualtran is a host-language-agnostic interchange format for hierarchical composite quantum programs. The Python `qualtran` library (Qualtran-L2) can compile to Qualtran-L1.\n",
"\n",
" - L1 quantum functions are represented as text vs. L2 bloqs represented as in-memory Python objects.\n",
" - a L1 `*.qlt` file contains a full hierarchical record of the quantum funciton vs. \"lazy\" evaluation of decompositions in L2.\n",
" - Compile-time classical parameters are filled in and static in L1 vs. templated families of quantum subroutines via bloq classes in L2."
]
},
{
"cell_type": "markdown",
"id": "7d56515d-2d3f-4cc2-97c6-5efe02eb3b84",
"metadata": {},
"source": [
"## Example usage"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ab390b71-0792-4a48-af09-27463f7d3390",
"metadata": {},
"outputs": [],
"source": [
"import qualtran as qlt\n",
"import qualtran.dtype as qdt"
]
},
{
"cell_type": "markdown",
"id": "667a66b5-8e1c-4d20-b3a4-17a499a8b512",
"metadata": {},
"source": [
"### `dump_l1`\n",
"\n",
"This function will take a bloq and recursively \"compile\" it to the static L1 textual representation. \n",
"\n",
" - The hierarchical structure of the program definition is maintained.\n",
" - Each bloq object is included as a `qdef` quantum function declaration with a static quantum signature (enclosed in square brackets).\n",
" - Bloq objects with a defined decomposition include a `qdef` quantum function definition with a static function body (enclosed in curly braces) encoding the composition.\n",
" - Bloq objects without a defined decomposition are included as `extern qdef` declarations *only*. These must include the `from` clause, which provides the L1-objectstrng used to *link* the extern qdefs with an in-memory Python bloq object."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4f412be1-1377-4524-a124-fd51383ac335",
"metadata": {},
"outputs": [],
"source": [
"from qualtran.bloqs.arithmetic import BitwiseNot\n",
"from qualtran.l1 import dump_l1\n",
"\n",
"l1_code = dump_l1(BitwiseNot(qdt.QUInt(4)))\n",
"print(l1_code)"
]
},
{
"cell_type": "markdown",
"id": "b8cf9e9d-e528-4925-872b-ed598ba6928c",
"metadata": {},
"source": [
"### `dump_root_l1`\n",
"\n",
"This convenience function is provided to only dump one level of decomposition and declare each of the immediate callees as extern qdefs."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d6f7696e-b255-434b-a8d7-ff767a0e050c",
"metadata": {},
"outputs": [],
"source": [
"from qualtran.bloqs.arithmetic import Negate\n",
"from qualtran.l1 import dump_root_l1\n",
"\n",
"negate = Negate(qdt.QUInt(8))\n",
"root_l1_code = dump_root_l1(negate)\n",
"print(root_l1_code)"
]
},
{
"cell_type": "markdown",
"id": "9ac23592-9f55-4ef0-9675-2c2c97f82a6c",
"metadata": {},
"source": [
"### `load_module`"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "76769eeb-a777-4bf3-9466-05efda846cf5",
"metadata": {},
"outputs": [],
"source": [
"from qualtran.l1 import load_module\n",
"module = load_module(\"\"\"\n",
"# Qualtran-L1\n",
"# 1.0.0\n",
"\n",
"qdef Negate[x: QUInt(8)] {\n",
" x2 = BitwiseNot(8)[x=x] \n",
" x3 = AddK(k=1)[x=x2] \n",
" return [x=x3] \n",
"}\n",
"\n",
"extern qdef BitwiseNot(8)\n",
"from qualtran.bloqs.arithmetic.BitwiseNot(QUInt(8))\n",
"[x: QUInt(8)]\n",
"\n",
"extern qdef AddK(k=1)\n",
"from qualtran.bloqs.arithmetic.AddK(QUInt(8), 1)\n",
"[x: QUInt(8)]\"\"\")\n",
"module.keys()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0d98758f-8efd-42bb-a918-6842074be601",
"metadata": {},
"outputs": [],
"source": [
"module['Negate'].bloq_instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "72e18029-f45f-4a31-8cf9-1f5ce72698ef",
"metadata": {},
"outputs": [],
"source": [
"type(module['Negate']), type(negate)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8b7a75c5-7002-4294-8171-7edaecdccd55",
"metadata": {},
"outputs": [],
"source": [
"module['Negate'].call_classically(x=1)"
]
}
],
"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.13.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
10 changes: 7 additions & 3 deletions qualtran/l1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from ._eval import eval_cvalue_node
from ._parse import parse_objectstring
from ._parse_eval import load_objectstring
from ._ast_to_code import L1ASTPrinter
from ._ast_visitor_base import L1VisitorBase
from ._eval import eval_cvalue_node, eval_module
from ._parse import dump_ast, parse_module, parse_objectstring
from ._parse_eval import load_bloq, load_module, load_objectstring
from ._to_cobject_node import dump_objectstring, to_cobject_node
from ._to_l1 import dump_l1, dump_root_l1, L1ModuleBuilder
from ._vm import StandardQualtranArchitectureAgnosticVirtualMachine
Loading
Loading