From eb7356a69ca7ef585cb34f47d4c2cf860d7da17e Mon Sep 17 00:00:00 2001 From: mstechly Date: Thu, 27 Jun 2024 15:54:43 -0400 Subject: [PATCH 01/12] WiP QREF integration. --- qualtran/qref_interop/__init__.py | 1 + qualtran/qref_interop/_bloq_to_qref.py | 280 +++++++++++++++++++++ qualtran/qref_interop/qualtran_bartiq.py | 58 +++++ qualtran/qref_interop/test_bloq_to_qref.py | 31 +++ 4 files changed, 370 insertions(+) create mode 100644 qualtran/qref_interop/__init__.py create mode 100644 qualtran/qref_interop/_bloq_to_qref.py create mode 100644 qualtran/qref_interop/qualtran_bartiq.py create mode 100644 qualtran/qref_interop/test_bloq_to_qref.py diff --git a/qualtran/qref_interop/__init__.py b/qualtran/qref_interop/__init__.py new file mode 100644 index 000000000..f2f82519b --- /dev/null +++ b/qualtran/qref_interop/__init__.py @@ -0,0 +1 @@ +from ._bloq_to_qref import bloq_to_qref diff --git a/qualtran/qref_interop/_bloq_to_qref.py b/qualtran/qref_interop/_bloq_to_qref.py new file mode 100644 index 000000000..07daa6a66 --- /dev/null +++ b/qualtran/qref_interop/_bloq_to_qref.py @@ -0,0 +1,280 @@ +""" +.. Copyright © 2023-2024 PsiQuantum Corp. All rights reserved. + PSIQUANTUM CORP. CONFIDENTIAL + This file includes unpublished proprietary source code of PsiQuantum Corp. + The copyright notice above does not evidence any actual or intended publication + of such source code. Disclosure of this source code or any related proprietary + information is strictly prohibited without the express written permission of + PsiQuantum Corp. + +Integration with Qualtran. +""" + +from functools import singledispatch +from typing import Any, Iterable, Optional + +from qualtran import Bloq, BloqInstance, CompositeBloq +from qualtran import Connection as QualtranConnection +from qualtran import Register, Side, Soquet +from qualtran.cirq_interop import CirqGateAsBloq + +from qref.schema_v1 import RoutineV1, PortV1, ConnectionV1, ResourceV1, SchemaV1 + + +@singledispatch +def _bloq_type(bloq: Bloq) -> str: + """Determine type of Bloq. + + Output of this function is used for populating the `type` field of RoutineV1 + build from imported Bloqs. By default, we use name of the type of the Bloq. + """ + return type(bloq).__name__ + + +@_bloq_type.register +def _cirq_gate_bloq_type(bloq: CirqGateAsBloq) -> str: + """Determine type of Bloq constructed from Cirq gate. + + Without this variant of _bloq_type, type of all instances of CirqGateAsBloq + are set to "CirqGateAsBloq" which is not helpful, because all gates get the + same type. Instead of this default behaviour, we extract textual representation + of the Cirq's gate. + """ + return str(bloq.gate) + + +def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> dict[str, Any]: + """Extract common bloq attributes such as name, type and ports. + + + There are several Bloq classes, however, they all share common set of atributes. + This function is used to extract them, so that we don't have to duplicate logic + for each Bloq subtype. + + Args: + bloq: Bloq for which information should be extracted. + name: Optional override for name. Setting it to None will cause some reasonable + name (depending on bloq type) to be inferred. The typical use of non-trivial + name is when a better name is known from the parent Bloq. + + Returns: + A dictionary that can be unpacked into arguments of RoutineV1 initializer, + containing the following fields: "name", "type", "ports". + """ + return { + "name": bloq.__class__.__name__ if name is None else name, + "type": _bloq_type(bloq), + "ports": [port for reg in bloq.signature for port in _ports_from_register(reg)], + "resources": _import_resources(bloq), + "input_params": _extract_input_params(bloq), + } + + +def _bloq_instance_name(instance: BloqInstance) -> str: + """Infer unique (but readable) name for a BloqInstance. + + Child Bloqs in CompositeBloq (and some other places) are stored as BloqInstances, + which combine a Bloq with a unique ID. When converting such BloqInstance to Bartiq + RoutineV1, the ID has to be incorporated into the name, because otherwise one could + get several siblings having the same name. + """ + return f"{_bloq_type(instance.bloq)}_{instance.i}" + + +def bloq_to_qref(obj) -> SchemaV1: + """TODO""" + return SchemaV1(version="v1", program=bloq_to_routine(obj)) + + +@singledispatch +def bloq_to_routine(obj, name: Optional[str] = None): + """Import object from Qualtran by converting it into coresponding Bartiq object. + + Args: + obj: object to be imported. Can be either Bloq or BloqInstance. + name: optional name override. This can be useful e.g. if you are converting + CompositeBloq (which do not store meaningful names in Qualtran) and + know some good name for it. + + Return: + A Bartiq object corresponding to the source Qualtran object. For both Bloqs + and BloqInstances the returned object is of type RoutineV1. + + """ + raise NotImplementedError(f"Cannot import object {obj} of type {type(obj)}.") + + +@bloq_to_routine.register +def _composite_bloq_to_routine(bloq: CompositeBloq, name: Optional[str] = None) -> RoutineV1: + """Import CompositeBloq from Qualtran. + + See `import_from_qualtran` for moe info. + """ + return RoutineV1( + **_extract_common_bloq_attributes(bloq, name), + children=[bloq_to_routine(instance) for instance in bloq.bloq_instances], + connections=[_import_connection(c) for c in bloq.connections], + ) + + +@bloq_to_routine.register +def _bloq_to_routine(bloq: Bloq, name: Optional[str] = None) -> RoutineV1: + """Import Bloq (other than CompositeBloq) from Qualtran. + + See `import_from_qualtran` for moe info. + """ + return RoutineV1(**_extract_common_bloq_attributes(bloq, name)) + + +@bloq_to_routine.register +def _bloq_instance_to_routine(instance: BloqInstance) -> RoutineV1: + """Import Bloq (other than CompositeBloq) from Qualtran. + + When importing BloqInstance we derive name from Bloq's default name and + instance ID to prevent duplication of names between siblings. + + See `import_from_qualtran` and `_bloq_instance_name` for more info. + """ + return bloq_to_routine(instance.bloq, name=_bloq_instance_name(instance)) + + +def _names_and_dir_from_register(reg: Register) -> Iterable[tuple[str, str]]: + """Yield names and directions of Bartiq Ports corresponding to QualtranRegister. + + For LEFT/RIGHT registers we yield one pair of name and direction corresponding + of resp. output and input port. For THRU registers we yield both such pairs, + which effectively splits THRU registers into two ports. + """ + if reg.side != Side.LEFT: + yield (f"out_{reg.name}", "output") + if reg.side != Side.RIGHT: + yield (f"in_{reg.name}", "input") + + +def _expand_name_if_needed(reg_name, shape) -> Iterable[str]: + """Given a register name, expand it into sequence of names if it has nontrivial shape. + + Examples: + "reg", () -> "reg" + "reg", (3,) -> "reg_0", "reg_1", "reg_2" + """ + return (reg_name,) if shape == () else (f"{reg_name}_{i}" for i in range(shape[0])) + + +def _ports_from_register(reg: Register) -> Iterable[PortV1]: + """Given a Qualtran register, return iterable of corresponding Bartiq Ports. + + Intuitively, one would expect a one to one correspondence between ports and registers. + However: + - We currently don't support bidirectional ports. Hence, THRU registers have to be + split into pairs of input/output ports + - We currently don't support composite ports. Hence composite registers (i.e. ones + with a nontrivial shape) have to be split into multiple ports. + + Args: + reg: Register to be converted into ports. + + Raises: + NotImplementedError: if `reg` is a compound register with more than one-dimension. + Currently we don't support such scenario. + """ + if len(reg.shape) > 1: + raise NotImplementedError( + "Registers with two or more dimensional shape are not yet supported. " + f"The error was caused by register {reg}." + ) + + return sorted( + [ + # Observe two loops: + # - first one splits (if needed) any THRU register into two ports. It also takes care of + # correct naming based on port directions. + # - second one expands composite register (which have no counterpart in Bartiq) into + # required number of single ports. + PortV1( + name=expanded_name, + direction=direction, + size=reg.bitsize if isinstance(reg.bitsize, int) else str(reg.bitsize), + ) + for flat_name, direction in _names_and_dir_from_register(reg) + for expanded_name in _expand_name_if_needed(flat_name, reg.shape) + ], + key=lambda p: p.name, + ) + + +def _opposite(direction: str) -> str: + return "out" if direction == "in" else "in" + + +def _relative_port_name(soquet: Soquet, direction) -> str: + """Given a Soquet and direction, determine the relative name of corresponding Bartiq Port. + + The relative name is always computed wrt. the parent RoutineV1. + This function correctly recognizes the fact, that in any connection, the input parent + ports serve as outputs for the connection (and vice versa). + """ + if len(soquet.idx) > 1: + raise NotImplementedError( + "Soquets referencing more than one index in composite register are not yet supported. " + f"The error was caused by the following soquet: {soquet}." + ) + # We add another suffix iff soquet references idx in composite register + suffix = f"_{soquet.idx[0]}" if soquet.idx else "" + return ( + # If soquet references BlogqInstance, the corresponding object in Bartiq + # references child - construct dotted relative name. + # Otherwise, soquet references the parent port, and so for the output direction, + # the port is in_parent_port, which is why we include _opposte here. + f"{_bloq_instance_name(soquet.binst)}.{direction}_{soquet.reg.name}{suffix}" + if isinstance(soquet.binst, BloqInstance) + else f"{_opposite(direction)}_{soquet.reg.name}{suffix}" + ) + + +def _import_connection(connection: QualtranConnection) -> dict[str, Any]: + """Import connection from Qualtran.""" + return { + "source": _relative_port_name(connection.left, "out"), + "target": _relative_port_name(connection.right, "in"), + } + + +def _import_resources(bloq: Bloq) -> list[dict[str, Any]]: + t_complexity = bloq.t_complexity() + resource_names = ["t", "clifford", "rotations"] + resources = [] + for name in resource_names: + resources.append( + { + "name": name, + "value": _ensure_primitive_type(getattr(t_complexity, name)), + "type": "additive", + } + ) + # if all(resource["value"] == 0 for resource in resources): + # return {} + return resources + + +from typing import Union + + +# TODO: copied from Bartiq QREF integration +def _ensure_primitive_type(value: Any) -> Union[int, float, str, None]: + """Ensure given value is of primitive type (e.g. is not a sympy expression).""" + return value if value is None or isinstance(value, (int, float, str)) else str(value) + + +# TODO: typing +def _extract_input_params(bloq: Bloq): + input_params = set() + # TODO: logic duplication from _import_resources + t_complexity = bloq.t_complexity() + resource_names = ["t", "clifford", "rotations"] + for name in resource_names: + try: + input_params.update(getattr(t_complexity, name).free_symbols) + except AttributeError: + pass + return [str(symbol) for symbol in input_params] diff --git a/qualtran/qref_interop/qualtran_bartiq.py b/qualtran/qref_interop/qualtran_bartiq.py new file mode 100644 index 000000000..0026ad384 --- /dev/null +++ b/qualtran/qref_interop/qualtran_bartiq.py @@ -0,0 +1,58 @@ +from qualtran.bloqs.state_preparation import StatePreparationAliasSampling +from qualtran.qref_interop import bloq_to_qref +from qualtran.drawing.graphviz import PrettyGraphDrawer +from qref.experimental.rendering import to_graphviz +from bartiq.integrations.qref import qref_to_bartiq +from bartiq import compile_routine, evaluate +from qualtran.bloqs.data_loading.qrom import QROM + +import yaml +import sympy + +bloq = StatePreparationAliasSampling.from_lcu_probs( + [0.25, 0.5, 0.25], probability_epsilon=0.05 +) # .decompose_bloq() + +N, M, b1, b2, c = sympy.symbols("N M b1 b2 c") +# N = 10 +# M = 15 +# b1 = 5 +# b2 = 3 +# c = 10 +# bloq = QROM.build_from_bitsize((N, M), (b1, b2), num_controls=c) +# bloq = QROM.build_from_bitsize((N, M), (b1, b2), num_controls=c).decompose_bloq() + + +bloq_image = PrettyGraphDrawer(bloq).get_svg_bytes() + +with open("bloq.svg", "wb") as f: + f.write(bloq_image) + +qref_definition = bloq_to_qref(bloq) + +with open("qref.yaml", "w") as f: + yaml.safe_dump(qref_definition.model_dump(exclude_unset=True), f, default_flow_style=None) + +graphviz_object = to_graphviz(qref_definition) +graphviz_object.render("qualtran_to_qref") + + +routine = qref_to_bartiq(qref_definition) +print("Initial resources:") +print(routine.resources) +# routine.resources = {} +# print("Empty resources:") +# print(routine.resources) + +# breakpoint() + +compiled_routine = compile_routine(routine) +print("Compiled resources:") +print(compiled_routine.resources) + +# assignments = ["c=20"] +# evaluated_routine = evaluate(compiled_routine, assignments) +# print("Evaluated resources:") +# print(evaluated_routine.resources) + +breakpoint() diff --git a/qualtran/qref_interop/test_bloq_to_qref.py b/qualtran/qref_interop/test_bloq_to_qref.py new file mode 100644 index 000000000..0cd94add7 --- /dev/null +++ b/qualtran/qref_interop/test_bloq_to_qref.py @@ -0,0 +1,31 @@ +from dev_tools.qualtran_dev_tools.bloq_finder import get_bloq_examples +from qualtran.qref_interop import bloq_to_qref +import pytest + +from qualtran import DecomposeTypeError, DecomposeNotImplementedError +from qref.verification import verify_topology + + +@pytest.mark.parametrize("bloq_example", get_bloq_examples()) +def test_bloq_examples_can_be_converted_to_qualtran(bloq_example): + bloq = bloq_example.make() + try: + qref_routine = bloq_to_qref(bloq) + verify_topology(qref_routine) + except: + pytest.xfail(f"QREF conversion failing for {bloq}") + + +@pytest.mark.parametrize("bloq_example", get_bloq_examples()) +def test_bloq_examples_can_be_converted_to_qualtran_when_decomposed(bloq_example): + try: + bloq = bloq_example.make().decompose_bloq() + # I think ValueError here is a bit hacky + except (DecomposeTypeError, DecomposeNotImplementedError, ValueError) as e: + pytest.xfail(f"QREF conversion not attempted, as bloq decomposition faield with {e}") + + try: + qref_routine = bloq_to_qref(bloq) + # verify_topology(qref_routine) + except: + pytest.xfail(f"QREF conversion failing for {bloq}") From 325d8a36a8d773968578c423cc0dde138f87cdf5 Mon Sep 17 00:00:00 2001 From: mstechly Date: Wed, 24 Jul 2024 16:52:45 +0200 Subject: [PATCH 02/12] Conversion to QREF updated --- qualtran/qref_interop/__init__.py | 2 +- qualtran/qref_interop/_bloq_to_qref.py | 99 +++-- qualtran/qref_interop/qualtran_bartiq.py | 58 --- qualtran/qref_interop/test_bloq_to_qref.py | 445 ++++++++++++++++++++- 4 files changed, 506 insertions(+), 98 deletions(-) delete mode 100644 qualtran/qref_interop/qualtran_bartiq.py diff --git a/qualtran/qref_interop/__init__.py b/qualtran/qref_interop/__init__.py index f2f82519b..4691d4b65 100644 --- a/qualtran/qref_interop/__init__.py +++ b/qualtran/qref_interop/__init__.py @@ -1 +1 @@ -from ._bloq_to_qref import bloq_to_qref +from ._bloq_to_qref import bloq_to_qref, bloq_to_qref_from_call_graph diff --git a/qualtran/qref_interop/_bloq_to_qref.py b/qualtran/qref_interop/_bloq_to_qref.py index 07daa6a66..5be37cb94 100644 --- a/qualtran/qref_interop/_bloq_to_qref.py +++ b/qualtran/qref_interop/_bloq_to_qref.py @@ -1,25 +1,16 @@ -""" -.. Copyright © 2023-2024 PsiQuantum Corp. All rights reserved. - PSIQUANTUM CORP. CONFIDENTIAL - This file includes unpublished proprietary source code of PsiQuantum Corp. - The copyright notice above does not evidence any actual or intended publication - of such source code. Disclosure of this source code or any related proprietary - information is strictly prohibited without the express written permission of - PsiQuantum Corp. - -Integration with Qualtran. -""" +import networkx as nx from functools import singledispatch -from typing import Any, Iterable, Optional +from typing import Any, Iterable, Optional, Union + +import sympy +from qref.schema_v1 import PortV1, RoutineV1, SchemaV1 from qualtran import Bloq, BloqInstance, CompositeBloq from qualtran import Connection as QualtranConnection from qualtran import Register, Side, Soquet from qualtran.cirq_interop import CirqGateAsBloq -from qref.schema_v1 import RoutineV1, PortV1, ConnectionV1, ResourceV1, SchemaV1 - @singledispatch def _bloq_type(bloq: Bloq) -> str: @@ -36,17 +27,24 @@ def _cirq_gate_bloq_type(bloq: CirqGateAsBloq) -> str: """Determine type of Bloq constructed from Cirq gate. Without this variant of _bloq_type, type of all instances of CirqGateAsBloq - are set to "CirqGateAsBloq" which is not helpful, because all gates get the + are set to "CirqGateAsBloq" which is not helpful, because all gates would get the same type. Instead of this default behaviour, we extract textual representation of the Cirq's gate. """ return str(bloq.gate) +def _is_symbol_or_int(expression): + try: + int(expression) + return True + except (TypeError, ValueError): + return expression.isidentifier() + + def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> dict[str, Any]: """Extract common bloq attributes such as name, type and ports. - There are several Bloq classes, however, they all share common set of atributes. This function is used to extract them, so that we don't have to duplicate logic for each Bloq subtype. @@ -58,16 +56,40 @@ def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> d name is when a better name is known from the parent Bloq. Returns: - A dictionary that can be unpacked into arguments of RoutineV1 initializer, - containing the following fields: "name", "type", "ports". + A dictionary that can be unpacked into arguments of RoutineV1 initializer. """ - return { - "name": bloq.__class__.__name__ if name is None else name, + ports = [port for reg in bloq.signature for port in _ports_from_register(reg)] + local_variables = {} + for port in ports: + if not _is_symbol_or_int(str(port.size)): + local_variable_name = f"{port.name}_size" + local_variables[local_variable_name] = port.size + port.size = local_variable_name + + if name is None: + name = bloq.__class__.__name__ + try: + if bloq.uncompute: + name += "_uncompute" + except AttributeError: + pass + try: + if bloq.is_adjoint: + name += "_adjoint" + except AttributeError: + pass + input_params = _extract_input_params(bloq, ports, local_variables) + + attributes = { + "name": name, "type": _bloq_type(bloq), - "ports": [port for reg in bloq.signature for port in _ports_from_register(reg)], + "ports": ports, "resources": _import_resources(bloq), - "input_params": _extract_input_params(bloq), + "input_params": input_params, } + if len(local_variables) > 0: + attributes["local_variables"] = local_variables + return attributes def _bloq_instance_name(instance: BloqInstance) -> str: @@ -82,13 +104,13 @@ def _bloq_instance_name(instance: BloqInstance) -> str: def bloq_to_qref(obj) -> SchemaV1: - """TODO""" + """Converts Bloq to QREF SchemaV1 object.""" return SchemaV1(version="v1", program=bloq_to_routine(obj)) @singledispatch def bloq_to_routine(obj, name: Optional[str] = None): - """Import object from Qualtran by converting it into coresponding Bartiq object. + """Import object from Qualtran by converting it into corresponding QREF RoutineV1 object. Args: obj: object to be imported. Can be either Bloq or BloqInstance. @@ -108,7 +130,7 @@ def bloq_to_routine(obj, name: Optional[str] = None): def _composite_bloq_to_routine(bloq: CompositeBloq, name: Optional[str] = None) -> RoutineV1: """Import CompositeBloq from Qualtran. - See `import_from_qualtran` for moe info. + See `import_from_qualtran` for more info. """ return RoutineV1( **_extract_common_bloq_attributes(bloq, name), @@ -241,6 +263,7 @@ def _import_connection(connection: QualtranConnection) -> dict[str, Any]: def _import_resources(bloq: Bloq) -> list[dict[str, Any]]: + """Import resources from Bloq's t_complexity method.""" t_complexity = bloq.t_complexity() resource_names = ["t", "clifford", "rotations"] resources = [] @@ -252,24 +275,24 @@ def _import_resources(bloq: Bloq) -> list[dict[str, Any]]: "type": "additive", } ) - # if all(resource["value"] == 0 for resource in resources): - # return {} return resources -from typing import Union - - -# TODO: copied from Bartiq QREF integration def _ensure_primitive_type(value: Any) -> Union[int, float, str, None]: """Ensure given value is of primitive type (e.g. is not a sympy expression).""" return value if value is None or isinstance(value, (int, float, str)) else str(value) -# TODO: typing -def _extract_input_params(bloq: Bloq): +def _extract_input_params(bloq: Bloq, ports: list[PortV1], local_variables) -> list[str]: + """Extracts input_params from bloq's t_complexity and port sizes.""" + params_from_t_complexity = _extract_input_params_from_t_complexity(bloq) + params_from_ports = _extract_input_params_from_ports(ports) + params = list(set(params_from_t_complexity + params_from_ports) - set(local_variables)) + return sorted(params) + + +def _extract_input_params_from_t_complexity(bloq: Bloq) -> list[str]: input_params = set() - # TODO: logic duplication from _import_resources t_complexity = bloq.t_complexity() resource_names = ["t", "clifford", "rotations"] for name in resource_names: @@ -278,3 +301,11 @@ def _extract_input_params(bloq: Bloq): except AttributeError: pass return [str(symbol) for symbol in input_params] + + +def _extract_input_params_from_ports(ports) -> list[str]: + input_params = set() + for port in ports: + input_params = input_params | sympy.sympify(port.size).free_symbols + + return [str(param) for param in input_params] diff --git a/qualtran/qref_interop/qualtran_bartiq.py b/qualtran/qref_interop/qualtran_bartiq.py deleted file mode 100644 index 0026ad384..000000000 --- a/qualtran/qref_interop/qualtran_bartiq.py +++ /dev/null @@ -1,58 +0,0 @@ -from qualtran.bloqs.state_preparation import StatePreparationAliasSampling -from qualtran.qref_interop import bloq_to_qref -from qualtran.drawing.graphviz import PrettyGraphDrawer -from qref.experimental.rendering import to_graphviz -from bartiq.integrations.qref import qref_to_bartiq -from bartiq import compile_routine, evaluate -from qualtran.bloqs.data_loading.qrom import QROM - -import yaml -import sympy - -bloq = StatePreparationAliasSampling.from_lcu_probs( - [0.25, 0.5, 0.25], probability_epsilon=0.05 -) # .decompose_bloq() - -N, M, b1, b2, c = sympy.symbols("N M b1 b2 c") -# N = 10 -# M = 15 -# b1 = 5 -# b2 = 3 -# c = 10 -# bloq = QROM.build_from_bitsize((N, M), (b1, b2), num_controls=c) -# bloq = QROM.build_from_bitsize((N, M), (b1, b2), num_controls=c).decompose_bloq() - - -bloq_image = PrettyGraphDrawer(bloq).get_svg_bytes() - -with open("bloq.svg", "wb") as f: - f.write(bloq_image) - -qref_definition = bloq_to_qref(bloq) - -with open("qref.yaml", "w") as f: - yaml.safe_dump(qref_definition.model_dump(exclude_unset=True), f, default_flow_style=None) - -graphviz_object = to_graphviz(qref_definition) -graphviz_object.render("qualtran_to_qref") - - -routine = qref_to_bartiq(qref_definition) -print("Initial resources:") -print(routine.resources) -# routine.resources = {} -# print("Empty resources:") -# print(routine.resources) - -# breakpoint() - -compiled_routine = compile_routine(routine) -print("Compiled resources:") -print(compiled_routine.resources) - -# assignments = ["c=20"] -# evaluated_routine = evaluate(compiled_routine, assignments) -# print("Evaluated resources:") -# print(evaluated_routine.resources) - -breakpoint() diff --git a/qualtran/qref_interop/test_bloq_to_qref.py b/qualtran/qref_interop/test_bloq_to_qref.py index 0cd94add7..110dc07cd 100644 --- a/qualtran/qref_interop/test_bloq_to_qref.py +++ b/qualtran/qref_interop/test_bloq_to_qref.py @@ -1,10 +1,19 @@ from dev_tools.qualtran_dev_tools.bloq_finder import get_bloq_examples -from qualtran.qref_interop import bloq_to_qref +from qualtran.qref_interop import bloq_to_qref, bloq_to_qref_from_call_graph import pytest +import sympy +from qualtran.bloqs.basic_gates import CNOT +from qualtran.bloqs.arithmetic.comparison import LessThanEqual +from qualtran.bloqs.state_preparation import StatePreparationAliasSampling +from qualtran.bloqs.data_loading.qrom import QROM + from qualtran import DecomposeTypeError, DecomposeNotImplementedError from qref.verification import verify_topology +from qualtran import Bloq, BloqBuilder +from qref.schema_v1 import RoutineV1 + @pytest.mark.parametrize("bloq_example", get_bloq_examples()) def test_bloq_examples_can_be_converted_to_qualtran(bloq_example): @@ -20,12 +29,438 @@ def test_bloq_examples_can_be_converted_to_qualtran(bloq_example): def test_bloq_examples_can_be_converted_to_qualtran_when_decomposed(bloq_example): try: bloq = bloq_example.make().decompose_bloq() - # I think ValueError here is a bit hacky except (DecomposeTypeError, DecomposeNotImplementedError, ValueError) as e: - pytest.xfail(f"QREF conversion not attempted, as bloq decomposition faield with {e}") - + pytest.skip(f"QREF conversion not attempted, as bloq decomposition failed with {e}") try: qref_routine = bloq_to_qref(bloq) - # verify_topology(qref_routine) except: pytest.xfail(f"QREF conversion failing for {bloq}") + + +@pytest.mark.parametrize("bloq_example", get_bloq_examples()) +def test_bloq_examples_can_be_converted_to_qualtran_through_call_graph(bloq_example): + try: + bloq = bloq_example.make() + except (DecomposeTypeError, DecomposeNotImplementedError, ValueError) as e: + pytest.skip(f"QREF conversion not attempted, as extracting callgraph failed with {e}") + try: + qref_routine = bloq_to_qref_from_call_graph(bloq) + except: + pytest.xfail(f"QREF conversion failing for {bloq}") + + +def _cnot_routine(name: str) -> RoutineV1: + return RoutineV1( + name=name, + type="CNOT", + ports=[ + {"name": "in_ctrl", "size": 1, "direction": "input"}, + {"name": "in_target", "size": 1, "direction": "input"}, + {"name": "out_ctrl", "size": 1, "direction": "output"}, + {"name": "out_target", "size": 1, "direction": "output"}, + ], + resources=[ + {"name": "clifford", "value": 1, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 0, "type": "additive"}, + ], + ) + + +def _two_connected_cnots() -> tuple[Bloq, RoutineV1, str]: + cnot = CNOT() + bb = BloqBuilder() + q0 = bb.add_register("q0", 1) + q1 = bb.add_register("q1", 1) + q0, q1 = bb.add(cnot, ctrl=q0, target=q1) + q0, q1 = bb.add(cnot, ctrl=q0, target=q1) + cbloq = bb.finalize(q0=q0, q1=q1) + + routine = RoutineV1( + name="CompositeBloq", + type="CompositeBloq", + children=[_cnot_routine("CNOT_0"), _cnot_routine("CNOT_1")], + ports=sorted( + [ + {"name": "in_q0", "size": 1, "direction": "input"}, + {"name": "in_q1", "size": 1, "direction": "input"}, + {"name": "out_q0", "size": 1, "direction": "output"}, + {"name": "out_q1", "size": 1, "direction": "output"}, + ], + key=lambda p: p["name"], + ), + connections=[ + {"source": "in_q0", "target": "CNOT_0.in_ctrl"}, + {"source": "in_q1", "target": "CNOT_0.in_target"}, + {"source": "CNOT_0.out_ctrl", "target": "CNOT_1.in_ctrl"}, + {"source": "CNOT_0.out_target", "target": "CNOT_1.in_target"}, + {"source": "CNOT_1.out_target", "target": "out_q1"}, + {"source": "CNOT_1.out_ctrl", "target": "out_q0"}, + ], + resources=[ + {"name": "clifford", "value": 2, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 0, "type": "additive"}, + ], + ) + + return cbloq, routine, "two connected CNOTs" + + +def _two_cross_connected_cnots() -> tuple[Bloq, RoutineV1, str]: + cnot = CNOT() + bb = BloqBuilder() + q0 = bb.add_register("q0", 1) + q1 = bb.add_register("q1", 1) + q0, q1 = bb.add(cnot, ctrl=q0, target=q1) + q0, q1 = bb.add(cnot, ctrl=q1, target=q0) + cbloq = bb.finalize(q0=q0, q1=q1) + + routine = RoutineV1( + name="CompositeBloq", + type="CompositeBloq", + children=[_cnot_routine("CNOT_0"), _cnot_routine("CNOT_1")], + ports=[ + {"name": "in_q0", "size": 1, "direction": "input"}, + {"name": "in_q1", "size": 1, "direction": "input"}, + {"name": "out_q0", "size": 1, "direction": "output"}, + {"name": "out_q1", "size": 1, "direction": "output"}, + ], + connections=[ + {"source": "in_q0", "target": "CNOT_0.in_ctrl"}, + {"source": "in_q1", "target": "CNOT_0.in_target"}, + {"source": "CNOT_0.out_ctrl", "target": "CNOT_1.in_target"}, + {"source": "CNOT_0.out_target", "target": "CNOT_1.in_ctrl"}, + {"source": "CNOT_1.out_target", "target": "out_q1"}, + {"source": "CNOT_1.out_ctrl", "target": "out_q0"}, + ], + resources=[ + {"name": "clifford", "value": 2, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 0, "type": "additive"}, + ], + ) + + return cbloq, routine, "two cross connected CNOTs" + + +def _less_than_equal() -> tuple[Bloq, RoutineV1, str]: + a = 10 + b = 15 + bloq = LessThanEqual(a, b) + routine = RoutineV1( + name="LessThanEqual", + type="LessThanEqual", + ports=[ + {"name": "in_target", "direction": "input", "size": 1}, + {"name": "in_x", "direction": "input", "size": a}, + {"name": "in_y", "direction": "input", "size": b}, + {"name": "out_target", "direction": "output", "size": 1}, + {"name": "out_x", "direction": "output", "size": a}, + {"name": "out_y", "direction": "output", "size": b}, + ], + resources=[ + {"name": "clifford", "type": "additive", "value": 529}, + {"name": "rotations", "type": "additive", "value": 0}, + {"name": "t", "type": "additive", "value": 96}, + ], + ) + + return bloq, routine, "less than equal (numeric)" + + +def _less_than_equal_symbolic() -> tuple[Bloq, RoutineV1, str]: + a, b = sympy.symbols("a b") + bloq = LessThanEqual(a, b) + routine = RoutineV1( + name="LessThanEqual", + type="LessThanEqual", + ports=[ + {"name": "in_target", "direction": "input", "size": 1}, + {"name": "in_x", "direction": "input", "size": "a"}, + {"name": "in_y", "direction": "input", "size": "b"}, + {"name": "out_target", "direction": "output", "size": 1}, + {"name": "out_x", "direction": "output", "size": "a"}, + {"name": "out_y", "direction": "output", "size": "b"}, + ], + resources=[ + {"name": "clifford", "type": "additive", "value": str(bloq.t_complexity().clifford)}, + {"name": "rotations", "type": "additive", "value": str(bloq.t_complexity().rotations)}, + {"name": "t", "type": "additive", "value": str(bloq.t_complexity().t)}, + ], + input_params=["a", "b"], + ) + return bloq, routine, "less than equal (symbolic)" + + +def _qrom_symbolic() -> tuple[Bloq, RoutineV1, str]: + N, M, b1, b2, c = sympy.symbols("N M b1 b2 c") + bloq = QROM.build_from_bitsize((N, M), (b1, b2), num_controls=c) + routine = RoutineV1( + name="QROM", + type="QROM", + ports=[ + {"name": "in_control", "direction": "input", "size": "c"}, + {"name": "in_selection0", "direction": "input", "size": "in_selection0_size"}, + {"name": "in_selection1", "direction": "input", "size": "in_selection1_size"}, + {"name": "in_target0_", "direction": "input", "size": "b1"}, + {"name": "in_target1_", "direction": "input", "size": "b2"}, + {"name": "out_control", "direction": "output", "size": "c"}, + {"name": "out_selection0", "direction": "output", "size": "out_selection0_size"}, + {"name": "out_selection1", "direction": "output", "size": "out_selection1_size"}, + {"name": "out_target0_", "direction": "output", "size": "b1"}, + {"name": "out_target1_", "direction": "output", "size": "b2"}, + ], + resources=[ + {"name": "clifford", "type": "additive", "value": str(bloq.t_complexity().clifford)}, + {"name": "rotations", "type": "additive", "value": str(bloq.t_complexity().rotations)}, + {"name": "t", "type": "additive", "value": str(bloq.t_complexity().t)}, + ], + input_params=["M", "N", "b1", "b2", "c"], + local_variables={ + 'in_selection0_size': 'ceiling(log2(N - 1))', + 'out_selection0_size': 'ceiling(log2(N - 1))', + 'in_selection1_size': 'ceiling(log2(M - 1))', + 'out_selection1_size': 'ceiling(log2(M - 1))', + }, + ) + return bloq, routine, "qrom (symbolic)" + + +def _undecomposed_alias_sampling() -> tuple[Bloq, RoutineV1, str]: + bloq = StatePreparationAliasSampling.from_lcu_probs([0.25, 0.5, 0.25], probability_epsilon=0.05) + + routine = RoutineV1( + name="StatePreparationAliasSampling", + type="StatePreparationAliasSampling", + ports=[ + {"name": "in_selection", "size": 2, "direction": "input"}, + {"name": "in_sigma_mu", "size": 3, "direction": "input"}, + {"name": "in_alt", "size": 2, "direction": "input"}, + {"name": "in_keep", "size": 3, "direction": "input"}, + {"name": "in_less_than_equal", "size": 1, "direction": "input"}, + {"name": "out_selection", "size": 2, "direction": "output"}, + {"name": "out_sigma_mu", "size": 3, "direction": "output"}, + {"name": "out_alt", "size": 2, "direction": "output"}, + {"name": "out_keep", "size": 3, "direction": "output"}, + {"name": "out_less_than_equal", "size": 1, "direction": "output"}, + ], + resources=[ + {"name": "clifford", "value": 268, "type": "additive"}, + {"name": "rotations", "value": 2, "type": "additive"}, + {"name": "t", "value": 58, "type": "additive"}, + ], + ) + + return bloq, routine, "alias sampling (not decomposed)" + + +def _decomposed_alias_sampling() -> tuple[Bloq, RoutineV1, str]: + bloq = StatePreparationAliasSampling.from_lcu_probs( + [0.25, 0.5, 0.25], probability_epsilon=0.05 + ).decompose_bloq() + + routine = RoutineV1( + name="CompositeBloq", + type="CompositeBloq", + ports=[ + {"name": "in_selection", "size": 2, "direction": "input"}, + {"name": "in_sigma_mu", "size": 3, "direction": "input"}, + {"name": "in_alt", "size": 2, "direction": "input"}, + {"name": "in_keep", "size": 3, "direction": "input"}, + {"name": "in_less_than_equal", "size": 1, "direction": "input"}, + {"name": "out_selection", "size": 2, "direction": "output"}, + {"name": "out_sigma_mu", "size": 3, "direction": "output"}, + {"name": "out_alt", "size": 2, "direction": "output"}, + {"name": "out_keep", "size": 3, "direction": "output"}, + {"name": "out_less_than_equal", "size": 1, "direction": "output"}, + ], + children=[ + RoutineV1( + name="Split_1", + type="Split", + ports=[ + {"name": "in_reg", "direction": "input", "size": 3}, + {"name": "out_reg_0", "direction": "output", "size": 1}, + {"name": "out_reg_1", "direction": "output", "size": 1}, + {"name": "out_reg_2", "direction": "output", "size": 1}, + ], + resources=[ + {"name": "clifford", "value": 0, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 0, "type": "additive"}, + ], + ), + RoutineV1( + name="Hadamard_2", + type="Hadamard", + ports=[ + {"name": "in_q", "direction": "input", "size": 1}, + {"name": "out_q", "direction": "output", "size": 1}, + ], + resources=[ + {"name": "clifford", "value": 1, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 0, "type": "additive"}, + ], + ), + RoutineV1( + name="Hadamard_3", + type="Hadamard", + ports=[ + {"name": "in_q", "direction": "input", "size": 1}, + {"name": "out_q", "direction": "output", "size": 1}, + ], + resources=[ + {"name": "clifford", "value": 1, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 0, "type": "additive"}, + ], + ), + RoutineV1( + name="Hadamard_4", + type="Hadamard", + ports=[ + {"name": "in_q", "direction": "input", "size": 1}, + {"name": "out_q", "direction": "output", "size": 1}, + ], + resources=[ + {"name": "clifford", "value": 1, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 0, "type": "additive"}, + ], + ), + RoutineV1( + name="CSwap_8", + type="CSwap", + ports=[ + {"name": "in_ctrl", "direction": "input", "size": 1}, + {"name": "out_ctrl", "direction": "output", "size": 1}, + {"name": "in_x", "direction": "input", "size": 2}, + {"name": "out_x", "direction": "output", "size": 2}, + {"name": "in_y", "direction": "input", "size": 2}, + {"name": "out_y", "direction": "output", "size": 2}, + ], + resources=[ + {"name": "clifford", "value": 20, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 14, "type": "additive"}, + ], + ), + RoutineV1( + name="Join_6", + type="Join", + ports=[ + {"name": "out_reg", "direction": "output", "size": 3}, + {"name": "in_reg_0", "direction": "input", "size": 1}, + {"name": "in_reg_1", "direction": "input", "size": 1}, + {"name": "in_reg_2", "direction": "input", "size": 1}, + ], + resources=[ + {"name": "clifford", "value": 0, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 0, "type": "additive"}, + ], + ), + RoutineV1( + name="LessThanEqual_7", + type="LessThanEqual", + ports=[ + {"name": "in_x", "direction": "input", "size": 3}, + {"name": "out_x", "direction": "output", "size": 3}, + {"name": "in_y", "direction": "input", "size": 3}, + {"name": "out_y", "direction": "output", "size": 3}, + {"name": "in_target", "direction": "input", "size": 1}, + {"name": "out_target", "direction": "output", "size": 1}, + ], + resources=[ + {"name": "clifford", "value": 117, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 20, "type": "additive"}, + ], + ), + RoutineV1( + name="PrepareUniformSuperposition_0", + type="PrepareUniformSuperposition", + ports=[ + {"name": "in_target", "direction": "input", "size": 2}, + {"name": "out_target", "direction": "output", "size": 2}, + ], + resources=[ + {"name": "clifford", "value": 103, "type": "additive"}, + {"name": "rotations", "value": 2, "type": "additive"}, + {"name": "t", "value": 20, "type": "additive"}, + ], + ), + RoutineV1( + name="QROM_5", + type="QROM", + ports=[ + {"name": "in_selection", "direction": "input", "size": 2}, + {"name": "out_selection", "direction": "output", "size": 2}, + {"name": "in_target0_", "direction": "input", "size": 2}, + {"name": "out_target0_", "direction": "output", "size": 2}, + {"name": "in_target1_", "direction": "input", "size": 3}, + {"name": "out_target1_", "direction": "output", "size": 3}, + ], + resources=[ + {"name": "clifford", "value": 25, "type": "additive"}, + {"name": "rotations", "value": 0, "type": "additive"}, + {"name": "t", "value": 4, "type": "additive"}, + ], + ), + ], + connections=[ + {"source": in_, "target": out_} + for in_, out_ in [ + ("CSwap_8.out_ctrl", "out_less_than_equal"), + ("CSwap_8.out_x", "out_alt"), + ("CSwap_8.out_y", "out_selection"), + ("Hadamard_2.out_q", "Join_6.in_reg_0"), + ("Hadamard_3.out_q", "Join_6.in_reg_1"), + ("Hadamard_4.out_q", "Join_6.in_reg_2"), + ("Join_6.out_reg", "LessThanEqual_7.in_y"), + ("LessThanEqual_7.out_target", "CSwap_8.in_ctrl"), + ("LessThanEqual_7.out_x", "out_keep"), + ("LessThanEqual_7.out_y", "out_sigma_mu"), + ("PrepareUniformSuperposition_0.out_target", "QROM_5.in_selection"), + ("QROM_5.out_selection", "CSwap_8.in_y"), + ("QROM_5.out_target0_", "CSwap_8.in_x"), + ("QROM_5.out_target1_", "LessThanEqual_7.in_x"), + ("Split_1.out_reg_0", "Hadamard_2.in_q"), + ("Split_1.out_reg_1", "Hadamard_3.in_q"), + ("Split_1.out_reg_2", "Hadamard_4.in_q"), + ("in_alt", "QROM_5.in_target0_"), + ("in_keep", "QROM_5.in_target1_"), + ("in_less_than_equal", "LessThanEqual_7.in_target"), + ("in_selection", "PrepareUniformSuperposition_0.in_target"), + ("in_sigma_mu", "Split_1.in_reg"), + ] + ], + resources=[ + {"name": "clifford", "value": 268, "type": "additive"}, + {"name": "rotations", "value": 2, "type": "additive"}, + {"name": "t", "value": 58, "type": "additive"}, + ], + ) + + return bloq, routine, "alias sampling (decomposed)" + + +@pytest.mark.parametrize( + "qualtran_object, expected_routine", + [ + pytest.param(operation, bloq, id=case_id) + for operation, bloq, case_id in [ + _two_connected_cnots(), + _two_cross_connected_cnots(), + _less_than_equal(), + _less_than_equal_symbolic(), + _qrom_symbolic(), + _undecomposed_alias_sampling(), + _decomposed_alias_sampling(), + ] + ], +) +def test_importing_qualtran_object_gives_expected_routine_object(qualtran_object, expected_routine): + assert bloq_to_qref(qualtran_object).program == expected_routine From 88843b8ff81fbe676715ecf1272a49d03f9abf8d Mon Sep 17 00:00:00 2001 From: mstechly Date: Thu, 25 Jul 2024 19:06:58 +0200 Subject: [PATCH 03/12] remove outdated import --- qualtran/qref_interop/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qualtran/qref_interop/__init__.py b/qualtran/qref_interop/__init__.py index 4691d4b65..f2f82519b 100644 --- a/qualtran/qref_interop/__init__.py +++ b/qualtran/qref_interop/__init__.py @@ -1 +1 @@ -from ._bloq_to_qref import bloq_to_qref, bloq_to_qref_from_call_graph +from ._bloq_to_qref import bloq_to_qref From 41cc5230c3f74396d97dea54cb9d3993feb87ade Mon Sep 17 00:00:00 2001 From: mstechly Date: Thu, 25 Jul 2024 21:40:54 +0200 Subject: [PATCH 04/12] Add notebook with Bartiq interop demo --- qualtran/qref_interop/bartiq_demo.ipynb | 2214 +++++++++++++++++++++++ 1 file changed, 2214 insertions(+) create mode 100644 qualtran/qref_interop/bartiq_demo.ipynb diff --git a/qualtran/qref_interop/bartiq_demo.ipynb b/qualtran/qref_interop/bartiq_demo.ipynb new file mode 100644 index 000000000..b8cfdaa15 --- /dev/null +++ b/qualtran/qref_interop/bartiq_demo.ipynb @@ -0,0 +1,2214 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6f3d7cc7-39a1-443a-84fb-8810097b0637", + "metadata": {}, + "source": [ + "# Qualtran + QREF & Bartiq" + ] + }, + { + "cell_type": "markdown", + "id": "9de43b9f-5b74-4d0a-92d8-b27e9c3f5e15", + "metadata": {}, + "source": [ + "This notebook shows how to convert Bloqs to [QREF](https://github.com/PsiQ/qref) and use them with [Bartiq](https://github.com/PsiQ/bartiq) library for symbolic compilation.\n", + "\n", + "This is not meant to be introduction to these packages, we assume that the reader has a basic understanding of what these packages allow them to do. If not, please refer to their documentation." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "bfbe10db-d89d-4c23-a862-c8473fe1bdd3", + "metadata": {}, + "outputs": [], + "source": [ + "from qualtran.bloqs.data_loading.qrom import QROM\n", + "from qualtran.bloqs.state_preparation import PrepareUniformSuperposition\n", + "from qualtran.drawing import show_call_graph\n", + "\n", + "import yaml\n", + "import sympy" + ] + }, + { + "cell_type": "markdown", + "id": "0d62ccdd-3336-4971-9a68-d67dc0e060f8", + "metadata": {}, + "source": [ + "## Basics\n", + "\n", + "QREF is a format for serializing quantum algorithms for the purpose of performing resource estimations.\n", + "Bartiq is a library for obtaining symbolic expressions for QREs. \n", + "\n", + "To showcase how using QREF and Bartiq with Qualtran could be useful, we'll analyze Alias Sampling – a state preparation method described in [Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity](https://arxiv.org/abs/1805.03662).\n", + "\n", + "Let's start from the basics – converting Bloq to QREF and compiling costs using Bartiq." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cfeb60ce-81af-494c-8e6c-9033642048f8", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "my_graph\n", + "\n", + "\n", + "\n", + "selection_G45\n", + "selection\n", + "\n", + "\n", + "\n", + "PrepareUniformSuperposition\n", + "\n", + "PrepareUniformSuperposition\n", + "\n", + "target\n", + "\n", + "\n", + "\n", + "selection_G45:e->PrepareUniformSuperposition:w\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "sigma_mu\n", + "sigma_mu\n", + "\n", + "\n", + "\n", + "Split\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "sigma_mu:e->Split:w\n", + "\n", + "\n", + "21\n", + "\n", + "\n", + "\n", + "alt\n", + "alt\n", + "\n", + "\n", + "\n", + "QROM\n", + "\n", + "QROM\n", + "\n", + "selection\n", + "\n", + "target0_\n", + "\n", + "target1_\n", + "\n", + "\n", + "\n", + "alt:e->QROM:w\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "keep\n", + "keep\n", + "\n", + "\n", + "\n", + "keep:e->QROM:w\n", + "\n", + "\n", + "21\n", + "\n", + "\n", + "\n", + "less_than_equal_G112\n", + "less_than_equal\n", + "\n", + "\n", + "\n", + "LessThanEqual\n", + "\n", + "LessThanEqual\n", + "\n", + "x\n", + "\n", + "y\n", + "\n", + "target\n", + "\n", + "\n", + "\n", + "less_than_equal_G112:e->LessThanEqual:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Join\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "Hadamard:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G0\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Hadamard_G0:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G2\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Hadamard_G2:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G4\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Hadamard_G4:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G6\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Hadamard_G6:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G8\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Hadamard_G8:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "CSwap\n", + "\n", + "CSwap\n", + "\n", + "ctrl\n", + "\n", + "x\n", + "\n", + "y\n", + "\n", + "\n", + "\n", + "selection_G90\n", + "selection\n", + "\n", + "\n", + "\n", + "CSwap:e->selection_G90:w\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "alt_G101\n", + "alt\n", + "\n", + "\n", + "\n", + "CSwap:e->alt_G101:w\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "less_than_equal\n", + "less_than_equal\n", + "\n", + "\n", + "\n", + "CSwap:e->less_than_equal:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G0:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G2:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G4:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G6:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G8:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G10\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G10:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G12\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G12:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G14\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G14:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G16\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G16:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G18\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G18:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G20\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G20:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G22\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G22:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G24\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G24:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G30\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G30:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G32\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G32:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G34\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G34:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G36\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G36:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G38\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G38:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G40\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G40:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G42\n", + "\n", + "H\n", + "\n", + "q\n", + "\n", + "\n", + "\n", + "Split:e->Hadamard_G42:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G10:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G12:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G14:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "PrepareUniformSuperposition:e->QROM:w\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "QROM:e->CSwap:w\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "QROM:e->CSwap:w\n", + "\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "QROM:e->LessThanEqual:w\n", + "\n", + "\n", + "21\n", + "\n", + "\n", + "\n", + "Hadamard_G16:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G18:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G20:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G22:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G24:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "LessThanEqual:e->CSwap:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "sigma_mu_G99\n", + "sigma_mu\n", + "\n", + "\n", + "\n", + "LessThanEqual:e->sigma_mu_G99:w\n", + "\n", + "\n", + "21\n", + "\n", + "\n", + "\n", + "keep_G72\n", + "keep\n", + "\n", + "\n", + "\n", + "LessThanEqual:e->keep_G72:w\n", + "\n", + "\n", + "21\n", + "\n", + "\n", + "\n", + "Join:e->LessThanEqual:w\n", + "\n", + "\n", + "21\n", + "\n", + "\n", + "\n", + "Hadamard_G30:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G32:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G34:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G36:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G38:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G40:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "Hadamard_G42:e->Join:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qualtran.bloqs.state_preparation import StatePreparationAliasSampling\n", + "from qualtran.drawing.graphviz import PrettyGraphDrawer\n", + "\n", + "probs_list = list(range(24))\n", + "bloq = StatePreparationAliasSampling.from_probabilities(probs_list).decompose_bloq()\n", + "PrettyGraphDrawer(bloq).get_svg()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f3726d8c-ce01-4b6a-b5b6-72654b58f09b", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "cluster_.CompositeBloq\n", + "\n", + "CompositeBloq\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_alt"\n", + "\n", + "in_alt\n", + "\n", + "\n", + "\n", + "".CompositeBloq.QROM_23"\n", + "\n", + "in_selection\n", + "\n", + "in_target0_\n", + "\n", + "in_target1_\n", + "\n", + "QROM_23\n", + "\n", + "out_selection\n", + "\n", + "out_target0_\n", + "\n", + "out_target1_\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_alt"->".CompositeBloq.QROM_23":in_target0_\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_keep"\n", + "\n", + "in_keep\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_keep"->".CompositeBloq.QROM_23":in_target1_\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_less_than_equal"\n", + "\n", + "in_less_than_equal\n", + "\n", + "\n", + "\n", + "".CompositeBloq.LessThanEqual_25"\n", + "\n", + "in_target\n", + "\n", + "in_x\n", + "\n", + "in_y\n", + "\n", + "LessThanEqual_25\n", + "\n", + "out_target\n", + "\n", + "out_x\n", + "\n", + "out_y\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_less_than_equal"->".CompositeBloq.LessThanEqual_25":in_target\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_selection"\n", + "\n", + "in_selection\n", + "\n", + "\n", + "\n", + "".CompositeBloq.PrepareUniformSuperposition_0"\n", + "\n", + "in_target\n", + "\n", + "PrepareUniformSuperposition_0\n", + "\n", + "out_target\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_selection"->".CompositeBloq.PrepareUniformSuperposition_0":in_target\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_sigma_mu"\n", + "\n", + "in_sigma_mu\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1"\n", + "\n", + "in_reg\n", + "\n", + "Split_1\n", + "\n", + "out_reg_0\n", + "\n", + "out_reg_1\n", + "\n", + "out_reg_10\n", + "\n", + "out_reg_11\n", + "\n", + "out_reg_12\n", + "\n", + "out_reg_13\n", + "\n", + "out_reg_14\n", + "\n", + "out_reg_15\n", + "\n", + "out_reg_16\n", + "\n", + "out_reg_17\n", + "\n", + "out_reg_18\n", + "\n", + "out_reg_19\n", + "\n", + "out_reg_2\n", + "\n", + "out_reg_20\n", + "\n", + "out_reg_3\n", + "\n", + "out_reg_4\n", + "\n", + "out_reg_5\n", + "\n", + "out_reg_6\n", + "\n", + "out_reg_7\n", + "\n", + "out_reg_8\n", + "\n", + "out_reg_9\n", + "\n", + "\n", + "\n", + "".CompositeBloq.in_sigma_mu"->".CompositeBloq.Split_1":in_reg\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.out_alt"\n", + "\n", + "out_alt\n", + "\n", + "\n", + "\n", + "".CompositeBloq.out_keep"\n", + "\n", + "out_keep\n", + "\n", + "\n", + "\n", + "".CompositeBloq.out_less_than_equal"\n", + "\n", + "out_less_than_equal\n", + "\n", + "\n", + "\n", + "".CompositeBloq.out_selection"\n", + "\n", + "out_selection\n", + "\n", + "\n", + "\n", + "".CompositeBloq.out_sigma_mu"\n", + "\n", + "out_sigma_mu\n", + "\n", + "\n", + "\n", + "".CompositeBloq.CSwap_26"\n", + "\n", + "in_ctrl\n", + "\n", + "in_x\n", + "\n", + "in_y\n", + "\n", + "CSwap_26\n", + "\n", + "out_ctrl\n", + "\n", + "out_x\n", + "\n", + "out_y\n", + "\n", + "\n", + "\n", + "".CompositeBloq.CSwap_26":out_x->".CompositeBloq.out_alt"\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.CSwap_26":out_ctrl->".CompositeBloq.out_less_than_equal"\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.CSwap_26":out_y->".CompositeBloq.out_selection"\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_10"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_10\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Join_24"\n", + "\n", + "in_reg_0\n", + "\n", + "in_reg_1\n", + "\n", + "in_reg_10\n", + "\n", + "in_reg_11\n", + "\n", + "in_reg_12\n", + "\n", + "in_reg_13\n", + "\n", + "in_reg_14\n", + "\n", + "in_reg_15\n", + "\n", + "in_reg_16\n", + "\n", + "in_reg_17\n", + "\n", + "in_reg_18\n", + "\n", + "in_reg_19\n", + "\n", + "in_reg_2\n", + "\n", + "in_reg_20\n", + "\n", + "in_reg_3\n", + "\n", + "in_reg_4\n", + "\n", + "in_reg_5\n", + "\n", + "in_reg_6\n", + "\n", + "in_reg_7\n", + "\n", + "in_reg_8\n", + "\n", + "in_reg_9\n", + "\n", + "Join_24\n", + "\n", + "out_reg\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_10":out_q->".CompositeBloq.Join_24":in_reg_8\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_11"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_11\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_11":out_q->".CompositeBloq.Join_24":in_reg_9\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_12"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_12\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_12":out_q->".CompositeBloq.Join_24":in_reg_10\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_13"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_13\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_13":out_q->".CompositeBloq.Join_24":in_reg_11\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_14"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_14\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_14":out_q->".CompositeBloq.Join_24":in_reg_12\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_15"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_15\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_15":out_q->".CompositeBloq.Join_24":in_reg_13\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_16"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_16\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_16":out_q->".CompositeBloq.Join_24":in_reg_14\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_17"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_17\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_17":out_q->".CompositeBloq.Join_24":in_reg_15\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_18"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_18\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_18":out_q->".CompositeBloq.Join_24":in_reg_16\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_19"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_19\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_19":out_q->".CompositeBloq.Join_24":in_reg_17\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_2"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_2\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_2":out_q->".CompositeBloq.Join_24":in_reg_0\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_20"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_20\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_20":out_q->".CompositeBloq.Join_24":in_reg_18\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_21"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_21\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_21":out_q->".CompositeBloq.Join_24":in_reg_19\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_22"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_22\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_22":out_q->".CompositeBloq.Join_24":in_reg_20\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_3"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_3\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_3":out_q->".CompositeBloq.Join_24":in_reg_1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_4"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_4\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_4":out_q->".CompositeBloq.Join_24":in_reg_2\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_5"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_5\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_5":out_q->".CompositeBloq.Join_24":in_reg_3\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_6"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_6\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_6":out_q->".CompositeBloq.Join_24":in_reg_4\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_7"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_7\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_7":out_q->".CompositeBloq.Join_24":in_reg_5\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_8"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_8\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_8":out_q->".CompositeBloq.Join_24":in_reg_6\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_9"\n", + "\n", + "in_q\n", + "\n", + "Hadamard_9\n", + "\n", + "out_q\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Hadamard_9":out_q->".CompositeBloq.Join_24":in_reg_7\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Join_24":out_reg->".CompositeBloq.LessThanEqual_25":in_y\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.LessThanEqual_25":out_x->".CompositeBloq.out_keep"\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.LessThanEqual_25":out_y->".CompositeBloq.out_sigma_mu"\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.LessThanEqual_25":out_target->".CompositeBloq.CSwap_26":in_ctrl\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.PrepareUniformSuperposition_0":out_target->".CompositeBloq.QROM_23":in_selection\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.QROM_23":out_selection->".CompositeBloq.CSwap_26":in_y\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.QROM_23":out_target0_->".CompositeBloq.CSwap_26":in_x\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.QROM_23":out_target1_->".CompositeBloq.LessThanEqual_25":in_x\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_8->".CompositeBloq.Hadamard_10":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_9->".CompositeBloq.Hadamard_11":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_10->".CompositeBloq.Hadamard_12":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_11->".CompositeBloq.Hadamard_13":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_12->".CompositeBloq.Hadamard_14":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_13->".CompositeBloq.Hadamard_15":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_14->".CompositeBloq.Hadamard_16":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_15->".CompositeBloq.Hadamard_17":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_16->".CompositeBloq.Hadamard_18":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_17->".CompositeBloq.Hadamard_19":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_0->".CompositeBloq.Hadamard_2":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_18->".CompositeBloq.Hadamard_20":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_19->".CompositeBloq.Hadamard_21":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_20->".CompositeBloq.Hadamard_22":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_1->".CompositeBloq.Hadamard_3":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_2->".CompositeBloq.Hadamard_4":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_3->".CompositeBloq.Hadamard_5":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_4->".CompositeBloq.Hadamard_6":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_5->".CompositeBloq.Hadamard_7":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_6->".CompositeBloq.Hadamard_8":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "".CompositeBloq.Split_1":out_reg_7->".CompositeBloq.Hadamard_9":in_q\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qualtran.qref_interop import bloq_to_qref\n", + "from qref.experimental.rendering import to_graphviz\n", + "\n", + "# We can easily convert it to QREF representation with the following code:\n", + "qref_definition = bloq_to_qref(bloq)\n", + "to_graphviz(qref_definition)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "755d7031-617a-4908-9ee1-45a42c422fbd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TComplexity(t=307, clifford=1770, rotations=2)\n", + "[ResourceV1(name='clifford', type='additive', value=1770),\n", + " ResourceV1(name='rotations', type='additive', value=2),\n", + " ResourceV1(name='t', type='additive', value=307)]\n" + ] + } + ], + "source": [ + "from pprint import pprint\n", + "# We can check that the resources for both representations are the same:\n", + "pprint(bloq.t_complexity())\n", + "pprint(qref_definition.program.resources)" + ] + }, + { + "cell_type": "markdown", + "id": "5133d33a-017a-488e-a8f9-2c37a058062d", + "metadata": {}, + "source": [ + "These are only the \"top-level\" resources, we can also see what are the resources of the building blocks, for example Uniform State Preparation:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "bafd2405-3ac0-43ff-b9b4-7978ffd49cef", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TComplexity(t=20, clifford=106, rotations=2)\n", + "[ResourceV1(name='clifford', type='additive', value=106),\n", + " ResourceV1(name='rotations', type='additive', value=2),\n", + " ResourceV1(name='t', type='additive', value=20)]\n" + ] + } + ], + "source": [ + "USP_bloq = [bloq_inst.bloq for bloq_inst in bloq.bloq_instances if bloq_inst.bloq.pretty_name() == \"PrepareUniformSuperposition\"][0]\n", + "pprint(USP_bloq.t_complexity())\n", + "pprint(qref_definition.program.children.by_name[\"PrepareUniformSuperposition_0\"].resources)" + ] + }, + { + "cell_type": "markdown", + "id": "4953f807-5ce0-42c5-9bf4-6773c5f45e87", + "metadata": {}, + "source": [ + "Now we can take the QREF definition and pass it to Bartiq.\n", + "However, it would be trivial as all the resources are already there. For this reason, before passing it to Bartiq, we'll remove the top level resources in QREF." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "56beb66e-0989-4cf6-920b-bbc51cae559d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'clifford': ,\n", + " 'rotations': ,\n", + " 't': }\n" + ] + } + ], + "source": [ + "from bartiq.integrations.qref import qref_to_bartiq\n", + "from bartiq import compile_routine\n", + "\n", + "qref_definition.program.resources = [] \n", + "bartiq_routine = qref_to_bartiq(qref_definition)\n", + "compiled_routine = compile_routine(bartiq_routine)\n", + "pprint(compiled_routine.resources)" + ] + }, + { + "cell_type": "markdown", + "id": "2db6c501-5756-4356-ae6f-a6f412155e68", + "metadata": {}, + "source": [ + "As we can see, Bartiq correctly reconstructed the costs from the subroutines." + ] + }, + { + "cell_type": "markdown", + "id": "27483d83-d008-499c-9322-c2953f6db573", + "metadata": {}, + "source": [ + "## Writing custom USP implementation\n", + "\n", + "So far so good, but we used Bartiq to derive the same information we already had in Qualtran.\n", + "\n", + "There are two limitations of Qualtran implementation, with which Bartiq can help us, let's see what these are.\n", + "\n", + "### Numeric implementation\n", + "\n", + "The example above is purely numeric. We can get the symbolic cost of the whole `StatePreparationAliasSampling` (see snippet below) but we can't decompose it using `decompose_bloq()`.\n", + "\n", + "```\n", + "import sympy\n", + "N, M, eps = sympy.symbols(\"N M eps\")\n", + "bloq = StatePreparationAliasSampling.from_n_coeff(n_coeff=N, sum_of_unnormalized_probabilites=M, precision=eps)\n", + "pprint(bloq.t_complexity())\n", + "bloq.decompose_bloq()\n", + "```\n", + "\n", + "### Resources tied to a specific implementation\n", + "\n", + "At the time of writing, if we look at the source code of [PrepareUniformSuperposition](https://github.com/quantumlib/Qualtran/blob/c0a3a94d712f4eebb1cad119fc507a6cd9a7d8e7/qualtran/bloqs/state_preparation/prepare_uniform_superposition.py#L44), we'll see the following information in the docstring:\n", + "\n", + "> Performs a single round of amplitude amplification and prepares a uniform superposition over the first $n$ basis states $|0>, |1>, ..., |n - 1>$. The expected T-complexity should be $10 * log(L) + 2 * K$ T-gates and $2$ single qubit rotation gates, where $n = L * 2^K$.\n", + ">\n", + "> However, the current T-complexity is $12 * log(L)$ T-gates and $2 + 2 * (K + log(L))$ rotations\n", + "because of two open issues:\n", + "> \n", + "> - https://github.com/quantumlib/Qualtran/issues/233 and\n", + "> - https://github.com/quantumlib/Qualtran/issues/235\n", + "\n", + "We see that in Qualtran we're sometimes tied with the resources to a specific implementation, even if we know it's incorrect.\n", + "\n", + "\n", + "\n", + "Below we'll see how we can quickly create an alternative implementation of USP with QREF" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "b6491b25-8364-4542-ba4e-3de3b990ad10", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "TComplexity(t=12*ceiling(log2(N - 1)) - 4, clifford=52*ceiling(log2(N - 1)) - 9, rotations=2)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qualtran.bloqs.state_preparation import PrepareUniformSuperposition\n", + "N = sympy.symbols(\"N\")\n", + "USP_bloq = PrepareUniformSuperposition(N)\n", + "# We see that contrary to the docstring, number of rotations is already correct\n", + "USP_bloq.t_complexity()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "1c730d6c-1ed3-4da5-8988-3d8bac2dcbd3", + "metadata": {}, + "outputs": [], + "source": [ + "# Now we create two QREF definitions based on the PrepareUniformSuperposition bloq\n", + "usp_1_qref = bloq_to_qref(USP_bloq) # this will be left unchanged\n", + "usp_2_qref = bloq_to_qref(USP_bloq) # this will be updated" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d5c82602-5db5-4071-9b52-062454ce154a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[ResourceV1(name='clifford', type='additive', value='52*ceiling(log2(N - 1)) - 9'),\n", + " ResourceV1(name='rotations', type='additive', value='2'),\n", + " ResourceV1(name='t', type='additive', value='12*ceiling(log2(N - 1)) - 4')]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# We check if the expressions are \n", + "usp_1_qref.program.resources" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "97d88fce-c538-4282-a665-b2c721716d84", + "metadata": {}, + "outputs": [], + "source": [ + "# We'll implement the new version of USP straight in QREF, it's based on `usp_1_qref.model_dump()`\n", + "# Note that we omit Clifford gates here, as the expression for them is not mentioned in the docstring.\n", + "from qref import SchemaV1\n", + "import math\n", + "port_size = math.ceil(math.log2(len(probs_list)))\n", + "\n", + "usp_2_qref = SchemaV1(\n", + " program={\n", + " \"name\": \"PrepareUniformSuperposition\",\n", + " \"input_params\": [\"N\"],\n", + " \"ports\": [\n", + " {\"direction\": \"input\", \"name\": \"in_target\", \"size\": port_size},\n", + " {\"direction\": \"output\", \"name\": \"out_target\", \"size\": port_size},\n", + " ],\n", + " \"resources\": [\n", + " {\"name\": \"t\", \"type\": \"additive\", \"value\": \"10*ceiling(log2(L)) + 2*k\"},\n", + " {\"name\": \"rotations\", \"type\": \"additive\", \"value\": \"2\"},\n", + " ],\n", + " \"local_variables\": {\"k\": \"multiplicity(2, N)\", \"L\": \"N/2**k\"},\n", + " },\n", + " version=\"v1\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "814c2e11-d430-411e-b015-85e803528b3a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "usp_1_bartiq = qref_to_bartiq(usp_1_qref)\n", + "compile_routine(usp_1_bartiq).resources[\"t\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1183503a-0aa5-42e9-8c10-1218b9a2dbf7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "usp_2_bartiq = qref_to_bartiq(usp_2_qref)\n", + "compile_routine(usp_2_bartiq).resources[\"t\"]" + ] + }, + { + "cell_type": "markdown", + "id": "07d684ae-fa77-4d48-8850-4d394b2ec4e3", + "metadata": {}, + "source": [ + "## Updating Alias Sampling" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "d2bddbd7-fd86-400e-8cfe-b593995f91f3", + "metadata": {}, + "outputs": [], + "source": [ + "bloq = StatePreparationAliasSampling.from_probabilities(probs_list).decompose_bloq()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "b1a54903-29a3-4017-84cf-e87d51d53a4a", + "metadata": {}, + "outputs": [], + "source": [ + "# We export our Alias Sampling bloq to QREF and remove top-level resources so we can re-compute them later.\n", + "qref_as_1 = bloq_to_qref(bloq)\n", + "qref_as_2 = bloq_to_qref(bloq)\n", + "qref_as_1.program.resources = []\n", + "qref_as_2.program.resources = []" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "f2305c8f-7bf0-44a2-8c2f-d6afd63111ea", + "metadata": {}, + "outputs": [], + "source": [ + "# Before we put the subroutine in the right place, we need to make sure it's named correctly, otherwise \n", + "# some of the connections will be invalid.\n", + "usp_2_qref.program.name = \"PrepareUniformSuperposition_0\"\n", + "qref_as_2.program.children.by_name[\"PrepareUniformSuperposition_0\"] = usp_2_qref.program" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "8fe913dc-a880-432f-bc37-d18316d6da92", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bartiq_as_1 = qref_to_bartiq(qref_as_1)\n", + "compile_routine(bartiq_as_1).resources[\"t\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "72f0b802-a3cd-4e43-86da-ad1bbe0fe39b", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/mstechly/Documents/code/2024-06-26-qualtran-conversion/bartiq/src/bartiq/compilation/_compile.py:117: UserWarning: Found the following issues with the provided routine after the compilation has finished: [\"Input param N found in subroutine: CompositeBloq.PrepareUniformSuperposition_0, which is not among top level params: {'PrepareUniformSuperposition_0.N'}.\"]\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bartiq_as_2 = qref_to_bartiq(qref_as_2)\n", + "compile_routine(bartiq_as_2).resources[\"t\"]" + ] + }, + { + "cell_type": "markdown", + "id": "44cc58e6-6155-4919-9156-556b5e42fdf4", + "metadata": {}, + "source": [ + "Since the top-level routine does not have knowledge about it's children parameter, the parameter `N` from USP routine got namespaced and we see: `PrepareUniformSuperposition_0.N` in the expression. To get rid of that, we'll make a tiny update:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "275437ee-aab0-4f38-93dc-603ba1a4a5f2", + "metadata": {}, + "outputs": [], + "source": [ + "from qref.schema_v1 import ParamLinkV1\n", + "qref_as_2.program.input_params = [\"N\"]\n", + "qref_as_2.program.linked_params = [{\"source\": \"N\", \"targets\": [\"PrepareUniformSuperposition_0.N\"]}]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "2d0cc292-9421-42ee-a4ef-f8753e308167", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bartiq_as_2 = qref_to_bartiq(qref_as_2)\n", + "compiled_as_2 = compile_routine(bartiq_as_2)\n", + "compiled_as_2.resources[\"t\"]" + ] + }, + { + "cell_type": "markdown", + "id": "e864d60d-66cc-4bc7-92dc-708c2a77b614", + "metadata": {}, + "source": [ + "In order to get the value of these resources for a specific value of `N`, we can use Bartiq's `evaluate` method:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "1ecc7d7a-22da-4072-bf96-1d6e26e01493", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from bartiq import evaluate\n", + "\n", + "N_value = len(probs_list)\n", + "\n", + "assignments = {f\"N={N_value}\"}\n", + "\n", + "evaluate(compiled_as_2, assignments).resources[\"t\"]" + ] + }, + { + "cell_type": "markdown", + "id": "0d866675-d219-4ff7-a5a8-d1c2419b7863", + "metadata": {}, + "source": [ + "# Custom functions" + ] + }, + { + "cell_type": "markdown", + "id": "765b39e3-2665-4e7d-ab90-0db7da3d9d96", + "metadata": {}, + "source": [ + "Another case where Bartiq can be useful is when the cost of a particular routine is given by a custom function.\n", + "Let's say that we have an idea for defining cost of USP by using a recursive function `foo` as defined below." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "5e6f5a6e-3b31-4bb0-ad9e-2cc45e2290ed", + "metadata": {}, + "outputs": [], + "source": [ + "def foo(n):\n", + " if n < 10:\n", + " return n\n", + " else:\n", + " return foo(n-3) " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "1bc1821a-0b41-4c4c-9cbf-24d71e0f18ec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'t': }" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import copy\n", + "usp_3_qref = copy.copy(usp_2_qref)\n", + "usp_3_qref.program.resources = [{\"name\": \"t\", \"type\": \"additive\", \"value\": \"2*foo(N)\"}]\n", + "\n", + "usp_3_bartiq = qref_to_bartiq(usp_3_qref)\n", + "compiled_usp_3 = compile_routine(usp_3_bartiq)\n", + "compiled_usp_3.resources" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "4cf814e0-d3e5-43f0-9197-373b897233a0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'t': }" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "assignments = {\"N=101\"}\n", + "functions_map = {\"foo\": foo}\n", + "evaluate(compiled_usp_3, assignments, functions_map=functions_map).resources" + ] + }, + { + "cell_type": "markdown", + "id": "51f03933-923d-4386-8dbc-f329ae22e2d2", + "metadata": {}, + "source": [ + "We see that in such case we can both use custom functions in the symbolic expressions for the costs, as well as evaluate them with specific numeric values." + ] + }, + { + "cell_type": "markdown", + "id": "c23692ca-2038-4db2-aeb2-4608940d1e31", + "metadata": {}, + "source": [ + "## Closing remarks" + ] + }, + { + "cell_type": "markdown", + "id": "4bd2b13a-2127-4797-866e-a9fe26bb0f7e", + "metadata": {}, + "source": [ + "Thank you for going through this notebook!\n", + "QREF and Bartiq are still in beta, and there's so much more we could do to make the integration with Qualtran better.\n", + "If you have specific usecase in mind or if you encounter any issues, please leave an issue in any of the involved projects and we'll love to help you make it work." + ] + } + ], + "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.10.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 1df9dbd0b8b86c798f7b2f633e0f0903e3a7d926 Mon Sep 17 00:00:00 2001 From: mstechly Date: Mon, 29 Jul 2024 22:06:09 +0200 Subject: [PATCH 05/12] minor refactor and fixes --- qualtran/qref_interop/_bloq_to_qref.py | 58 ++++++++----------- ..._bloq_to_qref.py => _bloq_to_qref_test.py} | 8 +-- 2 files changed, 28 insertions(+), 38 deletions(-) rename qualtran/qref_interop/{test_bloq_to_qref.py => _bloq_to_qref_test.py} (98%) diff --git a/qualtran/qref_interop/_bloq_to_qref.py b/qualtran/qref_interop/_bloq_to_qref.py index 5be37cb94..05a418bb4 100644 --- a/qualtran/qref_interop/_bloq_to_qref.py +++ b/qualtran/qref_interop/_bloq_to_qref.py @@ -1,7 +1,5 @@ -import networkx as nx - from functools import singledispatch -from typing import Any, Iterable, Optional, Union +from typing import Any, Iterable, Optional import sympy from qref.schema_v1 import PortV1, RoutineV1, SchemaV1 @@ -10,6 +8,7 @@ from qualtran import Connection as QualtranConnection from qualtran import Register, Side, Soquet from qualtran.cirq_interop import CirqGateAsBloq +from qualtran.symbolics import is_symbolic @singledispatch @@ -78,7 +77,7 @@ def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> d name += "_adjoint" except AttributeError: pass - input_params = _extract_input_params(bloq, ports, local_variables) + input_params = _extract_input_params(bloq, ports) - set(local_variables) attributes = { "name": name, @@ -161,7 +160,7 @@ def _bloq_instance_to_routine(instance: BloqInstance) -> RoutineV1: def _names_and_dir_from_register(reg: Register) -> Iterable[tuple[str, str]]: - """Yield names and directions of Bartiq Ports corresponding to QualtranRegister. + """Yield names and directions of Bartiq Ports corresponding to Qualtran Register. For LEFT/RIGHT registers we yield one pair of name and direction corresponding of resp. output and input port. For THRU registers we yield both such pairs, @@ -180,6 +179,12 @@ def _expand_name_if_needed(reg_name, shape) -> Iterable[str]: "reg", () -> "reg" "reg", (3,) -> "reg_0", "reg_1", "reg_2" """ + if len(shape) > 1: + raise NotImplementedError( + "Registers with two or more dimensional shape are not yet supported. " + f"The error was caused by register {reg_name}." + ) + return (reg_name,) if shape == () else (f"{reg_name}_{i}" for i in range(shape[0])) @@ -200,12 +205,6 @@ def _ports_from_register(reg: Register) -> Iterable[PortV1]: NotImplementedError: if `reg` is a compound register with more than one-dimension. Currently we don't support such scenario. """ - if len(reg.shape) > 1: - raise NotImplementedError( - "Registers with two or more dimensional shape are not yet supported. " - f"The error was caused by register {reg}." - ) - return sorted( [ # Observe two loops: @@ -269,43 +268,36 @@ def _import_resources(bloq: Bloq) -> list[dict[str, Any]]: resources = [] for name in resource_names: resources.append( - { - "name": name, - "value": _ensure_primitive_type(getattr(t_complexity, name)), - "type": "additive", - } + {"name": name, "value": is_symbolic(getattr(t_complexity, name)), "type": "additive"} ) return resources -def _ensure_primitive_type(value: Any) -> Union[int, float, str, None]: - """Ensure given value is of primitive type (e.g. is not a sympy expression).""" - return value if value is None or isinstance(value, (int, float, str)) else str(value) - - -def _extract_input_params(bloq: Bloq, ports: list[PortV1], local_variables) -> list[str]: +def _extract_input_params(bloq: Bloq, ports: list[PortV1]) -> list[str]: """Extracts input_params from bloq's t_complexity and port sizes.""" - params_from_t_complexity = _extract_input_params_from_t_complexity(bloq) - params_from_ports = _extract_input_params_from_ports(ports) - params = list(set(params_from_t_complexity + params_from_ports) - set(local_variables)) + params_from_t_complexity = _extract_symbols_from_t_complexity(bloq) + params_from_ports = _extract_symbols_from_port_sizes(ports) + params = list(set(params_from_t_complexity + params_from_ports)) return sorted(params) -def _extract_input_params_from_t_complexity(bloq: Bloq) -> list[str]: - input_params = set() +def _extract_symbols_from_t_complexity(bloq: Bloq) -> list[str]: + """Extracts symbols from t_complexity of a given bloq.""" + symbols = set() t_complexity = bloq.t_complexity() resource_names = ["t", "clifford", "rotations"] for name in resource_names: try: - input_params.update(getattr(t_complexity, name).free_symbols) + symbols.update(getattr(t_complexity, name).free_symbols) except AttributeError: pass - return [str(symbol) for symbol in input_params] + return [str(symbol) for symbol in symbols] -def _extract_input_params_from_ports(ports) -> list[str]: - input_params = set() +def _extract_symbols_from_port_sizes(ports: list[PortV1]) -> list[str]: + """Extracts symbols from the expressions for port sizes.""" + symbols = set() for port in ports: - input_params = input_params | sympy.sympify(port.size).free_symbols + symbols = symbols | sympy.sympify(port.size).free_symbols - return [str(param) for param in input_params] + return [str(symbol) for symbol in symbols] diff --git a/qualtran/qref_interop/test_bloq_to_qref.py b/qualtran/qref_interop/_bloq_to_qref_test.py similarity index 98% rename from qualtran/qref_interop/test_bloq_to_qref.py rename to qualtran/qref_interop/_bloq_to_qref_test.py index 110dc07cd..f2513c4a9 100644 --- a/qualtran/qref_interop/test_bloq_to_qref.py +++ b/qualtran/qref_interop/_bloq_to_qref_test.py @@ -1,5 +1,5 @@ from dev_tools.qualtran_dev_tools.bloq_finder import get_bloq_examples -from qualtran.qref_interop import bloq_to_qref, bloq_to_qref_from_call_graph +from qualtran.qref_interop import bloq_to_qref import pytest import sympy @@ -228,7 +228,7 @@ def _qrom_symbolic() -> tuple[Bloq, RoutineV1, str]: def _undecomposed_alias_sampling() -> tuple[Bloq, RoutineV1, str]: - bloq = StatePreparationAliasSampling.from_lcu_probs([0.25, 0.5, 0.25], probability_epsilon=0.05) + bloq = StatePreparationAliasSampling.from_probabilities([0.25, 0.5, 0.25]) routine = RoutineV1( name="StatePreparationAliasSampling", @@ -256,9 +256,7 @@ def _undecomposed_alias_sampling() -> tuple[Bloq, RoutineV1, str]: def _decomposed_alias_sampling() -> tuple[Bloq, RoutineV1, str]: - bloq = StatePreparationAliasSampling.from_lcu_probs( - [0.25, 0.5, 0.25], probability_epsilon=0.05 - ).decompose_bloq() + bloq = StatePreparationAliasSampling.from_probabilities([0.25, 0.5, 0.25]).decompose_bloq() routine = RoutineV1( name="CompositeBloq", From 4d688eb0e99f7d73c353341620138b40d9389253 Mon Sep 17 00:00:00 2001 From: mstechly Date: Tue, 30 Jul 2024 16:42:25 +0200 Subject: [PATCH 06/12] Fixes in QREF conversion --- qualtran/qref_interop/_bloq_to_qref.py | 30 ++- qualtran/qref_interop/_bloq_to_qref_test.py | 215 +------------------- 2 files changed, 30 insertions(+), 215 deletions(-) diff --git a/qualtran/qref_interop/_bloq_to_qref.py b/qualtran/qref_interop/_bloq_to_qref.py index 05a418bb4..07d6fe7f5 100644 --- a/qualtran/qref_interop/_bloq_to_qref.py +++ b/qualtran/qref_interop/_bloq_to_qref.py @@ -1,5 +1,5 @@ from functools import singledispatch -from typing import Any, Iterable, Optional +from typing import Any, Iterable, Optional, Union import sympy from qref.schema_v1 import PortV1, RoutineV1, SchemaV1 @@ -58,6 +58,9 @@ def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> d A dictionary that can be unpacked into arguments of RoutineV1 initializer. """ ports = [port for reg in bloq.signature for port in _ports_from_register(reg)] + + # Logic associated with local_variables is needed in order to get around a limitation of bartiq, + # which currently cannot handle input port sizes with non-trivial sizes. local_variables = {} for port in ports: if not _is_symbol_or_int(str(port.size)): @@ -77,7 +80,10 @@ def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> d name += "_adjoint" except AttributeError: pass - input_params = _extract_input_params(bloq, ports) - set(local_variables) + + input_params = sorted( + list(_extract_input_params(bloq, ports, local_variables) - set(local_variables)) + ) attributes = { "name": name, @@ -87,6 +93,10 @@ def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> d "input_params": input_params, } if len(local_variables) > 0: + print("\n") + print(local_variables) + print(_import_resources(bloq)) + print("\n") attributes["local_variables"] = local_variables return attributes @@ -261,6 +271,11 @@ def _import_connection(connection: QualtranConnection) -> dict[str, Any]: } +def _ensure_primitive_type(value: Any) -> Union[int, float, str, None]: + """Ensure given value is of primitive type (e.g. is not a sympy expression).""" + return value if value is None or not is_symbolic(value) else str(value) + + def _import_resources(bloq: Bloq) -> list[dict[str, Any]]: """Import resources from Bloq's t_complexity method.""" t_complexity = bloq.t_complexity() @@ -268,17 +283,20 @@ def _import_resources(bloq: Bloq) -> list[dict[str, Any]]: resources = [] for name in resource_names: resources.append( - {"name": name, "value": is_symbolic(getattr(t_complexity, name)), "type": "additive"} + { + "name": name, + "value": _ensure_primitive_type(getattr(t_complexity, name)), + "type": "additive", + } ) return resources -def _extract_input_params(bloq: Bloq, ports: list[PortV1]) -> list[str]: +def _extract_input_params(bloq: Bloq, ports: list[PortV1], local_variables) -> list[str]: """Extracts input_params from bloq's t_complexity and port sizes.""" params_from_t_complexity = _extract_symbols_from_t_complexity(bloq) params_from_ports = _extract_symbols_from_port_sizes(ports) - params = list(set(params_from_t_complexity + params_from_ports)) - return sorted(params) + return set(params_from_t_complexity + params_from_ports) def _extract_symbols_from_t_complexity(bloq: Bloq) -> list[str]: diff --git a/qualtran/qref_interop/_bloq_to_qref_test.py b/qualtran/qref_interop/_bloq_to_qref_test.py index f2513c4a9..14116998e 100644 --- a/qualtran/qref_interop/_bloq_to_qref_test.py +++ b/qualtran/qref_interop/_bloq_to_qref_test.py @@ -37,18 +37,6 @@ def test_bloq_examples_can_be_converted_to_qualtran_when_decomposed(bloq_example pytest.xfail(f"QREF conversion failing for {bloq}") -@pytest.mark.parametrize("bloq_example", get_bloq_examples()) -def test_bloq_examples_can_be_converted_to_qualtran_through_call_graph(bloq_example): - try: - bloq = bloq_example.make() - except (DecomposeTypeError, DecomposeNotImplementedError, ValueError) as e: - pytest.skip(f"QREF conversion not attempted, as extracting callgraph failed with {e}") - try: - qref_routine = bloq_to_qref_from_call_graph(bloq) - except: - pytest.xfail(f"QREF conversion failing for {bloq}") - - def _cnot_routine(name: str) -> RoutineV1: return RoutineV1( name=name, @@ -235,216 +223,26 @@ def _undecomposed_alias_sampling() -> tuple[Bloq, RoutineV1, str]: type="StatePreparationAliasSampling", ports=[ {"name": "in_selection", "size": 2, "direction": "input"}, - {"name": "in_sigma_mu", "size": 3, "direction": "input"}, + {"name": "in_sigma_mu", "size": 16, "direction": "input"}, {"name": "in_alt", "size": 2, "direction": "input"}, - {"name": "in_keep", "size": 3, "direction": "input"}, + {"name": "in_keep", "size": 16, "direction": "input"}, {"name": "in_less_than_equal", "size": 1, "direction": "input"}, {"name": "out_selection", "size": 2, "direction": "output"}, - {"name": "out_sigma_mu", "size": 3, "direction": "output"}, + {"name": "out_sigma_mu", "size": 16, "direction": "output"}, {"name": "out_alt", "size": 2, "direction": "output"}, - {"name": "out_keep", "size": 3, "direction": "output"}, + {"name": "out_keep", "size": 16, "direction": "output"}, {"name": "out_less_than_equal", "size": 1, "direction": "output"}, ], resources=[ - {"name": "clifford", "value": 268, "type": "additive"}, + {"name": "clifford", "value": 879, "type": "additive"}, {"name": "rotations", "value": 2, "type": "additive"}, - {"name": "t", "value": 58, "type": "additive"}, + {"name": "t", "value": 162, "type": "additive"}, ], ) return bloq, routine, "alias sampling (not decomposed)" -def _decomposed_alias_sampling() -> tuple[Bloq, RoutineV1, str]: - bloq = StatePreparationAliasSampling.from_probabilities([0.25, 0.5, 0.25]).decompose_bloq() - - routine = RoutineV1( - name="CompositeBloq", - type="CompositeBloq", - ports=[ - {"name": "in_selection", "size": 2, "direction": "input"}, - {"name": "in_sigma_mu", "size": 3, "direction": "input"}, - {"name": "in_alt", "size": 2, "direction": "input"}, - {"name": "in_keep", "size": 3, "direction": "input"}, - {"name": "in_less_than_equal", "size": 1, "direction": "input"}, - {"name": "out_selection", "size": 2, "direction": "output"}, - {"name": "out_sigma_mu", "size": 3, "direction": "output"}, - {"name": "out_alt", "size": 2, "direction": "output"}, - {"name": "out_keep", "size": 3, "direction": "output"}, - {"name": "out_less_than_equal", "size": 1, "direction": "output"}, - ], - children=[ - RoutineV1( - name="Split_1", - type="Split", - ports=[ - {"name": "in_reg", "direction": "input", "size": 3}, - {"name": "out_reg_0", "direction": "output", "size": 1}, - {"name": "out_reg_1", "direction": "output", "size": 1}, - {"name": "out_reg_2", "direction": "output", "size": 1}, - ], - resources=[ - {"name": "clifford", "value": 0, "type": "additive"}, - {"name": "rotations", "value": 0, "type": "additive"}, - {"name": "t", "value": 0, "type": "additive"}, - ], - ), - RoutineV1( - name="Hadamard_2", - type="Hadamard", - ports=[ - {"name": "in_q", "direction": "input", "size": 1}, - {"name": "out_q", "direction": "output", "size": 1}, - ], - resources=[ - {"name": "clifford", "value": 1, "type": "additive"}, - {"name": "rotations", "value": 0, "type": "additive"}, - {"name": "t", "value": 0, "type": "additive"}, - ], - ), - RoutineV1( - name="Hadamard_3", - type="Hadamard", - ports=[ - {"name": "in_q", "direction": "input", "size": 1}, - {"name": "out_q", "direction": "output", "size": 1}, - ], - resources=[ - {"name": "clifford", "value": 1, "type": "additive"}, - {"name": "rotations", "value": 0, "type": "additive"}, - {"name": "t", "value": 0, "type": "additive"}, - ], - ), - RoutineV1( - name="Hadamard_4", - type="Hadamard", - ports=[ - {"name": "in_q", "direction": "input", "size": 1}, - {"name": "out_q", "direction": "output", "size": 1}, - ], - resources=[ - {"name": "clifford", "value": 1, "type": "additive"}, - {"name": "rotations", "value": 0, "type": "additive"}, - {"name": "t", "value": 0, "type": "additive"}, - ], - ), - RoutineV1( - name="CSwap_8", - type="CSwap", - ports=[ - {"name": "in_ctrl", "direction": "input", "size": 1}, - {"name": "out_ctrl", "direction": "output", "size": 1}, - {"name": "in_x", "direction": "input", "size": 2}, - {"name": "out_x", "direction": "output", "size": 2}, - {"name": "in_y", "direction": "input", "size": 2}, - {"name": "out_y", "direction": "output", "size": 2}, - ], - resources=[ - {"name": "clifford", "value": 20, "type": "additive"}, - {"name": "rotations", "value": 0, "type": "additive"}, - {"name": "t", "value": 14, "type": "additive"}, - ], - ), - RoutineV1( - name="Join_6", - type="Join", - ports=[ - {"name": "out_reg", "direction": "output", "size": 3}, - {"name": "in_reg_0", "direction": "input", "size": 1}, - {"name": "in_reg_1", "direction": "input", "size": 1}, - {"name": "in_reg_2", "direction": "input", "size": 1}, - ], - resources=[ - {"name": "clifford", "value": 0, "type": "additive"}, - {"name": "rotations", "value": 0, "type": "additive"}, - {"name": "t", "value": 0, "type": "additive"}, - ], - ), - RoutineV1( - name="LessThanEqual_7", - type="LessThanEqual", - ports=[ - {"name": "in_x", "direction": "input", "size": 3}, - {"name": "out_x", "direction": "output", "size": 3}, - {"name": "in_y", "direction": "input", "size": 3}, - {"name": "out_y", "direction": "output", "size": 3}, - {"name": "in_target", "direction": "input", "size": 1}, - {"name": "out_target", "direction": "output", "size": 1}, - ], - resources=[ - {"name": "clifford", "value": 117, "type": "additive"}, - {"name": "rotations", "value": 0, "type": "additive"}, - {"name": "t", "value": 20, "type": "additive"}, - ], - ), - RoutineV1( - name="PrepareUniformSuperposition_0", - type="PrepareUniformSuperposition", - ports=[ - {"name": "in_target", "direction": "input", "size": 2}, - {"name": "out_target", "direction": "output", "size": 2}, - ], - resources=[ - {"name": "clifford", "value": 103, "type": "additive"}, - {"name": "rotations", "value": 2, "type": "additive"}, - {"name": "t", "value": 20, "type": "additive"}, - ], - ), - RoutineV1( - name="QROM_5", - type="QROM", - ports=[ - {"name": "in_selection", "direction": "input", "size": 2}, - {"name": "out_selection", "direction": "output", "size": 2}, - {"name": "in_target0_", "direction": "input", "size": 2}, - {"name": "out_target0_", "direction": "output", "size": 2}, - {"name": "in_target1_", "direction": "input", "size": 3}, - {"name": "out_target1_", "direction": "output", "size": 3}, - ], - resources=[ - {"name": "clifford", "value": 25, "type": "additive"}, - {"name": "rotations", "value": 0, "type": "additive"}, - {"name": "t", "value": 4, "type": "additive"}, - ], - ), - ], - connections=[ - {"source": in_, "target": out_} - for in_, out_ in [ - ("CSwap_8.out_ctrl", "out_less_than_equal"), - ("CSwap_8.out_x", "out_alt"), - ("CSwap_8.out_y", "out_selection"), - ("Hadamard_2.out_q", "Join_6.in_reg_0"), - ("Hadamard_3.out_q", "Join_6.in_reg_1"), - ("Hadamard_4.out_q", "Join_6.in_reg_2"), - ("Join_6.out_reg", "LessThanEqual_7.in_y"), - ("LessThanEqual_7.out_target", "CSwap_8.in_ctrl"), - ("LessThanEqual_7.out_x", "out_keep"), - ("LessThanEqual_7.out_y", "out_sigma_mu"), - ("PrepareUniformSuperposition_0.out_target", "QROM_5.in_selection"), - ("QROM_5.out_selection", "CSwap_8.in_y"), - ("QROM_5.out_target0_", "CSwap_8.in_x"), - ("QROM_5.out_target1_", "LessThanEqual_7.in_x"), - ("Split_1.out_reg_0", "Hadamard_2.in_q"), - ("Split_1.out_reg_1", "Hadamard_3.in_q"), - ("Split_1.out_reg_2", "Hadamard_4.in_q"), - ("in_alt", "QROM_5.in_target0_"), - ("in_keep", "QROM_5.in_target1_"), - ("in_less_than_equal", "LessThanEqual_7.in_target"), - ("in_selection", "PrepareUniformSuperposition_0.in_target"), - ("in_sigma_mu", "Split_1.in_reg"), - ] - ], - resources=[ - {"name": "clifford", "value": 268, "type": "additive"}, - {"name": "rotations", "value": 2, "type": "additive"}, - {"name": "t", "value": 58, "type": "additive"}, - ], - ) - - return bloq, routine, "alias sampling (decomposed)" - - @pytest.mark.parametrize( "qualtran_object, expected_routine", [ @@ -456,7 +254,6 @@ def _decomposed_alias_sampling() -> tuple[Bloq, RoutineV1, str]: _less_than_equal_symbolic(), _qrom_symbolic(), _undecomposed_alias_sampling(), - _decomposed_alias_sampling(), ] ], ) From 8db252dec78a4e3e6224b92572839a3e345d580f Mon Sep 17 00:00:00 2001 From: mstechly Date: Tue, 30 Jul 2024 16:47:38 +0200 Subject: [PATCH 07/12] Update notebook output --- qualtran/qref_interop/bartiq_demo.ipynb | 1795 +---------------------- 1 file changed, 38 insertions(+), 1757 deletions(-) diff --git a/qualtran/qref_interop/bartiq_demo.ipynb b/qualtran/qref_interop/bartiq_demo.ipynb index b8cfdaa15..e79a0df82 100644 --- a/qualtran/qref_interop/bartiq_demo.ipynb +++ b/qualtran/qref_interop/bartiq_demo.ipynb @@ -18,21 +18,6 @@ "This is not meant to be introduction to these packages, we assume that the reader has a basic understanding of what these packages allow them to do. If not, please refer to their documentation." ] }, - { - "cell_type": "code", - "execution_count": 1, - "id": "bfbe10db-d89d-4c23-a862-c8473fe1bdd3", - "metadata": {}, - "outputs": [], - "source": [ - "from qualtran.bloqs.data_loading.qrom import QROM\n", - "from qualtran.bloqs.state_preparation import PrepareUniformSuperposition\n", - "from qualtran.drawing import show_call_graph\n", - "\n", - "import yaml\n", - "import sympy" - ] - }, { "cell_type": "markdown", "id": "0d62ccdd-3336-4971-9a68-d67dc0e060f8", @@ -50,751 +35,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "cfeb60ce-81af-494c-8e6c-9033642048f8", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "my_graph\n", - "\n", - "\n", - "\n", - "selection_G45\n", - "selection\n", - "\n", - "\n", - "\n", - "PrepareUniformSuperposition\n", - "\n", - "PrepareUniformSuperposition\n", - "\n", - "target\n", - "\n", - "\n", - "\n", - "selection_G45:e->PrepareUniformSuperposition:w\n", - "\n", - "\n", - "5\n", - "\n", - "\n", - "\n", - "sigma_mu\n", - "sigma_mu\n", - "\n", - "\n", - "\n", - "Split\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "sigma_mu:e->Split:w\n", - "\n", - "\n", - "21\n", - "\n", - "\n", - "\n", - "alt\n", - "alt\n", - "\n", - "\n", - "\n", - "QROM\n", - "\n", - "QROM\n", - "\n", - "selection\n", - "\n", - "target0_\n", - "\n", - "target1_\n", - "\n", - "\n", - "\n", - "alt:e->QROM:w\n", - "\n", - "\n", - "5\n", - "\n", - "\n", - "\n", - "keep\n", - "keep\n", - "\n", - "\n", - "\n", - "keep:e->QROM:w\n", - "\n", - "\n", - "21\n", - "\n", - "\n", - "\n", - "less_than_equal_G112\n", - "less_than_equal\n", - "\n", - "\n", - "\n", - "LessThanEqual\n", - "\n", - "LessThanEqual\n", - "\n", - "x\n", - "\n", - "y\n", - "\n", - "target\n", - "\n", - "\n", - "\n", - "less_than_equal_G112:e->LessThanEqual:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Join\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Hadamard:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G0\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Hadamard_G0:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G2\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Hadamard_G2:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G4\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Hadamard_G4:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G6\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Hadamard_G6:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G8\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Hadamard_G8:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "CSwap\n", - "\n", - "CSwap\n", - "\n", - "ctrl\n", - "\n", - "x\n", - "\n", - "y\n", - "\n", - "\n", - "\n", - "selection_G90\n", - "selection\n", - "\n", - "\n", - "\n", - "CSwap:e->selection_G90:w\n", - "\n", - "\n", - "5\n", - "\n", - "\n", - "\n", - "alt_G101\n", - "alt\n", - "\n", - "\n", - "\n", - "CSwap:e->alt_G101:w\n", - "\n", - "\n", - "5\n", - "\n", - "\n", - "\n", - "less_than_equal\n", - "less_than_equal\n", - "\n", - "\n", - "\n", - "CSwap:e->less_than_equal:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G0:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G2:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G4:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G6:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G8:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G10\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G10:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G12\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G12:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G14\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G14:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G16\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G16:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G18\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G18:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G20\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G20:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G22\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G22:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G24\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G24:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G30\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G30:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G32\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G32:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G34\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G34:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G36\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G36:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G38\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G38:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G40\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G40:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G42\n", - "\n", - "H\n", - "\n", - "q\n", - "\n", - "\n", - "\n", - "Split:e->Hadamard_G42:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G10:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G12:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G14:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "PrepareUniformSuperposition:e->QROM:w\n", - "\n", - "\n", - "5\n", - "\n", - "\n", - "\n", - "QROM:e->CSwap:w\n", - "\n", - "\n", - "5\n", - "\n", - "\n", - "\n", - "QROM:e->CSwap:w\n", - "\n", - "\n", - "5\n", - "\n", - "\n", - "\n", - "QROM:e->LessThanEqual:w\n", - "\n", - "\n", - "21\n", - "\n", - "\n", - "\n", - "Hadamard_G16:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G18:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G20:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G22:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G24:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "LessThanEqual:e->CSwap:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "sigma_mu_G99\n", - "sigma_mu\n", - "\n", - "\n", - "\n", - "LessThanEqual:e->sigma_mu_G99:w\n", - "\n", - "\n", - "21\n", - "\n", - "\n", - "\n", - "keep_G72\n", - "keep\n", - "\n", - "\n", - "\n", - "LessThanEqual:e->keep_G72:w\n", - "\n", - "\n", - "21\n", - "\n", - "\n", - "\n", - "Join:e->LessThanEqual:w\n", - "\n", - "\n", - "21\n", - "\n", - "\n", - "\n", - "Hadamard_G30:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G32:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G34:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G36:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G38:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G40:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "Hadamard_G42:e->Join:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from qualtran.bloqs.state_preparation import StatePreparationAliasSampling\n", "from qualtran.drawing.graphviz import PrettyGraphDrawer\n", @@ -806,822 +50,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "f3726d8c-ce01-4b6a-b5b6-72654b58f09b", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "cluster_.CompositeBloq\n", - "\n", - "CompositeBloq\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_alt"\n", - "\n", - "in_alt\n", - "\n", - "\n", - "\n", - "".CompositeBloq.QROM_23"\n", - "\n", - "in_selection\n", - "\n", - "in_target0_\n", - "\n", - "in_target1_\n", - "\n", - "QROM_23\n", - "\n", - "out_selection\n", - "\n", - "out_target0_\n", - "\n", - "out_target1_\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_alt"->".CompositeBloq.QROM_23":in_target0_\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_keep"\n", - "\n", - "in_keep\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_keep"->".CompositeBloq.QROM_23":in_target1_\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_less_than_equal"\n", - "\n", - "in_less_than_equal\n", - "\n", - "\n", - "\n", - "".CompositeBloq.LessThanEqual_25"\n", - "\n", - "in_target\n", - "\n", - "in_x\n", - "\n", - "in_y\n", - "\n", - "LessThanEqual_25\n", - "\n", - "out_target\n", - "\n", - "out_x\n", - "\n", - "out_y\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_less_than_equal"->".CompositeBloq.LessThanEqual_25":in_target\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_selection"\n", - "\n", - "in_selection\n", - "\n", - "\n", - "\n", - "".CompositeBloq.PrepareUniformSuperposition_0"\n", - "\n", - "in_target\n", - "\n", - "PrepareUniformSuperposition_0\n", - "\n", - "out_target\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_selection"->".CompositeBloq.PrepareUniformSuperposition_0":in_target\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_sigma_mu"\n", - "\n", - "in_sigma_mu\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1"\n", - "\n", - "in_reg\n", - "\n", - "Split_1\n", - "\n", - "out_reg_0\n", - "\n", - "out_reg_1\n", - "\n", - "out_reg_10\n", - "\n", - "out_reg_11\n", - "\n", - "out_reg_12\n", - "\n", - "out_reg_13\n", - "\n", - "out_reg_14\n", - "\n", - "out_reg_15\n", - "\n", - "out_reg_16\n", - "\n", - "out_reg_17\n", - "\n", - "out_reg_18\n", - "\n", - "out_reg_19\n", - "\n", - "out_reg_2\n", - "\n", - "out_reg_20\n", - "\n", - "out_reg_3\n", - "\n", - "out_reg_4\n", - "\n", - "out_reg_5\n", - "\n", - "out_reg_6\n", - "\n", - "out_reg_7\n", - "\n", - "out_reg_8\n", - "\n", - "out_reg_9\n", - "\n", - "\n", - "\n", - "".CompositeBloq.in_sigma_mu"->".CompositeBloq.Split_1":in_reg\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.out_alt"\n", - "\n", - "out_alt\n", - "\n", - "\n", - "\n", - "".CompositeBloq.out_keep"\n", - "\n", - "out_keep\n", - "\n", - "\n", - "\n", - "".CompositeBloq.out_less_than_equal"\n", - "\n", - "out_less_than_equal\n", - "\n", - "\n", - "\n", - "".CompositeBloq.out_selection"\n", - "\n", - "out_selection\n", - "\n", - "\n", - "\n", - "".CompositeBloq.out_sigma_mu"\n", - "\n", - "out_sigma_mu\n", - "\n", - "\n", - "\n", - "".CompositeBloq.CSwap_26"\n", - "\n", - "in_ctrl\n", - "\n", - "in_x\n", - "\n", - "in_y\n", - "\n", - "CSwap_26\n", - "\n", - "out_ctrl\n", - "\n", - "out_x\n", - "\n", - "out_y\n", - "\n", - "\n", - "\n", - "".CompositeBloq.CSwap_26":out_x->".CompositeBloq.out_alt"\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.CSwap_26":out_ctrl->".CompositeBloq.out_less_than_equal"\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.CSwap_26":out_y->".CompositeBloq.out_selection"\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_10"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_10\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Join_24"\n", - "\n", - "in_reg_0\n", - "\n", - "in_reg_1\n", - "\n", - "in_reg_10\n", - "\n", - "in_reg_11\n", - "\n", - "in_reg_12\n", - "\n", - "in_reg_13\n", - "\n", - "in_reg_14\n", - "\n", - "in_reg_15\n", - "\n", - "in_reg_16\n", - "\n", - "in_reg_17\n", - "\n", - "in_reg_18\n", - "\n", - "in_reg_19\n", - "\n", - "in_reg_2\n", - "\n", - "in_reg_20\n", - "\n", - "in_reg_3\n", - "\n", - "in_reg_4\n", - "\n", - "in_reg_5\n", - "\n", - "in_reg_6\n", - "\n", - "in_reg_7\n", - "\n", - "in_reg_8\n", - "\n", - "in_reg_9\n", - "\n", - "Join_24\n", - "\n", - "out_reg\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_10":out_q->".CompositeBloq.Join_24":in_reg_8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_11"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_11\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_11":out_q->".CompositeBloq.Join_24":in_reg_9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_12"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_12\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_12":out_q->".CompositeBloq.Join_24":in_reg_10\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_13"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_13\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_13":out_q->".CompositeBloq.Join_24":in_reg_11\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_14"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_14\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_14":out_q->".CompositeBloq.Join_24":in_reg_12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_15"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_15\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_15":out_q->".CompositeBloq.Join_24":in_reg_13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_16"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_16\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_16":out_q->".CompositeBloq.Join_24":in_reg_14\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_17"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_17\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_17":out_q->".CompositeBloq.Join_24":in_reg_15\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_18"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_18\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_18":out_q->".CompositeBloq.Join_24":in_reg_16\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_19"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_19\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_19":out_q->".CompositeBloq.Join_24":in_reg_17\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_2"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_2\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_2":out_q->".CompositeBloq.Join_24":in_reg_0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_20"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_20\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_20":out_q->".CompositeBloq.Join_24":in_reg_18\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_21"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_21\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_21":out_q->".CompositeBloq.Join_24":in_reg_19\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_22"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_22\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_22":out_q->".CompositeBloq.Join_24":in_reg_20\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_3"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_3\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_3":out_q->".CompositeBloq.Join_24":in_reg_1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_4"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_4\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_4":out_q->".CompositeBloq.Join_24":in_reg_2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_5"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_5\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_5":out_q->".CompositeBloq.Join_24":in_reg_3\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_6"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_6\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_6":out_q->".CompositeBloq.Join_24":in_reg_4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_7"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_7\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_7":out_q->".CompositeBloq.Join_24":in_reg_5\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_8"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_8\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_8":out_q->".CompositeBloq.Join_24":in_reg_6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_9"\n", - "\n", - "in_q\n", - "\n", - "Hadamard_9\n", - "\n", - "out_q\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Hadamard_9":out_q->".CompositeBloq.Join_24":in_reg_7\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Join_24":out_reg->".CompositeBloq.LessThanEqual_25":in_y\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.LessThanEqual_25":out_x->".CompositeBloq.out_keep"\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.LessThanEqual_25":out_y->".CompositeBloq.out_sigma_mu"\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.LessThanEqual_25":out_target->".CompositeBloq.CSwap_26":in_ctrl\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.PrepareUniformSuperposition_0":out_target->".CompositeBloq.QROM_23":in_selection\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.QROM_23":out_selection->".CompositeBloq.CSwap_26":in_y\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.QROM_23":out_target0_->".CompositeBloq.CSwap_26":in_x\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.QROM_23":out_target1_->".CompositeBloq.LessThanEqual_25":in_x\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_8->".CompositeBloq.Hadamard_10":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_9->".CompositeBloq.Hadamard_11":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_10->".CompositeBloq.Hadamard_12":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_11->".CompositeBloq.Hadamard_13":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_12->".CompositeBloq.Hadamard_14":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_13->".CompositeBloq.Hadamard_15":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_14->".CompositeBloq.Hadamard_16":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_15->".CompositeBloq.Hadamard_17":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_16->".CompositeBloq.Hadamard_18":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_17->".CompositeBloq.Hadamard_19":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_0->".CompositeBloq.Hadamard_2":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_18->".CompositeBloq.Hadamard_20":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_19->".CompositeBloq.Hadamard_21":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_20->".CompositeBloq.Hadamard_22":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_1->".CompositeBloq.Hadamard_3":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_2->".CompositeBloq.Hadamard_4":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_3->".CompositeBloq.Hadamard_5":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_4->".CompositeBloq.Hadamard_6":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_5->".CompositeBloq.Hadamard_7":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_6->".CompositeBloq.Hadamard_8":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "".CompositeBloq.Split_1":out_reg_7->".CompositeBloq.Hadamard_9":in_q\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from qualtran.qref_interop import bloq_to_qref\n", "from qref.experimental.rendering import to_graphviz\n", @@ -1633,21 +65,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "755d7031-617a-4908-9ee1-45a42c422fbd", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TComplexity(t=307, clifford=1770, rotations=2)\n", - "[ResourceV1(name='clifford', type='additive', value=1770),\n", - " ResourceV1(name='rotations', type='additive', value=2),\n", - " ResourceV1(name='t', type='additive', value=307)]\n" - ] - } - ], + "outputs": [], "source": [ "from pprint import pprint\n", "# We can check that the resources for both representations are the same:\n", @@ -1665,21 +86,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "bafd2405-3ac0-43ff-b9b4-7978ffd49cef", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TComplexity(t=20, clifford=106, rotations=2)\n", - "[ResourceV1(name='clifford', type='additive', value=106),\n", - " ResourceV1(name='rotations', type='additive', value=2),\n", - " ResourceV1(name='t', type='additive', value=20)]\n" - ] - } - ], + "outputs": [], "source": [ "USP_bloq = [bloq_inst.bloq for bloq_inst in bloq.bloq_instances if bloq_inst.bloq.pretty_name() == \"PrepareUniformSuperposition\"][0]\n", "pprint(USP_bloq.t_complexity())\n", @@ -1697,20 +107,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "56beb66e-0989-4cf6-920b-bbc51cae559d", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'clifford': ,\n", - " 'rotations': ,\n", - " 't': }\n" - ] - } - ], + "outputs": [], "source": [ "from bartiq.integrations.qref import qref_to_bartiq\n", "from bartiq import compile_routine\n", @@ -1773,23 +173,13 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "b6491b25-8364-4542-ba4e-3de3b990ad10", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "TComplexity(t=12*ceiling(log2(N - 1)) - 4, clifford=52*ceiling(log2(N - 1)) - 9, rotations=2)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from qualtran.bloqs.state_preparation import PrepareUniformSuperposition\n", + "import sympy\n", "N = sympy.symbols(\"N\")\n", "USP_bloq = PrepareUniformSuperposition(N)\n", "# We see that contrary to the docstring, number of rotations is already correct\n", @@ -1798,7 +188,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "1c730d6c-1ed3-4da5-8988-3d8bac2dcbd3", "metadata": {}, "outputs": [], @@ -1810,23 +200,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "d5c82602-5db5-4071-9b52-062454ce154a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[ResourceV1(name='clifford', type='additive', value='52*ceiling(log2(N - 1)) - 9'),\n", - " ResourceV1(name='rotations', type='additive', value='2'),\n", - " ResourceV1(name='t', type='additive', value='12*ceiling(log2(N - 1)) - 4')]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# We check if the expressions are \n", "usp_1_qref.program.resources" @@ -1834,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "97d88fce-c538-4282-a665-b2c721716d84", "metadata": {}, "outputs": [], @@ -1865,21 +242,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "814c2e11-d430-411e-b015-85e803528b3a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "usp_1_bartiq = qref_to_bartiq(usp_1_qref)\n", "compile_routine(usp_1_bartiq).resources[\"t\"]" @@ -1887,21 +253,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "1183503a-0aa5-42e9-8c10-1218b9a2dbf7", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "usp_2_bartiq = qref_to_bartiq(usp_2_qref)\n", "compile_routine(usp_2_bartiq).resources[\"t\"]" @@ -1917,7 +272,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "d2bddbd7-fd86-400e-8cfe-b593995f91f3", "metadata": {}, "outputs": [], @@ -1927,7 +282,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "b1a54903-29a3-4017-84cf-e87d51d53a4a", "metadata": {}, "outputs": [], @@ -1941,7 +296,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "f2305c8f-7bf0-44a2-8c2f-d6afd63111ea", "metadata": {}, "outputs": [], @@ -1954,21 +309,10 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "8fe913dc-a880-432f-bc37-d18316d6da92", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "bartiq_as_1 = qref_to_bartiq(qref_as_1)\n", "compile_routine(bartiq_as_1).resources[\"t\"]" @@ -1976,29 +320,10 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "72f0b802-a3cd-4e43-86da-ad1bbe0fe39b", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/mstechly/Documents/code/2024-06-26-qualtran-conversion/bartiq/src/bartiq/compilation/_compile.py:117: UserWarning: Found the following issues with the provided routine after the compilation has finished: [\"Input param N found in subroutine: CompositeBloq.PrepareUniformSuperposition_0, which is not among top level params: {'PrepareUniformSuperposition_0.N'}.\"]\n", - " warnings.warn(\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "bartiq_as_2 = qref_to_bartiq(qref_as_2)\n", "compile_routine(bartiq_as_2).resources[\"t\"]" @@ -2014,7 +339,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "275437ee-aab0-4f38-93dc-603ba1a4a5f2", "metadata": {}, "outputs": [], @@ -2026,21 +351,10 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "2d0cc292-9421-42ee-a4ef-f8753e308167", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "bartiq_as_2 = qref_to_bartiq(qref_as_2)\n", "compiled_as_2 = compile_routine(bartiq_as_2)\n", @@ -2057,21 +371,10 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "1ecc7d7a-22da-4072-bf96-1d6e26e01493", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from bartiq import evaluate\n", "\n", @@ -2101,7 +404,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "id": "5e6f5a6e-3b31-4bb0-ad9e-2cc45e2290ed", "metadata": {}, "outputs": [], @@ -2115,21 +418,10 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "id": "1bc1821a-0b41-4c4c-9cbf-24d71e0f18ec", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'t': }" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import copy\n", "usp_3_qref = copy.copy(usp_2_qref)\n", @@ -2142,21 +434,10 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "id": "4cf814e0-d3e5-43f0-9197-373b897233a0", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'t': }" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "assignments = {\"N=101\"}\n", "functions_map = {\"foo\": foo}\n", From 2907d672bbef845d56d80a6141e1e0be3a82e889 Mon Sep 17 00:00:00 2001 From: mstechly Date: Wed, 31 Jul 2024 14:03:46 +0200 Subject: [PATCH 08/12] Update tests --- qualtran/qref_interop/_bloq_to_qref_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qualtran/qref_interop/_bloq_to_qref_test.py b/qualtran/qref_interop/_bloq_to_qref_test.py index 14116998e..627953b36 100644 --- a/qualtran/qref_interop/_bloq_to_qref_test.py +++ b/qualtran/qref_interop/_bloq_to_qref_test.py @@ -20,9 +20,9 @@ def test_bloq_examples_can_be_converted_to_qualtran(bloq_example): bloq = bloq_example.make() try: qref_routine = bloq_to_qref(bloq) - verify_topology(qref_routine) except: pytest.xfail(f"QREF conversion failing for {bloq}") + verify_topology(qref_routine) @pytest.mark.parametrize("bloq_example", get_bloq_examples()) @@ -206,10 +206,10 @@ def _qrom_symbolic() -> tuple[Bloq, RoutineV1, str]: ], input_params=["M", "N", "b1", "b2", "c"], local_variables={ - 'in_selection0_size': 'ceiling(log2(N - 1))', - 'out_selection0_size': 'ceiling(log2(N - 1))', - 'in_selection1_size': 'ceiling(log2(M - 1))', - 'out_selection1_size': 'ceiling(log2(M - 1))', + 'in_selection0_size': 'ceiling(log2(floor(N)))', + 'out_selection0_size': 'ceiling(log2(floor(N)))', + 'in_selection1_size': 'ceiling(log2(floor(M)))', + 'out_selection1_size': 'ceiling(log2(floor(M)))', }, ) return bloq, routine, "qrom (symbolic)" From 83019c8a20f7b77f05ae8f6b6a407ecc0f2df13f Mon Sep 17 00:00:00 2001 From: mstechly Date: Thu, 8 Aug 2024 20:33:21 +0200 Subject: [PATCH 09/12] Further fixes in QREF integration --- qualtran/qref_interop/_bloq_to_qref.py | 12 +++-- qualtran/qref_interop/_bloq_to_qref_test.py | 54 ++++++++++++--------- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/qualtran/qref_interop/_bloq_to_qref.py b/qualtran/qref_interop/_bloq_to_qref.py index 07d6fe7f5..27626cdc6 100644 --- a/qualtran/qref_interop/_bloq_to_qref.py +++ b/qualtran/qref_interop/_bloq_to_qref.py @@ -81,9 +81,7 @@ def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> d except AttributeError: pass - input_params = sorted( - list(_extract_input_params(bloq, ports, local_variables) - set(local_variables)) - ) + input_params = sorted(list(_extract_input_params(bloq, ports) - set(local_variables))) attributes = { "name": name, @@ -292,8 +290,12 @@ def _import_resources(bloq: Bloq) -> list[dict[str, Any]]: return resources -def _extract_input_params(bloq: Bloq, ports: list[PortV1], local_variables) -> list[str]: - """Extracts input_params from bloq's t_complexity and port sizes.""" +def _extract_input_params(bloq: Bloq, ports: list[PortV1]) -> list[str]: + """Extracts input_params from bloq's t_complexity and port sizes. + + In QREF `input_params` define the symbols that can be used to define port sizes + and resources of a particular routine. + """ params_from_t_complexity = _extract_symbols_from_t_complexity(bloq) params_from_ports = _extract_symbols_from_port_sizes(ports) return set(params_from_t_complexity + params_from_ports) diff --git a/qualtran/qref_interop/_bloq_to_qref_test.py b/qualtran/qref_interop/_bloq_to_qref_test.py index 627953b36..2a846c52f 100644 --- a/qualtran/qref_interop/_bloq_to_qref_test.py +++ b/qualtran/qref_interop/_bloq_to_qref_test.py @@ -1,40 +1,50 @@ -from dev_tools.qualtran_dev_tools.bloq_finder import get_bloq_examples -from qualtran.qref_interop import bloq_to_qref import pytest - import sympy -from qualtran.bloqs.basic_gates import CNOT +from qref.schema_v1 import RoutineV1 +from qref.verification import verify_topology + +from qualtran import Bloq, BloqBuilder +from qualtran.bloqs.arithmetic.addition import _add_oop_large from qualtran.bloqs.arithmetic.comparison import LessThanEqual -from qualtran.bloqs.state_preparation import StatePreparationAliasSampling +from qualtran.bloqs.basic_gates import CNOT +from qualtran.bloqs.block_encoding.lcu_block_encoding import ( + _black_box_lcu_zero_state_block, + _black_box_prepare, +) +from qualtran.bloqs.chemistry.df.double_factorization import _df_block_encoding, _df_one_body from qualtran.bloqs.data_loading.qrom import QROM +from qualtran.bloqs.state_preparation import StatePreparationAliasSampling +from qualtran.qref_interop import bloq_to_qref -from qualtran import DecomposeTypeError, DecomposeNotImplementedError -from qref.verification import verify_topology +# This function could be replaced by get_bloq_examples from dev_tools.qualtran_dev_tools.bloq_finder +# to run tests on all the available bloq examples, rather than a subset defined here. +# This might require minor tweaks like adding `make()` calls. -from qualtran import Bloq, BloqBuilder -from qref.schema_v1 import RoutineV1 + + + +def get_bloq_examples(): + return [ + _add_oop_large, + _black_box_prepare, + _black_box_lcu_zero_state_block, + _df_one_body, + _df_block_encoding, + ] @pytest.mark.parametrize("bloq_example", get_bloq_examples()) def test_bloq_examples_can_be_converted_to_qualtran(bloq_example): bloq = bloq_example.make() - try: - qref_routine = bloq_to_qref(bloq) - except: - pytest.xfail(f"QREF conversion failing for {bloq}") - verify_topology(qref_routine) + qref_routine = bloq_to_qref(bloq) + assert verify_topology(qref_routine) @pytest.mark.parametrize("bloq_example", get_bloq_examples()) def test_bloq_examples_can_be_converted_to_qualtran_when_decomposed(bloq_example): - try: - bloq = bloq_example.make().decompose_bloq() - except (DecomposeTypeError, DecomposeNotImplementedError, ValueError) as e: - pytest.skip(f"QREF conversion not attempted, as bloq decomposition failed with {e}") - try: - qref_routine = bloq_to_qref(bloq) - except: - pytest.xfail(f"QREF conversion failing for {bloq}") + bloq = bloq_example.make().decompose_bloq() + qref_routine = bloq_to_qref(bloq) + assert verify_topology(qref_routine) def _cnot_routine(name: str) -> RoutineV1: From 5e3b96175bc60ff32e172132127a9bdeb56c66b5 Mon Sep 17 00:00:00 2001 From: mstechly Date: Thu, 8 Aug 2024 20:39:13 +0200 Subject: [PATCH 10/12] fix outdated import --- qualtran/qref_interop/_bloq_to_qref_test.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qualtran/qref_interop/_bloq_to_qref_test.py b/qualtran/qref_interop/_bloq_to_qref_test.py index 2a846c52f..54ceb2ac9 100644 --- a/qualtran/qref_interop/_bloq_to_qref_test.py +++ b/qualtran/qref_interop/_bloq_to_qref_test.py @@ -9,7 +9,7 @@ from qualtran.bloqs.basic_gates import CNOT from qualtran.bloqs.block_encoding.lcu_block_encoding import ( _black_box_lcu_zero_state_block, - _black_box_prepare, + _black_box_lcu_block, ) from qualtran.bloqs.chemistry.df.double_factorization import _df_block_encoding, _df_one_body from qualtran.bloqs.data_loading.qrom import QROM @@ -21,12 +21,10 @@ # This might require minor tweaks like adding `make()` calls. - - def get_bloq_examples(): return [ _add_oop_large, - _black_box_prepare, + _black_box_lcu_block, _black_box_lcu_zero_state_block, _df_one_body, _df_block_encoding, From cc68225c6b9a79e8258bd54c1bf3ea2fc392ce23 Mon Sep 17 00:00:00 2001 From: mstechly Date: Tue, 13 Aug 2024 19:19:08 +0200 Subject: [PATCH 11/12] fix formatting --- qualtran/qref_interop/_bloq_to_qref_test.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/qualtran/qref_interop/_bloq_to_qref_test.py b/qualtran/qref_interop/_bloq_to_qref_test.py index 54ceb2ac9..4fcacb634 100644 --- a/qualtran/qref_interop/_bloq_to_qref_test.py +++ b/qualtran/qref_interop/_bloq_to_qref_test.py @@ -7,28 +7,17 @@ from qualtran.bloqs.arithmetic.addition import _add_oop_large from qualtran.bloqs.arithmetic.comparison import LessThanEqual from qualtran.bloqs.basic_gates import CNOT -from qualtran.bloqs.block_encoding.lcu_block_encoding import ( - _black_box_lcu_zero_state_block, - _black_box_lcu_block, -) +from qualtran.bloqs.block_encoding.lcu_block_encoding import _black_box_lcu_block, _lcu_block from qualtran.bloqs.chemistry.df.double_factorization import _df_block_encoding, _df_one_body from qualtran.bloqs.data_loading.qrom import QROM from qualtran.bloqs.state_preparation import StatePreparationAliasSampling from qualtran.qref_interop import bloq_to_qref -# This function could be replaced by get_bloq_examples from dev_tools.qualtran_dev_tools.bloq_finder -# to run tests on all the available bloq examples, rather than a subset defined here. -# This might require minor tweaks like adding `make()` calls. - +# This function could be replaced by `get_bloq_examples` from `dev_tools.qualtran_dev_tools.bloq_finder` +# to run tests on all the available bloq examples, rather than a subset defined here. def get_bloq_examples(): - return [ - _add_oop_large, - _black_box_lcu_block, - _black_box_lcu_zero_state_block, - _df_one_body, - _df_block_encoding, - ] + return [_add_oop_large, _black_box_lcu_block, _lcu_block, _df_one_body, _df_block_encoding] @pytest.mark.parametrize("bloq_example", get_bloq_examples()) From bad1366483c33c2dd88c21b2a8e1ef4eda5c5fb1 Mon Sep 17 00:00:00 2001 From: mstechly Date: Tue, 13 Aug 2024 22:21:53 +0200 Subject: [PATCH 12/12] fix style issues --- qualtran/qref_interop/__init__.py | 26 ++++++++ qualtran/qref_interop/_bloq_to_qref.py | 69 +++++++++++++-------- qualtran/qref_interop/_bloq_to_qref_test.py | 26 ++++++++ 3 files changed, 95 insertions(+), 26 deletions(-) diff --git a/qualtran/qref_interop/__init__.py b/qualtran/qref_interop/__init__.py index f2f82519b..741991b9f 100644 --- a/qualtran/qref_interop/__init__.py +++ b/qualtran/qref_interop/__init__.py @@ -1 +1,27 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from ._bloq_to_qref import bloq_to_qref diff --git a/qualtran/qref_interop/_bloq_to_qref.py b/qualtran/qref_interop/_bloq_to_qref.py index 27626cdc6..dc4cae938 100644 --- a/qualtran/qref_interop/_bloq_to_qref.py +++ b/qualtran/qref_interop/_bloq_to_qref.py @@ -1,3 +1,29 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from functools import singledispatch from typing import Any, Iterable, Optional, Union @@ -70,20 +96,15 @@ def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> d if name is None: name = bloq.__class__.__name__ - try: - if bloq.uncompute: - name += "_uncompute" - except AttributeError: - pass - try: - if bloq.is_adjoint: - name += "_adjoint" - except AttributeError: - pass + + if hasattr(bloq, "uncompute"): + name += "_uncompute" + if hasattr(bloq, "is_adjoint"): + name += "_adjoint" input_params = sorted(list(_extract_input_params(bloq, ports) - set(local_variables))) - attributes = { + attributes: dict[str, Any] = { "name": name, "type": _bloq_type(bloq), "ports": ports, @@ -91,10 +112,6 @@ def _extract_common_bloq_attributes(bloq: Bloq, name: Optional[str] = None) -> d "input_params": input_params, } if len(local_variables) > 0: - print("\n") - print(local_variables) - print(_import_resources(bloq)) - print("\n") attributes["local_variables"] = local_variables return attributes @@ -103,7 +120,7 @@ def _bloq_instance_name(instance: BloqInstance) -> str: """Infer unique (but readable) name for a BloqInstance. Child Bloqs in CompositeBloq (and some other places) are stored as BloqInstances, - which combine a Bloq with a unique ID. When converting such BloqInstance to Bartiq + which combine a Bloq with a unique ID. When converting such BloqInstance to QREF RoutineV1, the ID has to be incorporated into the name, because otherwise one could get several siblings having the same name. """ @@ -116,7 +133,7 @@ def bloq_to_qref(obj) -> SchemaV1: @singledispatch -def bloq_to_routine(obj, name: Optional[str] = None): +def bloq_to_routine(obj: Any, name: Optional[str] = None) -> RoutineV1: """Import object from Qualtran by converting it into corresponding QREF RoutineV1 object. Args: @@ -126,7 +143,7 @@ def bloq_to_routine(obj, name: Optional[str] = None): know some good name for it. Return: - A Bartiq object corresponding to the source Qualtran object. For both Bloqs + A QREF object corresponding to the source Qualtran object. For both Bloqs and BloqInstances the returned object is of type RoutineV1. """ @@ -168,7 +185,7 @@ def _bloq_instance_to_routine(instance: BloqInstance) -> RoutineV1: def _names_and_dir_from_register(reg: Register) -> Iterable[tuple[str, str]]: - """Yield names and directions of Bartiq Ports corresponding to Qualtran Register. + """Yield names and directions of QREF Ports corresponding to Qualtran Register. For LEFT/RIGHT registers we yield one pair of name and direction corresponding of resp. output and input port. For THRU registers we yield both such pairs, @@ -197,7 +214,7 @@ def _expand_name_if_needed(reg_name, shape) -> Iterable[str]: def _ports_from_register(reg: Register) -> Iterable[PortV1]: - """Given a Qualtran register, return iterable of corresponding Bartiq Ports. + """Given a Qualtran register, return iterable of corresponding QREF Ports. Intuitively, one would expect a one to one correspondence between ports and registers. However: @@ -218,11 +235,11 @@ def _ports_from_register(reg: Register) -> Iterable[PortV1]: # Observe two loops: # - first one splits (if needed) any THRU register into two ports. It also takes care of # correct naming based on port directions. - # - second one expands composite register (which have no counterpart in Bartiq) into + # - second one expands composite register (which have no counterpart in QREF) into # required number of single ports. PortV1( name=expanded_name, - direction=direction, + direction=direction, # type: ignore size=reg.bitsize if isinstance(reg.bitsize, int) else str(reg.bitsize), ) for flat_name, direction in _names_and_dir_from_register(reg) @@ -237,7 +254,7 @@ def _opposite(direction: str) -> str: def _relative_port_name(soquet: Soquet, direction) -> str: - """Given a Soquet and direction, determine the relative name of corresponding Bartiq Port. + """Given a Soquet and direction, determine the relative name of corresponding QREF Port. The relative name is always computed wrt. the parent RoutineV1. This function correctly recognizes the fact, that in any connection, the input parent @@ -251,7 +268,7 @@ def _relative_port_name(soquet: Soquet, direction) -> str: # We add another suffix iff soquet references idx in composite register suffix = f"_{soquet.idx[0]}" if soquet.idx else "" return ( - # If soquet references BlogqInstance, the corresponding object in Bartiq + # If soquet references BloqInstance, the corresponding object in QREF # references child - construct dotted relative name. # Otherwise, soquet references the parent port, and so for the output direction, # the port is in_parent_port, which is why we include _opposte here. @@ -290,7 +307,7 @@ def _import_resources(bloq: Bloq) -> list[dict[str, Any]]: return resources -def _extract_input_params(bloq: Bloq, ports: list[PortV1]) -> list[str]: +def _extract_input_params(bloq: Bloq, ports: list[PortV1]) -> set[str]: """Extracts input_params from bloq's t_complexity and port sizes. In QREF `input_params` define the symbols that can be used to define port sizes @@ -316,7 +333,7 @@ def _extract_symbols_from_t_complexity(bloq: Bloq) -> list[str]: def _extract_symbols_from_port_sizes(ports: list[PortV1]) -> list[str]: """Extracts symbols from the expressions for port sizes.""" - symbols = set() + symbols: set[sympy.Symbol] = set() for port in ports: symbols = symbols | sympy.sympify(port.size).free_symbols diff --git a/qualtran/qref_interop/_bloq_to_qref_test.py b/qualtran/qref_interop/_bloq_to_qref_test.py index 4fcacb634..6962b6184 100644 --- a/qualtran/qref_interop/_bloq_to_qref_test.py +++ b/qualtran/qref_interop/_bloq_to_qref_test.py @@ -1,3 +1,29 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import pytest import sympy from qref.schema_v1 import RoutineV1