Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
13 changes: 8 additions & 5 deletions qualtran/qlt_ir/_to_qlt_ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,18 +573,21 @@ def bloq_to_ast(
# Signature
qdb.add_signature(bloq.signature)

if force_extern:
return qdb.finalize_extern(reason='force_extern'), []

# Detect bookkeeping / casting bloqs and emit as qcast.
# Alloc and Free are _BookkeepingBloqs but are *not* casts.
# These checks come before `force_extern`: a cast has no body to hide, so it is
# always emitted as a `qcast` (and alloc/free are always `extern` anyways).
from qualtran.bloqs.bookkeeping.allocate import Allocate
from qualtran.bloqs.bookkeeping.free import Free

if isinstance(bloq, (Allocate, Free)):
return qdb.finalize_extern(reason='alloc/free'), []
if _is_qcast_bloq(bloq):
return qdb.finalize_qcast(), []

if force_extern:
return qdb.finalize_extern(reason='force_extern'), []

if isinstance(bloq, qlt.CompositeBloq):
cbloq = bloq
else:
Expand Down Expand Up @@ -656,7 +659,7 @@ def add_bloqs(
include_annotations: Whether to include visual display annotations derived
from `bloq.wire_symbol`.
extern_only_from: Whether to only include a `from` clause for `extern` bloqs.
force_extern_pred: A predicate selecting bloqs to force to `extern`.
force_extern_pred: A predicate selecting non-cast bloqs to force to `extern`.
max_depth: If provided, only decompose bloqs whose minimum depth below
`root` is less than `max_depth`, emitting bloqs at or beyond `max_depth`
as `extern qdef`. `None` (the default) decomposes fully.
Expand Down Expand Up @@ -760,7 +763,7 @@ def dump_qlt_ir(
include_annotations: Whether to include visual display annotations derived
from `bloq.wire_symbol` (defaults to `False`).
extern_only_from: Whether to only include a `from` clause for `extern` bloqs.
force_extern_pred: A predicate selecting bloqs to force to `extern`.
force_extern_pred: A predicate selecting non-cast bloqs to force to `extern`.
max_depth: If provided, only decompose bloqs whose minimum depth below
`bloq` is less than `max_depth`, emitting bloqs at or beyond `max_depth`
as `extern qdef`. `None` (the default) decomposes fully.
Expand Down
35 changes: 35 additions & 0 deletions qualtran/qlt_ir/_to_qlt_ir_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import io
from typing import Any

import pytest

Expand Down Expand Up @@ -567,3 +568,37 @@ def build_composite_bloq(self, bb, q):
assert isinstance(by_key['_Shared'].qdef, QDefImplNode)
assert by_key['T'].implemented is False
assert isinstance(by_key['T'].qdef, QDefExternNode)


def test_max_depth_and_force_extern_keep_qcasts():
"""Casting bloqs have no body to hide, so they stay `qcast` below `max_depth`."""
from qualtran.bloqs.arithmetic import Add
from qualtran.bloqs.bookkeeping import Join, Split
from qualtran.qlt_ir import parse_module
from qualtran.qlt_ir.nodes import QCastNode

bloq = Add(qdt.QUInt(4))

all_mb_kwargs: list[dict[str, Any]] = [
dict(max_depth=1),
dict(force_extern_pred=lambda b: b != bloq),
]
for mb_kwargs in all_mb_kwargs:
mb = QltModuleBuilder()
mb.add_bloqs(bloq, **mb_kwargs)
by_bloq = {q.bloq: q for q in mb.qdefs}
assert isinstance(by_bloq[bloq].qdef, QDefImplNode)
casts = [b for b in by_bloq if isinstance(b, (Split, Join))]
assert casts, 'Add(QUInt(4)) decomposition should contain splits/joins'
for b in casts:
assert isinstance(by_bloq[b].qdef, QCastNode), b
for b, q in by_bloq.items():
if b != bloq and not isinstance(b, (Split, Join)):
assert isinstance(q.qdef, QDefExternNode), b

txt = dump_root_qlt_ir(bloq)
assert txt is not None
assert 'extern qdef Split' not in txt
assert 'extern qdef Join' not in txt
mod = parse_module(txt)
assert any(isinstance(q, QCastNode) for q in mod.qdefs)
Loading