diff --git a/dev_tools/autogenerate-bloqs-notebooks-v2.py b/dev_tools/autogenerate-bloqs-notebooks-v2.py index aba1b9c0e4..66d89998f6 100644 --- a/dev_tools/autogenerate-bloqs-notebooks-v2.py +++ b/dev_tools/autogenerate-bloqs-notebooks-v2.py @@ -43,7 +43,7 @@ python dev_tools/autogenerate-bloqs-notebooks-v2.py """ -from typing import Iterable, List +from collections.abc import Iterable from qualtran_dev_tools.bloq_finder import get_bloqdocspecs from qualtran_dev_tools.jupyter_autogen import NotebookSpecV2, render_notebook @@ -85,7 +85,7 @@ def render_notebooks(): render_notebook(nbspec) -def _get_toc_section_lines(caption: str, entries: List[str], maxdepth: int = 2) -> List[str]: +def _get_toc_section_lines(caption: str, entries: list[str], maxdepth: int = 2) -> list[str]: """Helper function to get the lines for a section of the table-of-contents.""" return ( ['.. toctree::', f' :maxdepth: {maxdepth}', f' :caption: {caption}:', ''] diff --git a/dev_tools/bloq-method-overrides-report.py b/dev_tools/bloq-method-overrides-report.py index 6f106bfc2f..f4d3530be5 100644 --- a/dev_tools/bloq-method-overrides-report.py +++ b/dev_tools/bloq-method-overrides-report.py @@ -11,14 +11,14 @@ # 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 typing import ForwardRef, Set, Type +from typing import ForwardRef from qualtran_dev_tools.bloq_finder import get_bloq_classes from qualtran import Bloq -def _call_graph(bc: Type[Bloq]): +def _call_graph(bc: type[Bloq]): """Check that a bloq class overrides the right call graph methods. - Override `build_call_graph` with canonical type annotations. @@ -42,7 +42,7 @@ def _call_graph(bc: Type[Bloq]): ) if annot['ssa'] != 'SympySymbolAllocator': print(f"{bc}.build_call_graph `ssa: 'SympySymbolAllocator'`") - if annot['return'] != Set[ForwardRef('BloqCountT')]: # type: ignore[misc] + if annot['return'] != set[ForwardRef('BloqCountT')]: # type: ignore[misc] print(f"{bc}.build_call_graph -> 'BloqCountT'") diff --git a/dev_tools/bloq-quickstarter.html b/dev_tools/bloq-quickstarter.html index fed8cda3ee..7ae2240a78 100644 --- a/dev_tools/bloq-quickstarter.html +++ b/dev_tools/bloq-quickstarter.html @@ -215,7 +215,7 @@

Code

signature += "\n ])" const template = `from functools import cached_property -from typing import Dict, Optional, Set, Union +from typing import Optional, Union from attrs import frozen @@ -238,10 +238,10 @@

Code

def signature(self) -> 'Signature': ${signature} - def build_composite_bloq(self, bb: 'BloqBuilder'${build_sig}) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder'${build_sig}) -> dict[str, 'SoquetT']: raise NotImplementedError("Implement or delete.") - def bloq_counts(self, ssa: Optional['SympySymbolAllocator'] = None) -> Set['BloqCountT']: + def bloq_counts(self, ssa: Optional['SympySymbolAllocator'] = None) -> set['BloqCountT']: raise NotImplementedError("Implement or delete.") def short_name(self) -> str: diff --git a/dev_tools/qualtran_dev_tools/all_call_graph.py b/dev_tools/qualtran_dev_tools/all_call_graph.py index 8154423c26..56b5fe530e 100644 --- a/dev_tools/qualtran_dev_tools/all_call_graph.py +++ b/dev_tools/qualtran_dev_tools/all_call_graph.py @@ -15,7 +15,7 @@ """Generate the library-wide call graph from all bloq examples.""" import logging import warnings -from typing import Iterable +from collections.abc import Iterable import networkx as nx diff --git a/dev_tools/qualtran_dev_tools/bloq_finder.py b/dev_tools/qualtran_dev_tools/bloq_finder.py index e0b0d12b49..b4d5ca9017 100644 --- a/dev_tools/qualtran_dev_tools/bloq_finder.py +++ b/dev_tools/qualtran_dev_tools/bloq_finder.py @@ -14,15 +14,15 @@ import importlib import inspect import subprocess +from collections.abc import Callable, Iterable from pathlib import Path -from typing import Callable, Iterable, List, Tuple, Type from qualtran import Bloq, BloqDocSpec, BloqExample from .git_tools import get_git_root -def _get_paths(bloqs_root: Path, filter_func: Callable[[Path], bool]) -> List[Path]: +def _get_paths(bloqs_root: Path, filter_func: Callable[[Path], bool]) -> list[Path]: """Get *.py files based on `filter_func`.""" cp = subprocess.run( ['git', 'ls-files', '*.py'], @@ -38,7 +38,7 @@ def _get_paths(bloqs_root: Path, filter_func: Callable[[Path], bool]) -> List[Pa return paths -def get_bloq_module_paths(bloqs_root: Path) -> List[Path]: +def get_bloq_module_paths(bloqs_root: Path) -> list[Path]: """Get *.py files for non-test, non-init modules under `bloqs_root`.""" def is_module_path(path: Path) -> bool: @@ -53,7 +53,7 @@ def is_module_path(path: Path) -> bool: return _get_paths(bloqs_root, is_module_path) -def get_bloq_test_module_paths(bloqs_root: Path) -> List[Path]: +def get_bloq_test_module_paths(bloqs_root: Path) -> list[Path]: """Get *_test.py files under `bloqs_root`.""" def is_test_module_path(path: Path) -> bool: @@ -70,7 +70,7 @@ def _bloq_modpath_to_modname(path: Path) -> str: return 'qualtran.bloqs.' + str(path)[: -len('.py')].replace('/', '.') -def modpath_to_bloqs(path: Path) -> Iterable[Type[Bloq]]: +def modpath_to_bloqs(path: Path) -> Iterable[type[Bloq]]: """Given a module path, return all the `Bloq` classes defined within.""" modname = _bloq_modpath_to_modname(path) mod = importlib.import_module(modname) @@ -88,7 +88,7 @@ def modpath_to_bloqs(path: Path) -> Iterable[Type[Bloq]]: yield cls -def modpath_to_bloq_exs(path: Path) -> Iterable[Tuple[str, str, BloqExample]]: +def modpath_to_bloq_exs(path: Path) -> Iterable[tuple[str, str, BloqExample]]: """Given a module path, return all the `BloqExample`s defined within.""" modname = _bloq_modpath_to_modname(path) mod = importlib.import_module(modname) @@ -97,7 +97,7 @@ def modpath_to_bloq_exs(path: Path) -> Iterable[Tuple[str, str, BloqExample]]: yield modname, name, obj -def modpath_to_bloqdocspecs(path: Path) -> Iterable[Tuple[str, str, BloqDocSpec]]: +def modpath_to_bloqdocspecs(path: Path) -> Iterable[tuple[str, str, BloqDocSpec]]: """Given a module path, return all the `BloqDocSpec`s defined within.""" modname = _bloq_modpath_to_modname(path) mod = importlib.import_module(modname) @@ -106,22 +106,22 @@ def modpath_to_bloqdocspecs(path: Path) -> Iterable[Tuple[str, str, BloqDocSpec] yield modname, name, obj -def get_bloq_classes() -> List[Type[Bloq]]: +def get_bloq_classes() -> list[type[Bloq]]: reporoot = get_git_root() bloqs_root = reporoot / 'qualtran/bloqs' paths = get_bloq_module_paths(bloqs_root) - bloq_clss: List[Type[Bloq]] = [] + bloq_clss: list[type[Bloq]] = [] for path in paths: bloq_clss.extend(modpath_to_bloqs(path)) return bloq_clss -def get_bloq_examples() -> List[BloqExample]: +def get_bloq_examples() -> list[BloqExample]: reporoot = get_git_root() bloqs_root = reporoot / 'qualtran/bloqs' paths = get_bloq_module_paths(bloqs_root) - bexamples: List[BloqExample] = [] + bexamples: list[BloqExample] = [] for path in paths: for modname, name, be in modpath_to_bloq_exs(path): bexamples.append(be) @@ -129,12 +129,12 @@ def get_bloq_examples() -> List[BloqExample]: return bexamples -def get_bloqdocspecs() -> List[BloqDocSpec]: +def get_bloqdocspecs() -> list[BloqDocSpec]: reporoot = get_git_root() bloqs_root = reporoot / 'qualtran/bloqs' paths = get_bloq_module_paths(bloqs_root) - bdspecs: List[BloqDocSpec] = [] + bdspecs: list[BloqDocSpec] = [] for path in paths: for modname, name, bds in modpath_to_bloqdocspecs(path): bdspecs.append(bds) diff --git a/dev_tools/qualtran_dev_tools/bloq_report_card.py b/dev_tools/qualtran_dev_tools/bloq_report_card.py index 4d26c7ffbc..1a82f086f7 100644 --- a/dev_tools/qualtran_dev_tools/bloq_report_card.py +++ b/dev_tools/qualtran_dev_tools/bloq_report_card.py @@ -13,7 +13,8 @@ # limitations under the License. import time import warnings -from typing import Any, Dict, Iterable, List, Optional, Set, Type +from collections.abc import Iterable +from typing import Any, Optional import pandas as pd import pandas.io.formats.style @@ -31,7 +32,7 @@ from .bloq_finder import get_bloq_classes, get_bloq_examples -def _get_package(bloq_cls: Type[Bloq]) -> str: +def _get_package(bloq_cls: type[Bloq]) -> str: """The package name for a bloq class""" return '.'.join(bloq_cls.__module__.split('.')[:-1]) @@ -56,8 +57,8 @@ def format_status(v: BloqCheckResult): def bloq_classes_with_no_examples( - bclasses: Iterable[Type[Bloq]], bexamples: Iterable[BloqExample] -) -> Set[Type[Bloq]]: + bclasses: Iterable[type[Bloq]], bexamples: Iterable[BloqExample] +) -> set[type[Bloq]]: ks = set(bclasses) for be in bexamples: try: @@ -72,13 +73,13 @@ def bloq_classes_with_no_examples( CHECKCOLS = ['make', 'decomp', 'counts', 'serialize', 'qtyping'] -def record_for_class_with_no_examples(k: Type[Bloq]) -> Dict[str, Any]: +def record_for_class_with_no_examples(k: type[Bloq]) -> dict[str, Any]: return {'bloq_cls': k.__name__, 'package': _get_package(k), 'name': '-'} | { check_name: BloqCheckResult.MISSING for check_name in CHECKCOLS } -def record_for_bloq_example(be: BloqExample) -> Dict[str, Any]: +def record_for_bloq_example(be: BloqExample) -> dict[str, Any]: start = time.perf_counter() record = { 'bloq_cls': be.bloq_cls.__name__, @@ -101,7 +102,7 @@ def show_bloq_report_card(df: pd.DataFrame) -> pandas.io.formats.style.Styler: def get_bloq_report_card( - bclasses: Optional[Iterable[Type[Bloq]]] = None, + bclasses: Optional[Iterable[type[Bloq]]] = None, bexamples: Optional[Iterable[BloqExample]] = None, package_prefix: str = 'qualtran.bloqs.', ) -> pd.DataFrame: @@ -115,7 +116,7 @@ def get_bloq_report_card( skips = ['qubitization_qpe_hubbard_model_small', 'qubitization_qpe_hubbard_model_large'] bexamples = [bex for bex in bexamples if bex.name not in skips] - records: List[Dict[str, Any]] = [] + records: list[dict[str, Any]] = [] missing_bclasses = bloq_classes_with_no_examples(bclasses, bexamples) records.extend(record_for_class_with_no_examples(k) for k in missing_bclasses) records.extend(record_for_bloq_example(be) for be in bexamples) diff --git a/dev_tools/qualtran_dev_tools/clean_notebooks.py b/dev_tools/qualtran_dev_tools/clean_notebooks.py index a5d31baf1c..83871ade6d 100644 --- a/dev_tools/qualtran_dev_tools/clean_notebooks.py +++ b/dev_tools/qualtran_dev_tools/clean_notebooks.py @@ -15,13 +15,13 @@ import subprocess from pathlib import Path from tempfile import NamedTemporaryFile -from typing import Any, List +from typing import Any import nbformat from nbconvert.preprocessors import ClearMetadataPreprocessor, ClearOutputPreprocessor -def get_nb_rel_paths(rootdir) -> List[Path]: +def get_nb_rel_paths(rootdir) -> list[Path]: """List all checked-in *.ipynb files within `rootdir`.""" cp = subprocess.run( ['git', 'ls-files', '*.ipynb'], diff --git a/dev_tools/qualtran_dev_tools/incremental_coverage.py b/dev_tools/qualtran_dev_tools/incremental_coverage.py index e13357eec6..8f7b060b00 100644 --- a/dev_tools/qualtran_dev_tools/incremental_coverage.py +++ b/dev_tools/qualtran_dev_tools/incremental_coverage.py @@ -14,7 +14,7 @@ import os.path import re -from typing import cast, Dict, List, Optional, Set, Tuple +from typing import cast, Optional from . import shell_tools from .prepared_env import PreparedEnv @@ -57,7 +57,7 @@ EXPLICIT_OPT_OUT_COMMENT = "#coverage:ignore" -def diff_to_new_interesting_lines(unified_diff_lines: List[str]) -> Dict[int, str]: +def diff_to_new_interesting_lines(unified_diff_lines: list[str]) -> dict[int, str]: """Extracts a set of 'interesting' lines out of a GNU unified diff format. Format: @@ -124,7 +124,7 @@ def fix_line_from_coverage_file(line): def get_incremental_uncovered_lines( abs_path: str, base_commit: str, actual_commit: Optional[str] -) -> List[Tuple[int, str, str]]: +) -> list[tuple[int, str, str]]: """Find touched but uncovered lines in the given file. Uses git diff and the annotation files created by `pytest --cov-report annotate` to find @@ -190,9 +190,9 @@ def line_content_counts_as_uncovered_manual(content: str) -> bool: return True -def determine_ignored_lines(content: str) -> Set[int]: +def determine_ignored_lines(content: str) -> set[int]: lines = content.split("\n") - result: List[int] = [] + result: list[int] = [] i = 0 while i < len(lines): @@ -222,7 +222,7 @@ def determine_ignored_lines(content: str) -> Set[int]: return {e + 1 for e in result} -def naive_find_end_of_scope(lines: List[str], i: int) -> int: +def naive_find_end_of_scope(lines: list[str], i: int) -> int: # TODO: deal with line continuations, which may be less indented. # Github issue: https://github.com/quantumlib/Cirq/issues/2968 line = lines[i] diff --git a/dev_tools/qualtran_dev_tools/jupyter_autogen.py b/dev_tools/qualtran_dev_tools/jupyter_autogen.py index fb7dd8cfe8..8b9c6e9124 100644 --- a/dev_tools/qualtran_dev_tools/jupyter_autogen.py +++ b/dev_tools/qualtran_dev_tools/jupyter_autogen.py @@ -21,7 +21,7 @@ import textwrap from pathlib import Path from types import ModuleType -from typing import List, Optional, Tuple +from typing import Optional import nbformat from attrs import field, frozen @@ -66,7 +66,7 @@ class NotebookSpecV2: title: str module: ModuleType - bloq_specs: List[BloqDocSpec] + bloq_specs: list[BloqDocSpec] directory: str = field() _path_stem: Optional[str] = None @@ -87,7 +87,7 @@ def path(self) -> Path: return Path(self.directory) / f'{self.path_stem}.ipynb' -def _get_bloq_example_source_lines(bloq_ex: 'BloqExample') -> List[str]: +def _get_bloq_example_source_lines(bloq_ex: 'BloqExample') -> list[str]: """Parse out the source code from a factory function, so we can render it into a cell. Args: @@ -158,7 +158,7 @@ class _PyCell(_Cell): cell_id: str -def get_bloq_doc_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> List[_Cell]: +def get_bloq_doc_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> list[_Cell]: """Cells introducing the `bloq_cls`""" md_doc: str = '\n'.join(get_markdown_docstring_lines(bloqdoc.bloq_cls)) @@ -178,19 +178,19 @@ def _get_one_ex_instance_cell(bloq_ex: BloqExample, cid_prefix): ) -def get_example_instances_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> List[_Cell]: +def get_example_instances_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> list[_Cell]: """Cells constructing example instances of the bloq class.""" examples = bloqdoc.examples if not examples: return [] - cells: List[_Cell] = [ + cells: list[_Cell] = [ _MarkdownCell('### Example Instances', cell_id=f'{cid_prefix}.example_instances.md') ] return cells + [_get_one_ex_instance_cell(ex, cid_prefix) for ex in examples] -def get_graphical_signature_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> List[_Cell]: +def get_graphical_signature_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> list[_Cell]: """Cells showing a 'graphical signature' for the bloq examples.""" if not bloqdoc.examples: return [] @@ -209,7 +209,7 @@ def get_graphical_signature_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> List ] -def get_call_graph_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> List[_Cell]: +def get_call_graph_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> list[_Cell]: """Cells showing a call graph for one of the bloq examples.""" if bloqdoc.call_graph_example is None: return [] @@ -231,8 +231,8 @@ def get_call_graph_cells(bloqdoc: BloqDocSpec, cid_prefix: str) -> List[_Cell]: ] -def get_cells(bloqdoc: BloqDocSpec) -> List[_Cell]: - cells: List[_Cell] = [] +def get_cells(bloqdoc: BloqDocSpec) -> list[_Cell]: + cells: list[_Cell] = [] cid_prefix = f'{bloqdoc.bloq_cls.__name__}' cells += get_bloq_doc_cells(bloqdoc, cid_prefix) cells += get_example_instances_cells(bloqdoc, cid_prefix) @@ -261,7 +261,7 @@ def _cell_to_nbnode(cell: _Cell) -> nbformat.NotebookNode: raise ValueError() -def _get_title_lines(title: str, mod: ModuleType) -> List[str]: +def _get_title_lines(title: str, mod: ModuleType) -> list[str]: """Return markdown lines for the title cell. This consists of the specified title as well as the associated module's docstring. @@ -278,7 +278,7 @@ def _get_title_lines(title: str, mod: ModuleType) -> List[str]: def _init_notebook( path_stem: str, overwrite=False, directory: str = '.' -) -> Tuple[nbformat.NotebookNode, Path]: +) -> tuple[nbformat.NotebookNode, Path]: """Initialize a jupyter notebook. If one already exists: load it in. Otherwise, create a new one. @@ -404,7 +404,7 @@ def render_notebook(nbspec: NotebookSpecV2) -> None: # 3. Merge rendered cells into the existing notebook. # -> we use the cells metadata field to match up cells. - cqids_to_render: List[str] = list(cells.keys()) + cqids_to_render: list[str] = list(cells.keys()) for i in range(len(nb.cells)): nb_node = nb.cells[i] if _K_CQ_AUTOGEN in nb_node.metadata: diff --git a/dev_tools/qualtran_dev_tools/notebook_execution.py b/dev_tools/qualtran_dev_tools/notebook_execution.py index 52a7cfbc5d..d6b344fb14 100644 --- a/dev_tools/qualtran_dev_tools/notebook_execution.py +++ b/dev_tools/qualtran_dev_tools/notebook_execution.py @@ -16,7 +16,7 @@ import subprocess import sys from pathlib import Path -from typing import List, Optional, Tuple +from typing import Optional import filelock import nbconvert @@ -28,7 +28,7 @@ from .git_tools import get_git_root -def get_nb_rel_paths(sourceroot: Path) -> List[Path]: +def get_nb_rel_paths(sourceroot: Path) -> list[Path]: """List all checked-in *.ipynb files within `sourceroot`.""" cp = subprocess.run( ['git', 'ls-files', '*.ipynb'], @@ -97,7 +97,7 @@ def needs_reexport(self): return self.html_needs_reexport() or self.nb_needs_reexport() -def _make_link_replacements() -> List[Tuple[str, str]]: +def _make_link_replacements() -> list[tuple[str, str]]: """Helper function to make a list of link replacements.""" top_level = [ 'Bloq', @@ -188,7 +188,7 @@ def __init__(self, reporoot: Path, output_nbs: bool, output_html: bool, only_out self.output_html = output_html self.only_out_of_date = only_out_of_date - def __call__(self, nb_rel_path: Path) -> Tuple[Path, Optional[Exception]]: + def __call__(self, nb_rel_path: Path) -> tuple[Path, Optional[Exception]]: paths = _NBInOutPaths.from_nb_rel_path( nb_rel_path, self.reporoot, output_html=self.output_html, output_nbs=self.output_nbs ) diff --git a/dev_tools/qualtran_dev_tools/notebook_specs.py b/dev_tools/qualtran_dev_tools/notebook_specs.py index eb2c113c2b..ae5fc9ad8e 100644 --- a/dev_tools/qualtran_dev_tools/notebook_specs.py +++ b/dev_tools/qualtran_dev_tools/notebook_specs.py @@ -27,8 +27,6 @@ 3. Update the `NotebookSpec` `bloq_specs` field to include the `BloqDocSpec` for your new bloq. """ -from typing import List - from qualtran_dev_tools.git_tools import get_git_root import qualtran.bloqs.arithmetic.addition @@ -144,7 +142,7 @@ # -------------------------------------------------------------------------- # ----- Basic Gates ---------------------------------------------------- # -------------------------------------------------------------------------- -BASIC_GATES: List[NotebookSpecV2] = [ +BASIC_GATES: list[NotebookSpecV2] = [ NotebookSpecV2( title='T Gate', module=qualtran.bloqs.basic_gates.t_gate, @@ -270,7 +268,7 @@ # -------------------------------------------------------------------------- # ----- Chemistry ------------------------------------------------------ # -------------------------------------------------------------------------- -CHEMISTRY: List[NotebookSpecV2] = [ +CHEMISTRY: list[NotebookSpecV2] = [ NotebookSpecV2( title='Sparse', module=qualtran.bloqs.chemistry.sparse, @@ -769,7 +767,7 @@ # -------------------------------------------------------------------------- # ----- Block Encoding ---------------------------------------------------------- # -------------------------------------------------------------------------- -BLOCK_ENCODING: List[NotebookSpecV2] = [ +BLOCK_ENCODING: list[NotebookSpecV2] = [ NotebookSpecV2( title='Block Encoding Interface', module=qualtran.bloqs.block_encoding, @@ -837,7 +835,7 @@ # -------------------------------------------------------------------------- # ----- Optimization --------------------------------------------------- # -------------------------------------------------------------------------- -OPTIMIZATION: List[NotebookSpecV2] = [ +OPTIMIZATION: list[NotebookSpecV2] = [ NotebookSpecV2( title='Planted Noisy kXOR - Kikuchi Guiding State', module=qualtran.bloqs.optimization.k_xor_sat.kikuchi_guiding_state, @@ -851,7 +849,7 @@ # -------------------------------------------------------------------------- # ----- Other ---------------------------------------------------------- # -------------------------------------------------------------------------- -OTHER: List[NotebookSpecV2] = [ +OTHER: list[NotebookSpecV2] = [ NotebookSpecV2( title='Prepare Uniform Superposition', module=qualtran.bloqs.state_preparation.prepare_uniform_superposition, diff --git a/dev_tools/qualtran_dev_tools/parse_docstrings.py b/dev_tools/qualtran_dev_tools/parse_docstrings.py index b296c64193..fdb675eb38 100644 --- a/dev_tools/qualtran_dev_tools/parse_docstrings.py +++ b/dev_tools/qualtran_dev_tools/parse_docstrings.py @@ -14,7 +14,7 @@ import inspect import re -from typing import List, Type, Union +from typing import Union from attrs import frozen from sphinx.ext.napoleon import Config, GoogleDocstring @@ -63,14 +63,14 @@ class _GoogleDocstringToMarkdown(GoogleDocstring): """Subclass of sphinx's parser to emit Markdown from Google-style docstrings.""" def __init__(self, *args, **kwargs): - self.references: List[ReferenceT] = [] + self.references: list[ReferenceT] = [] super().__init__(*args, **kwargs) def _load_custom_sections(self) -> None: super()._load_custom_sections() self._sections['registers'] = self._parse_registers_section - def _parse_parameters_section(self, section: str) -> List[str]: + def _parse_parameters_section(self, section: str) -> list[str]: """Sphinx method to emit a 'Parameters' section.""" def _template(name, desc_lines): @@ -83,7 +83,7 @@ def _template(name, desc_lines): '', ] - def _parse_references_section(self, section: str) -> List[str]: + def _parse_references_section(self, section: str) -> list[str]: """Sphinx method to emit a 'References' section.""" lines = self._dedent(self._consume_to_next_section()) @@ -97,7 +97,7 @@ def _parse_references_section(self, section: str) -> List[str]: self.references.extend(my_refs) return ['#### References', '\n'.join(f' - {ref.text}' for ref in my_refs), ''] - def _parse_registers_section(self, section: str) -> List[str]: + def _parse_registers_section(self, section: str) -> list[str]: def _template(name, desc_lines): desc = ' '.join(desc_lines) return f' - `{name}`: {desc}' @@ -109,7 +109,7 @@ def _template(name, desc_lines): ] -def get_markdown_docstring(cls: Type) -> List[str]: +def get_markdown_docstring(cls: type) -> list[str]: """From a class `cls`, return its docstring as Markdown lines.""" # 1. Sphinx incantation @@ -123,7 +123,7 @@ def get_markdown_docstring(cls: Type) -> List[str]: return lines -def get_markdown_docstring_lines(cls: Type) -> List[str]: +def get_markdown_docstring_lines(cls: type) -> list[str]: """From a class `cls`, return its docstring as Markdown lines with a header.""" # 1. Get documentation lines @@ -135,7 +135,7 @@ def get_markdown_docstring_lines(cls: Type) -> List[str]: return lines -def get_references(cls: Type) -> List[ReferenceT]: +def get_references(cls: type) -> list[ReferenceT]: """Get reference information for a class from the References section of its docstring.""" config = Config() docstring = cls.__doc__ if cls.__doc__ else "" diff --git a/dev_tools/qualtran_dev_tools/prepared_env.py b/dev_tools/qualtran_dev_tools/prepared_env.py index 8dfa56b257..3dff97fc5f 100644 --- a/dev_tools/qualtran_dev_tools/prepared_env.py +++ b/dev_tools/qualtran_dev_tools/prepared_env.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import List, Optional +from typing import Optional from . import shell_tools @@ -47,11 +47,11 @@ def __init__( self.destination_directory = destination_directory - def get_changed_files(self) -> List[str]: + def get_changed_files(self) -> list[str]: """Get the files changed on one git branch vs another. Returns: - List[str]: File paths of changed files, relative to the git repo + list[str]: File paths of changed files, relative to the git repo root. """ optional_actual_commit_id = [] if self.actual_commit_id is None else [self.actual_commit_id] diff --git a/dev_tools/qualtran_dev_tools/reference_docs.py b/dev_tools/qualtran_dev_tools/reference_docs.py index a0a6d59a44..e792355c9b 100644 --- a/dev_tools/qualtran_dev_tools/reference_docs.py +++ b/dev_tools/qualtran_dev_tools/reference_docs.py @@ -14,8 +14,8 @@ import re from collections import defaultdict +from collections.abc import Iterable from pathlib import Path -from typing import Dict, Iterable, List, Type import jinja2 import tensorflow_docs.api_generator.parser @@ -65,7 +65,7 @@ def filter_type_aliases_in_the_wrong_place(path, parent, children): return ret -def _filter_and_sort_members(py_object: object, members: Iterable[MemberInfo]) -> List[MemberInfo]: +def _filter_and_sort_members(py_object: object, members: Iterable[MemberInfo]) -> list[MemberInfo]: """Sort `members` according to their order in the source definition. For example: you can order class methods according to their order of definition @@ -79,7 +79,7 @@ def _filter_and_sort_members(py_object: object, members: Iterable[MemberInfo]) - return sorted(fmembs, key=lambda m: ordering[m.short_name]) -def mixin_custom_template(template_name: str) -> Type: +def mixin_custom_template(template_name: str) -> type: """Return a mixin for using a custom jinja template in TemplatePageBuilder classes.""" class _CustomTemplateMixin: @@ -382,7 +382,7 @@ def generate_ref_toc(reporoot: Path): page_paths = output_dir.glob('qualtran/**/*.md') # Group according to module - grouped_paths: Dict[Path, List] = defaultdict(list) + grouped_paths: dict[Path, list] = defaultdict(list) for path in page_paths: grouped_paths[path.parent].append(path) diff --git a/dev_tools/qualtran_dev_tools/shell_tools.py b/dev_tools/qualtran_dev_tools/shell_tools.py index ef02ed8e05..79a4efb5b0 100644 --- a/dev_tools/qualtran_dev_tools/shell_tools.py +++ b/dev_tools/qualtran_dev_tools/shell_tools.py @@ -14,7 +14,7 @@ import subprocess import sys -from typing import List, Tuple, Union +from typing import Union BOLD = 1 DIM = 2 @@ -37,7 +37,7 @@ def highlight(text: str, color_code: int, bold: bool = False) -> str: return "{}\033[{}m{}\033[0m".format("\033[1m" if bold else "", color_code, text) -def abbreviate_command_arguments_after_switches(cmd: Tuple[str, ...]) -> Tuple[str, ...]: +def abbreviate_command_arguments_after_switches(cmd: tuple[str, ...]) -> tuple[str, ...]: result = [cmd[0]] for i in range(1, len(cmd)): if not cmd[i].startswith("-"): @@ -48,7 +48,7 @@ def abbreviate_command_arguments_after_switches(cmd: Tuple[str, ...]) -> Tuple[s def run( - args: Union[str, List[str]], + args: Union[str, list[str]], *, log_run_to_stderr: bool = True, abbreviate_non_option_arguments: bool = False, @@ -87,14 +87,14 @@ def run( # setup our default for subprocess.run flag arguments subprocess_run_kwargs.update(check=check, text=text) if log_run_to_stderr: - cmd_desc: Tuple[str, ...] = (args,) if isinstance(args, str) else tuple(args) + cmd_desc: tuple[str, ...] = (args,) if isinstance(args, str) else tuple(args) if abbreviate_non_option_arguments: cmd_desc = abbreviate_command_arguments_after_switches(cmd_desc) print("run:", cmd_desc, file=sys.stderr) return subprocess.run(args, **subprocess_run_kwargs) # pylint: disable=subprocess-run-check -def output_of(args: Union[str, List[str]], **kwargs) -> str: +def output_of(args: Union[str, list[str]], **kwargs) -> str: """Invokes a subprocess and returns its output as a string. Args: diff --git a/dev_tools/qualtran_dev_tools/tensor_report_card.py b/dev_tools/qualtran_dev_tools/tensor_report_card.py index c2e3fa2df3..cd3284185d 100644 --- a/dev_tools/qualtran_dev_tools/tensor_report_card.py +++ b/dev_tools/qualtran_dev_tools/tensor_report_card.py @@ -13,7 +13,8 @@ # limitations under the License. import multiprocessing.connection import time -from typing import Any, Callable, Dict, List, Optional, Tuple +from collections.abc import Callable +from typing import Any, Optional from attrs import define @@ -28,7 +29,7 @@ class _Pending: p: multiprocessing.Process recv: multiprocessing.connection.Connection start_time: float - kwargs: Dict[str, Any] + kwargs: dict[str, Any] class ExecuteWithTimeout: @@ -42,15 +43,15 @@ def __init__(self, timeout: float, max_workers: int): self.timeout = timeout self.max_workers = max_workers - self.queued: List[Tuple[Callable, Dict[str, Any]]] = [] - self.pending: List[_Pending] = [] + self.queued: list[tuple[Callable, dict[str, Any]]] = [] + self.pending: list[_Pending] = [] @property def work_to_be_done(self) -> int: """The number of tasks currently executing or queued.""" return len(self.queued) + len(self.pending) - def submit(self, func: Callable, kwargs: Dict[str, Any]) -> None: + def submit(self, func: Callable, kwargs: dict[str, Any]) -> None: """Add a task to the queue. `func` must be a callable that can accept `kwargs` in addition to @@ -92,7 +93,7 @@ def _scan_pendings(self) -> Optional[_Pending]: return None - def next_result(self) -> Tuple[Dict[str, Any], Optional[Any]]: + def next_result(self) -> tuple[dict[str, Any], Optional[Any]]: """Get the next available result. This call is blocking, but should never take longer than `self.timeout`. This should @@ -131,7 +132,7 @@ def report_on_tensors(name: str, cls_name: str, bloq: Bloq, cxn) -> None: This should be used with `ExecuteWithTimeout`. The resultant record dictionary is sent over `cxn`. """ - record: Dict[str, Any] = {'name': name, 'cls': cls_name} + record: dict[str, Any] = {'name': name, 'cls': cls_name} try: start = time.perf_counter() diff --git a/qualtran/_infra/adjoint.py b/qualtran/_infra/adjoint.py index 0601a6248e..e07cea3fdf 100644 --- a/qualtran/_infra/adjoint.py +++ b/qualtran/_infra/adjoint.py @@ -14,7 +14,7 @@ from collections import Counter from functools import cached_property -from typing import Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -31,7 +31,7 @@ from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator -def _adjoint_final_soqs(cbloq: 'CompositeBloq', new_signature: Signature) -> Dict[str, 'SoquetT']: +def _adjoint_final_soqs(cbloq: 'CompositeBloq', new_signature: Signature) -> dict[str, 'SoquetT']: """`CompositeBloq.final_soqs()` but backwards.""" if LeftDangle not in cbloq._binst_graph: return {} @@ -59,7 +59,7 @@ def _adjoint_cbloq(cbloq: 'CompositeBloq') -> 'CompositeBloq': new_signature = cbloq.signature.adjoint() old_i_soqs = [_reg_to_soq(RightDangle, reg) for reg in old_signature.rights()] new_i_soqs = [_reg_to_soq(LeftDangle, reg) for reg in new_signature.lefts()] - soq_map: List[Tuple[SoquetT, SoquetT]] = list(zip(old_i_soqs, new_i_soqs)) + soq_map: list[tuple[SoquetT, SoquetT]] = list(zip(old_i_soqs, new_i_soqs)) # Then we reverse the order of subbloqs bloqnections = reversed(list(cbloq.iter_bloqnections())) @@ -175,7 +175,7 @@ def __str__(self) -> str: return f'{str(self.subbloq)}†' def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': # Note: since we pass are passed a soquet which has the 'new' side, we flip it before # delegating and then flip back. Subbloqs only have to answer this protocol diff --git a/qualtran/_infra/binst_graph_iterators.py b/qualtran/_infra/binst_graph_iterators.py index d22ebbcc5a..51105dc6e5 100644 --- a/qualtran/_infra/binst_graph_iterators.py +++ b/qualtran/_infra/binst_graph_iterators.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Iterator, TYPE_CHECKING +from collections.abc import Iterator +from typing import TYPE_CHECKING import networkx as nx diff --git a/qualtran/_infra/bloq.py b/qualtran/_infra/bloq.py index 8572718445..47ddb35b9f 100644 --- a/qualtran/_infra/bloq.py +++ b/qualtran/_infra/bloq.py @@ -16,18 +16,8 @@ """Contains the main interface for defining `Bloq`s.""" import abc -from typing import ( - Callable, - Dict, - List, - Mapping, - Optional, - Sequence, - Set, - Tuple, - TYPE_CHECKING, - Union, -) +from collections.abc import Callable, Mapping, Sequence +from typing import Optional, TYPE_CHECKING, Union if TYPE_CHECKING: import cirq @@ -129,7 +119,7 @@ def signature(self) -> 'Signature': about this bloq. """ - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: """Override this method to define a Bloq in terms of its constituent parts. Bloq authors should override this method. If you already have an instance of a `Bloq`, @@ -241,7 +231,7 @@ def basis_state_phase(self, **vals: 'ClassicalValT') -> Union[complex, None]: def call_classically( self, **vals: Union['sympy.Symbol', 'ClassicalValT'] - ) -> Tuple['ClassicalValT', ...]: + ) -> tuple['ClassicalValT', ...]: """Call this bloq on classical data. Bloq users can call this function to apply bloqs to classical data. If you're @@ -300,8 +290,8 @@ def tensor_contract(self, superoperator: bool = False) -> 'NDArray': return bloq_to_dense(self, superoperator=superoperator) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List[Union['qtn.Tensor', 'DiscardInd']]: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list[Union['qtn.Tensor', 'DiscardInd']]: """Override this method to support native quimb simulation of this Bloq. This method is responsible for returning tensors corresponding to the unitary, state, or @@ -335,7 +325,7 @@ def my_tensors( def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: """Override this method to build the bloq call graph. This method must return a set of `(bloq, n)` tuples where `bloq` is called `n` times in @@ -371,7 +361,7 @@ def call_graph( generalizer: Optional[Union['GeneralizerT', Sequence['GeneralizerT']]] = None, keep: Optional[Callable[['Bloq'], bool]] = None, max_depth: Optional[int] = None, - ) -> Tuple['nx.DiGraph', Dict['Bloq', Union[int, 'sympy.Expr']]]: + ) -> tuple['nx.DiGraph', dict['Bloq', Union[int, 'sympy.Expr']]]: """Get the bloq call graph and call totals. The call graph has edges from a parent bloq to each of the bloqs that it calls in @@ -400,7 +390,7 @@ def call_graph( def bloq_counts( self, generalizer: Optional[Union['GeneralizerT', Sequence['GeneralizerT']]] = None - ) -> Dict['Bloq', Union[int, 'sympy.Expr']]: + ) -> dict['Bloq', Union[int, 'sympy.Expr']]: """The number of subbloqs directly called by this bloq. This corresponds to one level of the call graph, see `Bloq.call_graph()`. @@ -420,7 +410,7 @@ def bloq_counts( return dict(get_bloq_callee_counts(self, generalizer=generalizer)) - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: """Get a controlled version of this bloq and a function to wire it up correctly. Users should likely call `Bloq.controlled(...)` which uses this method behind-the-scenes. @@ -441,8 +431,8 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlled It must have the following signature: def _my_add_controlled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: Which takes a bloq builder (for adding the controlled bloq), the new control soquets, input soquets for the existing registers; and returns a sequence of the output control @@ -494,7 +484,7 @@ def t_complexity(self) -> 'TComplexity': def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', **cirq_quregs: 'CirqQuregT' - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: """Override this method to support conversion to a Cirq operation. If this method is not overriden, the default implementation will wrap this bloq @@ -591,7 +581,7 @@ def on_registers( return self.on(*merge_qubits(self.signature, **qubit_regs)) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': """On a musical score visualization, use this `WireSymbol` to represent `soq`. diff --git a/qualtran/_infra/bloq_example.py b/qualtran/_infra/bloq_example.py index 18abbba75b..143c7e9266 100644 --- a/qualtran/_infra/bloq_example.py +++ b/qualtran/_infra/bloq_example.py @@ -11,8 +11,9 @@ # 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 typing -from typing import Any, Callable, Generic, Iterable, Optional, Sequence, Type, TypeVar, Union + +from collections.abc import Callable, Iterable, Sequence +from typing import Any, Generic, Optional, overload, TypeVar, Union from attrs import field, frozen @@ -44,7 +45,7 @@ class BloqExample(Generic[_BloqType]): _func: Callable[[], _BloqType] = field(repr=False, hash=False) name: str - bloq_cls: Type[Bloq] + bloq_cls: type[Bloq] generalizer: _GeneralizerType = field( converter=lambda x: tuple(x) if isinstance(x, Sequence) else x, default=lambda x: x ) @@ -68,7 +69,7 @@ def _name_from_func_name(func: Callable[[], _BloqType]) -> str: return func.__name__.lstrip('_') -def _bloq_cls_from_func_annotation(func: Callable[[], _BloqType]) -> Type[_BloqType]: +def _bloq_cls_from_func_annotation(func: Callable[[], _BloqType]) -> type[_BloqType]: """Use the function return type annotation as the `BloqExample.bloq_cls` with the decorator.""" anno = func.__annotations__ if 'return' not in anno: @@ -79,11 +80,11 @@ def _bloq_cls_from_func_annotation(func: Callable[[], _BloqType]) -> Type[_BloqT return cls -@typing.overload +@overload def bloq_example(_func: Callable[[], _BloqType], **kwargs: Any) -> BloqExample[_BloqType]: ... -@typing.overload +@overload def bloq_example( _func: None = None, *, generalizer: _GeneralizerType = lambda x: x ) -> Callable[[Callable[[], _BloqType]], BloqExample[_BloqType]]: ... @@ -147,7 +148,7 @@ class BloqDocSpec: graph. Note that this example must be included in `examples`. """ - bloq_cls: Type + bloq_cls: type examples: Sequence[BloqExample] = field(converter=_to_tuple, factory=tuple) import_line: str = field() call_graph_example: Union[BloqExample, None] = field() diff --git a/qualtran/_infra/composite_bloq.py b/qualtran/_infra/composite_bloq.py index 9832b9ffaa..fd5e59dc94 100644 --- a/qualtran/_infra/composite_bloq.py +++ b/qualtran/_infra/composite_bloq.py @@ -13,26 +13,9 @@ # limitations under the License. """Classes for building and manipulating `CompositeBloq`.""" -from collections.abc import Hashable +from collections.abc import Callable, Hashable, Iterable, Iterator, Mapping, Sequence from functools import cached_property -from typing import ( - Callable, - cast, - Dict, - FrozenSet, - Iterable, - Iterator, - List, - Mapping, - Optional, - overload, - Sequence, - Set, - Tuple, - TYPE_CHECKING, - TypeVar, - Union, -) +from typing import cast, FrozenSet, Optional, overload, TYPE_CHECKING, TypeVar, Union import attrs import networkx as nx @@ -106,7 +89,7 @@ class CompositeBloq(Bloq): should correspond to the dangling `Soquets` in the `cxns`. """ - connections: Tuple[Connection, ...] = attrs.field(converter=_to_tuple) + connections: tuple[Connection, ...] = attrs.field(converter=_to_tuple) signature: Signature bloq_instances: FrozenSet[BloqInstance] = attrs.field(converter=_to_set) @@ -142,7 +125,7 @@ def _binst_graph(self) -> nx.DiGraph: def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', **cirq_quregs: 'CirqQuregT' - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: """Return a cirq.CircuitOperation containing a cirq-exported version of this cbloq.""" import cirq @@ -153,7 +136,7 @@ def as_cirq_op( def to_cirq_circuit_and_quregs( self, qubit_manager: Optional['cirq.QubitManager'] = None, **cirq_quregs - ) -> Tuple['cirq.FrozenCircuit', Dict[str, 'CirqQuregT']]: + ) -> tuple['cirq.FrozenCircuit', dict[str, 'CirqQuregT']]: """Convert this CompositeBloq to a `cirq.Circuit` and output qubit registers. Args: @@ -214,14 +197,14 @@ def from_cirq_circuit(cls, circuit: 'cirq.Circuit') -> 'CompositeBloq': def on_classical_vals( self, **vals: Union[sympy.Symbol, 'ClassicalValT'] - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: """Support classical data by recursing into the composite bloq.""" from qualtran.simulation.classical_sim import call_cbloq_classically out_vals, _ = call_cbloq_classically(self.signature, vals, self._binst_graph) return out_vals - def call_classically(self, **vals: 'ClassicalValT') -> Tuple['ClassicalValT', ...]: + def call_classically(self, **vals: 'ClassicalValT') -> tuple['ClassicalValT', ...]: """Support classical data by recursing into the composite bloq.""" from qualtran.simulation.classical_sim import call_cbloq_classically @@ -246,7 +229,7 @@ def build_call_graph(self, ssa: Optional['SympySymbolAllocator']) -> 'BloqCountD def iter_bloqnections( self, - ) -> Iterator[Tuple[BloqInstance, List[Connection], List[Connection]]]: + ) -> Iterator[tuple[BloqInstance, list[Connection], list[Connection]]]: """Iterate over Bloqs and their connections in topological order. Yields: @@ -267,7 +250,7 @@ def iter_bloqnections( def iter_bloqsoqs( self, - ) -> Iterator[Tuple[BloqInstance, Dict[str, SoquetT], Tuple[SoquetT, ...]]]: + ) -> Iterator[tuple[BloqInstance, dict[str, SoquetT], tuple[SoquetT, ...]]]: """Iterate over bloq instances and their input soquets. This method is helpful for "adding from" this existing composite bloq. You must @@ -275,7 +258,7 @@ def iter_bloqsoqs( new bloq. >>> bb, _ = BloqBuilder.from_signature(self.signature) - >>> soq_map: List[Tuple[SoquetT, SoquetT]] = [] + >>> soq_map: list[tuple[SoquetT, SoquetT]] = [] >>> for binst, in_soqs, old_out_soqs in self.iter_bloqsoqs(): >>> in_soqs = bb.map_soqs(in_soqs, soq_map) >>> new_out_soqs = bb.add_t(binst.bloq, **in_soqs) @@ -300,7 +283,7 @@ def iter_bloqsoqs( out_soqs = tuple(_reg_to_soq(binst, reg) for reg in binst.bloq.signature.rights()) yield binst, in_soqs, out_soqs - def final_soqs(self) -> Dict[str, SoquetT]: + def final_soqs(self) -> dict[str, SoquetT]: """Return the final output soquets. This method is helpful for finalizing an "add from" operation, see `iter_bloqsoqs`. @@ -318,7 +301,7 @@ def final_soqs(self) -> Dict[str, SoquetT]: def copy(self) -> 'CompositeBloq': """Create a copy of this composite bloq by re-building it.""" bb, _ = BloqBuilder.from_signature(self.signature) - soq_map: List[Tuple[SoquetT, SoquetT]] = [] + soq_map: list[tuple[SoquetT, SoquetT]] = [] for binst, in_soqs, old_out_soqs in self.iter_bloqsoqs(): in_soqs = _map_soqs(in_soqs, soq_map) new_out_soqs = bb.add_t(binst.bloq, **in_soqs) @@ -364,8 +347,8 @@ def flatten_once( # pylint: disable=protected-access bb._i = max(binst.i for binst in self.bloq_instances) + 1 - soq_map: List[Tuple[SoquetT, SoquetT]] = [] - new_out_soqs: Tuple[SoquetT, ...] + soq_map: list[tuple[SoquetT, SoquetT]] = [] + new_out_soqs: tuple[SoquetT, ...] did_work = False for binst, in_soqs, old_out_soqs in self.iter_bloqsoqs(): in_soqs = _map_soqs(in_soqs, soq_map) # update `in_soqs` from old to new. @@ -432,7 +415,7 @@ def adjoint(self) -> 'CompositeBloq': return _adjoint_cbloq(self) @staticmethod - def _debug_binst(g: nx.DiGraph, binst: BloqInstance) -> List[str]: + def _debug_binst(g: nx.DiGraph, binst: BloqInstance) -> list[str]: """Helper method used in `debug_text`""" lines = [f'{binst}'] pred_cxns, succ_cxns = _binst_to_cxns(binst, binst_graph=g) @@ -499,13 +482,13 @@ def _create_binst_graph( def _binst_to_cxns( binst: Union[BloqInstance, DanglingT], binst_graph: nx.DiGraph -) -> Tuple[List[Connection], List[Connection]]: +) -> tuple[list[Connection], list[Connection]]: """Helper method to extract all predecessor and successor Connections for a binst.""" - pred_cxns: List[Connection] = [] + pred_cxns: list[Connection] = [] for pred in binst_graph.pred[binst]: pred_cxns.extend(binst_graph.edges[pred, binst]['cxns']) - succ_cxns: List[Connection] = [] + succ_cxns: list[Connection] = [] for succ in binst_graph.succ[binst]: succ_cxns.extend(binst_graph.edges[binst, succ]['cxns']) @@ -517,7 +500,7 @@ def _cxns_to_soq_dict( cxns: Iterable[Connection], get_me: Callable[[Connection], Soquet], get_assign: Callable[[Connection], Soquet], -) -> Dict[str, SoquetT]: +) -> dict[str, SoquetT]: """Helper function to get a dictionary of soquets from a list of connections. Args: @@ -534,7 +517,7 @@ def _cxns_to_soq_dict( Returns: soqdict: A dictionary mapping register name to the selected soquets. """ - soqdict: Dict[str, SoquetT] = {} + soqdict: dict[str, SoquetT] = {} # Initialize multi-dimensional dictionary values. for reg in regs: @@ -557,7 +540,7 @@ def _cxns_to_soq_dict( def _cxns_to_cxn_dict( regs: Iterable[Register], cxns: Iterable[Connection], get_me: Callable[[Connection], Soquet] -) -> Dict[str, ConnectionT]: +) -> dict[str, ConnectionT]: """Helper function to get a dictionary of connections from a list of connections Args: @@ -571,7 +554,7 @@ def _cxns_to_cxn_dict( Returns: cxndict: A dictionary mapping register name to the selected connections. """ - cxndict: Dict[str, ConnectionT] = {} + cxndict: dict[str, ConnectionT] = {} # Initialize multi-dimensional dictionary values. for reg in regs: @@ -590,7 +573,7 @@ def _cxns_to_cxn_dict( return cxndict -def _get_dangling_soquets(signature: Signature, right: bool = True) -> Dict[str, SoquetT]: +def _get_dangling_soquets(signature: Signature, right: bool = True) -> dict[str, SoquetT]: """Get instantiated dangling soquets from a `Signature`. Args: @@ -610,14 +593,14 @@ def _get_dangling_soquets(signature: Signature, right: bool = True) -> Dict[str, regs = signature.lefts() dang = LeftDangle - all_soqs: Dict[str, SoquetT] = {} + all_soqs: dict[str, SoquetT] = {} soqs: SoquetT for reg in regs: all_soqs[reg.name] = _reg_to_soq(dang, reg) return all_soqs -def _flatten_soquet_collection(vals: Iterable[SoquetT]) -> List[Soquet]: +def _flatten_soquet_collection(vals: Iterable[SoquetT]) -> list[Soquet]: """Flatten SoquetT into a flat list of Soquet. SoquetT is either a unit Soquet or an ndarray thereof. @@ -631,7 +614,7 @@ def _flatten_soquet_collection(vals: Iterable[SoquetT]) -> List[Soquet]: return soqvals -def _get_flat_dangling_soqs(signature: Signature, right: bool) -> List[Soquet]: +def _get_flat_dangling_soqs(signature: Signature, right: bool) -> list[Soquet]: """Flatten out the values of the soquet dictionaries from `_get_dangling_soquets`.""" soqdict = _get_dangling_soquets(signature, right=right) return _flatten_soquet_collection(soqdict.values()) @@ -660,7 +643,7 @@ def add(self, x: Hashable): def _reg_to_soq( binst: Union[BloqInstance, DanglingT], reg: Register, - available: Union[Set[Soquet], _IgnoreAvailable] = _IgnoreAvailable(), + available: Union[set[Soquet], _IgnoreAvailable] = _IgnoreAvailable(), ) -> SoquetT: """Create the soquet or array of soquets for a register. @@ -696,7 +679,7 @@ def _process_soquets( registers: Iterable[Register], in_soqs: Mapping[str, SoquetInT], debug_str: str, - func: Callable[[Soquet, Register, Tuple[int, ...]], None], + func: Callable[[Soquet, Register, tuple[int, ...]], None], ) -> None: """Process and validate `in_soqs` in the context of `registers`. @@ -719,7 +702,7 @@ def _process_soquets( the incoming, indexed soquet as well as the register and (left-)index it has been mapped to. """ - unchecked_names: Set[str] = set(in_soqs.keys()) + unchecked_names: set[str] = set(in_soqs.keys()) for reg in registers: try: # if we want fancy indexing (which we do), we need numpy @@ -746,8 +729,8 @@ def _process_soquets( def _map_soqs( - soqs: Dict[str, SoquetT], soq_map: Iterable[Tuple[SoquetT, SoquetT]] -) -> Dict[str, SoquetT]: + soqs: dict[str, SoquetT], soq_map: Iterable[tuple[SoquetT, SoquetT]] +) -> dict[str, SoquetT]: """Map `soqs` according to `soq_map`. See `CompositeBloq.iter_bloqsoqs` for example code. The public entry-point @@ -765,7 +748,7 @@ def _map_soqs( """ # First: flatten out any numpy arrays - flat_soq_map: Dict[Soquet, Soquet] = {} + flat_soq_map: dict[Soquet, Soquet] = {} for old_soqs, new_soqs in soq_map: if isinstance(old_soqs, Soquet): assert isinstance(new_soqs, Soquet), new_soqs @@ -818,15 +801,15 @@ class BloqBuilder: def __init__(self, add_registers_allowed: bool = True): # To be appended to: - self._cxns: List[Connection] = [] - self._regs: List[Register] = [] - self._binsts: Set[BloqInstance] = set() + self._cxns: list[Connection] = [] + self._regs: list[Register] = [] + self._binsts: set[BloqInstance] = set() # Initialize our BloqInstance counter self._i = 0 # Bookkeeping for linear types; Soquets must be used exactly once. - self._available: Set[Soquet] = set() + self._available: set[Soquet] = set() # Whether we can call `add_register` and do non-strict `finalize()`. self.add_register_allowed = add_registers_allowed @@ -926,7 +909,7 @@ def add_register( @classmethod def from_signature( cls, signature: Signature, add_registers_allowed: bool = False - ) -> Tuple['BloqBuilder', Dict[str, SoquetT]]: + ) -> tuple['BloqBuilder', dict[str, SoquetT]]: """Construct a BloqBuilder with a pre-specified signature. This is safer if e.g. you're decomposing an existing Bloq and need the signatures @@ -935,7 +918,7 @@ def from_signature( # Initial construction: allow register addition for the following loop. bb = cls(add_registers_allowed=True) - initial_soqs: Dict[str, SoquetT] = {} + initial_soqs: dict[str, SoquetT] = {} for reg in signature: if reg.side & Side.LEFT: register = bb.add_register_from_dtype(reg) @@ -951,8 +934,8 @@ def from_signature( @staticmethod def map_soqs( - soqs: Dict[str, SoquetT], soq_map: Iterable[Tuple[SoquetT, SoquetT]] - ) -> Dict[str, SoquetT]: + soqs: dict[str, SoquetT], soq_map: Iterable[tuple[SoquetT, SoquetT]] + ) -> dict[str, SoquetT]: """Map `soqs` according to `soq_map`. See `CompositeBloq.iter_bloqsoqs` for example code. @@ -979,7 +962,7 @@ def _add_cxn( binst: Union[BloqInstance, DanglingT], idxed_soq: Soquet, reg: Register, - idx: Tuple[int, ...], + idx: tuple[int, ...], ) -> None: """Helper function to be used as the base for the `func` argument of `_process_soquets`. @@ -996,7 +979,7 @@ def _add_cxn( cxn = Connection(idxed_soq, Soquet(binst, reg, idx)) self._cxns.append(cxn) - def add_t(self, bloq: Bloq, **in_soqs: SoquetInT) -> Tuple[SoquetT, ...]: + def add_t(self, bloq: Bloq, **in_soqs: SoquetInT) -> tuple[SoquetT, ...]: """Add a new bloq instance to the compute graph and always return a tuple of soquets. This method will always return a tuple of soquets. See `BloqBuilder.add_d(..)` for a @@ -1018,7 +1001,7 @@ def add_t(self, bloq: Bloq, **in_soqs: SoquetInT) -> Tuple[SoquetT, ...]: binst = BloqInstance(bloq, i=self._new_binst_i()) return tuple(soq for _, soq in self._add_binst(binst, in_soqs=in_soqs)) - def add_d(self, bloq: Bloq, **in_soqs: SoquetInT) -> Dict[str, SoquetT]: + def add_d(self, bloq: Bloq, **in_soqs: SoquetInT) -> dict[str, SoquetT]: """Add a new bloq instance to the compute graph and return new soquets as a dictionary. This method returns a dictionary of soquets. See `BloqBuilder.add_t(..)` for a method @@ -1040,7 +1023,7 @@ def add_d(self, bloq: Bloq, **in_soqs: SoquetInT) -> Dict[str, SoquetT]: def add_and_partition( self, bloq: Bloq, - partitions: Sequence[Tuple[Register, Sequence[Union[str, 'Unused']]]], + partitions: Sequence[tuple[Register, Sequence[Union[str, 'Unused']]]], left_only: bool = False, **in_soqs: SoquetInT, ): @@ -1103,7 +1086,7 @@ def add(self, bloq: Bloq, **in_soqs: SoquetInT): def _add_binst( self, binst: BloqInstance, in_soqs: Mapping[str, SoquetInT] - ) -> Iterator[Tuple[str, SoquetT]]: + ) -> Iterator[tuple[str, SoquetT]]: """Add a bloq instance. Warning! Do not use this function externally! Untold bad things will happen if @@ -1113,7 +1096,7 @@ def _add_binst( bloq = binst.bloq - def _add(idxed_soq: Soquet, reg: Register, idx: Tuple[int, ...]): + def _add(idxed_soq: Soquet, reg: Register, idx: tuple[int, ...]): # close over `binst` return self._add_cxn(binst, idxed_soq, reg, idx) @@ -1125,7 +1108,7 @@ def _add(idxed_soq: Soquet, reg: Register, idx: Tuple[int, ...]): for reg in bloq.signature.rights() ) - def add_from(self, bloq: Bloq, **in_soqs: SoquetInT) -> Tuple[SoquetT, ...]: + def add_from(self, bloq: Bloq, **in_soqs: SoquetInT) -> tuple[SoquetT, ...]: """Add all the sub-bloqs from `bloq` to the composite bloq under construction. Args: @@ -1146,7 +1129,7 @@ def add_from(self, bloq: Bloq, **in_soqs: SoquetInT) -> Tuple[SoquetT, ...]: in_soqs[k] = np.asarray(v) # Initial mapping of LeftDangle according to user-provided in_soqs. - soq_map: List[Tuple[SoquetT, SoquetT]] = [ + soq_map: list[tuple[SoquetT, SoquetT]] = [ (_reg_to_soq(LeftDangle, reg), cast(SoquetT, in_soqs[reg.name])) for reg in cbloq.signature.lefts() ] @@ -1207,7 +1190,7 @@ def _finalize_strict(self, **final_soqs: SoquetT) -> CompositeBloq: """ signature = Signature(self._regs) - def _fin(idxed_soq: Soquet, reg: Register, idx: Tuple[int, ...]): + def _fin(idxed_soq: Soquet, reg: Register, idx: tuple[int, ...]): # close over `RightDangle` return self._add_cxn(RightDangle, idxed_soq, reg, idx) diff --git a/qualtran/_infra/composite_bloq_test.py b/qualtran/_infra/composite_bloq_test.py index 114b55083f..98fbe59437 100644 --- a/qualtran/_infra/composite_bloq_test.py +++ b/qualtran/_infra/composite_bloq_test.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict, List, Tuple import attrs import networkx as nx @@ -75,7 +74,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: 'BloqBuilder', q1: 'Soquet', q2: 'Soquet' - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: q1, q2 = bb.add(CNOT(), ctrl=q1, target=q2) q1, q2 = bb.add(CNOT(), ctrl=q2, target=q1) return {'q1': q1, 'q2': q2} @@ -138,7 +137,7 @@ def test_map_soqs(): bb, _ = BloqBuilder.from_signature(cbloq.signature) bb._i = 100 # pylint: disable=protected-access - soq_map: List[Tuple[SoquetT, SoquetT]] = [] + soq_map: list[tuple[SoquetT, SoquetT]] = [] for binst, in_soqs, old_out_soqs in cbloq.iter_bloqsoqs(): if binst.i == 0: assert in_soqs == bb.map_soqs(in_soqs, soq_map) @@ -339,7 +338,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: 'BloqBuilder', control: 'Soquet', target: NDArray['Soquet'] # type: ignore[type-var] - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: for i in range(2): for j in range(3): control, target[i, j] = bb.add(CNOT(), ctrl=control, target=target[i, j]) diff --git a/qualtran/_infra/controlled.py b/qualtran/_infra/controlled.py index 0e99500728..1711e8f28f 100644 --- a/qualtran/_infra/controlled.py +++ b/qualtran/_infra/controlled.py @@ -13,21 +13,9 @@ # limitations under the License. import abc from collections import Counter +from collections.abc import Iterable, Mapping, Sequence from functools import cached_property -from typing import ( - Any, - Dict, - Iterable, - List, - Mapping, - Optional, - Protocol, - Sequence, - Tuple, - TYPE_CHECKING, - TypeAlias, - Union, -) +from typing import Any, Optional, Protocol, TYPE_CHECKING, TypeAlias, Union import attrs import numpy as np @@ -63,7 +51,7 @@ def _cvs_convert( Sequence[Sequence[Union[int, np.integer]]], Sequence[Union[NDArray[np.integer], Shaped]], ] -) -> Tuple[Union[NDArray[np.integer], Shaped], ...]: +) -> tuple[Union[NDArray[np.integer], Shaped], ...]: if isinstance(cvs, Shaped): return (cvs,) if isinstance(cvs, (int, np.integer)): @@ -118,10 +106,10 @@ class CtrlSpec: of the ctrl register is implied to be `cv.shape`). """ - qdtypes: Tuple[QCDType, ...] = attrs.field( + qdtypes: tuple[QCDType, ...] = attrs.field( default=QBit(), converter=lambda qt: (qt,) if isinstance(qt, QCDType) else tuple(qt) ) - cvs: Tuple[Union[NDArray[np.integer], Shaped], ...] = attrs.field( + cvs: tuple[Union[NDArray[np.integer], Shaped], ...] = attrs.field( default=1, converter=_cvs_convert ) @@ -133,7 +121,7 @@ def num_ctrl_reg(self) -> int: return len(self.qdtypes) @cached_property - def shapes(self) -> Tuple[Tuple[SymbolicInt, ...], ...]: + def shapes(self) -> tuple[tuple[SymbolicInt, ...], ...]: """Tuple of shapes of control registers represented by this CtrlSpec.""" return tuple(cv.shape for cv in self.cvs) @@ -165,7 +153,7 @@ def num_cbits(self) -> SymbolicInt: def is_symbolic(self): return is_symbolic(*self.qdtypes) or is_symbolic(*self.cvs) - def activation_function_dtypes(self) -> Sequence[Tuple[QCDType, Tuple[SymbolicInt, ...]]]: + def activation_function_dtypes(self) -> Sequence[tuple[QCDType, tuple[SymbolicInt, ...]]]: """The data types that serve as input to the 'activation function'. The activation function takes in (quantum) inputs of these types and shapes and determines @@ -209,7 +197,7 @@ def is_active(self, *vals: 'ClassicalValT') -> bool: return False return True - def wire_symbol(self, i: int, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, i: int, reg: Register, idx: tuple[int, ...] = tuple()) -> 'WireSymbol': from qualtran.drawing import Circle, TextBox cvs = self.cvs[i] @@ -226,7 +214,7 @@ def wire_symbol(self, i: int, reg: Register, idx: Tuple[int, ...] = tuple()) -> return TextBox(f'{cv}') @cached_property - def __cvs_tuple(self) -> Tuple[Union[tuple[int, ...], Shaped], ...]: + def __cvs_tuple(self) -> tuple[Union[tuple[int, ...], Shaped], ...]: """Serialize the control values for hashing and equality checking.""" def _serialize(cvs) -> Union[tuple[int, ...], Shaped]: @@ -273,7 +261,7 @@ def from_cirq_cv( cirq_cv: 'cirq.ops.AbstractControlValues', *, qdtypes: Optional[Sequence[QCDType]] = None, - shapes: Optional[Sequence[Tuple[int, ...]]] = None, + shapes: Optional[Sequence[tuple[int, ...]]] = None, ) -> 'CtrlSpec': """Construct a CtrlSpec from cirq.SumOfProducts representation of control values.""" conjunctions = [*cirq_cv.expand()] @@ -336,11 +324,11 @@ class AddControlledT(Protocol): """ def __call__( - self, bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: ... + self, bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: ... -def _get_nice_ctrl_reg_names(reg_names: List[str], n: int) -> Tuple[str, ...]: +def _get_nice_ctrl_reg_names(reg_names: list[str], n: int) -> tuple[str, ...]: """Get `n` names for the ctrl registers that don't overlap with (existing) `reg_names`.""" if n == 1 and 'ctrl' not in reg_names: # Special case for nicer register name if we just have one control register @@ -351,7 +339,7 @@ def _get_nice_ctrl_reg_names(reg_names: List[str], n: int) -> Tuple[str, ...]: i = 1 else: i = 0 - names: List[str] = [] + names: list[str] = [] while len(names) < n: while True: i += 1 @@ -386,7 +374,7 @@ def _thru_registers_only(self) -> bool: return True @staticmethod - def _make_ctrl_system(cb: '_ControlledBase') -> Tuple['_ControlledBase', 'AddControlledT']: + def _make_ctrl_system(cb: '_ControlledBase') -> tuple['_ControlledBase', 'AddControlledT']: """A static method to create the adder function from an implementation of this class. Classes implementing this interface can use this static method to create a factory @@ -397,8 +385,8 @@ class method to construct both the controlled bloq and its adder function. ctrl_reg_names = cb.ctrl_reg_names def add_controlled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: in_soqs |= dict(zip(ctrl_reg_names, ctrl_soqs)) new_out_d = bb.add_d(cb, **in_soqs) @@ -421,7 +409,7 @@ def ctrl_reg_names(self) -> Sequence[str]: return _get_nice_ctrl_reg_names(reg_names, n) @cached_property - def ctrl_regs(self) -> Tuple[Register, ...]: + def ctrl_regs(self) -> tuple[Register, ...]: return tuple( Register(name=self.ctrl_reg_names[i], dtype=qdtype, shape=shape, side=Side.THRU) for i, (qdtype, shape) in enumerate(self.ctrl_spec.activation_function_dtypes()) @@ -517,8 +505,8 @@ def _unitary_(self): raise ValueError(f"Cannot handle non-thru registers in {self}.") def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn from qualtran.simulation.tensor._dense import _order_incoming_outgoing_indices @@ -529,7 +517,7 @@ def my_tensors( data = self._tensor_data().reshape((2,) * len(inds)) return [qtn.Tensor(data=data, inds=inds, tags=[str(self)])] - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': from qualtran.drawing import Text if reg is None: @@ -549,7 +537,7 @@ def __str__(self) -> str: def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', **cirq_quregs: 'CirqQuregT' - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: ctrl_regs = {reg_name: cirq_quregs.pop(reg_name) for reg_name in self.ctrl_reg_names} ctrl_qubits = [q for reg in ctrl_regs.values() for q in reg.reshape(-1)] sub_op, cirq_quregs = self.subbloq.as_cirq_op(qubit_manager, **cirq_quregs) @@ -611,7 +599,7 @@ def __attrs_post_init__(self): @classmethod def make_ctrl_system( cls, bloq: 'Bloq', ctrl_spec: 'CtrlSpec' - ) -> Tuple['_ControlledBase', 'AddControlledT']: + ) -> tuple['_ControlledBase', 'AddControlledT']: """A factory method for creating both the Controlled and the adder function. See `Bloq.get_ctrl_system`. @@ -624,7 +612,7 @@ def decompose_bloq(self) -> 'CompositeBloq': def build_composite_bloq( self, bb: 'BloqBuilder', **initial_soqs: 'SoquetT' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if not self._thru_registers_only: raise DecomposeTypeError(f"Cannot handle non-thru registers in {self.subbloq}") @@ -636,9 +624,9 @@ def build_composite_bloq( else: cbloq = self.subbloq.decompose_bloq() - ctrl_soqs: List['SoquetT'] = [initial_soqs[creg_name] for creg_name in self.ctrl_reg_names] + ctrl_soqs: list['SoquetT'] = [initial_soqs[creg_name] for creg_name in self.ctrl_reg_names] - soq_map: List[Tuple[SoquetT, SoquetT]] = [] + soq_map: list[tuple[SoquetT, SoquetT]] = [] for binst, in_soqs, old_out_soqs in cbloq.iter_bloqsoqs(): in_soqs = bb.map_soqs(in_soqs, soq_map) new_bloq, adder = binst.bloq.get_ctrl_system(self.ctrl_spec) @@ -676,7 +664,7 @@ def adjoint(self) -> 'Bloq': def make_ctrl_system_with_correct_metabloq( bloq: 'Bloq', ctrl_spec: 'CtrlSpec' -) -> Tuple['_ControlledBase', 'AddControlledT']: +) -> tuple['_ControlledBase', 'AddControlledT']: """The default fallback for `Bloq.make_ctrl_system. This intelligently selects the correct implemetation of `_ControlledBase` based diff --git a/qualtran/_infra/controlled_test.py b/qualtran/_infra/controlled_test.py index 0a909d79ef..e9bb43b0b4 100644 --- a/qualtran/_infra/controlled_test.py +++ b/qualtran/_infra/controlled_test.py @@ -11,7 +11,7 @@ # 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 typing import List, TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np import pytest @@ -317,7 +317,7 @@ def test_bit_vector_ctrl(): bloq = Controlled(subbloq=TestAtom(), ctrl_spec=CtrlSpec(QBit(), cvs=(1, 0, 1))) msd = get_musical_score_data(bloq) # select SoqData for the 0th moment, sorted top to bottom - soqdatas: List[SoqData] = sorted( + soqdatas: list[SoqData] = sorted( (sd for sd in msd.soqs if sd.rpos.seq_x == 0), key=lambda sd: sd.rpos.y ) diff --git a/qualtran/_infra/data_types.py b/qualtran/_infra/data_types.py index 1b12cd1371..01e97167f8 100644 --- a/qualtran/_infra/data_types.py +++ b/qualtran/_infra/data_types.py @@ -15,9 +15,10 @@ import abc +from collections.abc import Iterable, Sequence from enum import Enum from functools import cached_property -from typing import Any, Iterable, List, Optional, Sequence, Union +from typing import Any, Optional, Union import attrs import galois @@ -51,7 +52,7 @@ def get_classical_domain(self) -> Iterable[Any]: by this type.""" @abc.abstractmethod - def to_bits(self, x) -> List[int]: + def to_bits(self, x) -> list[int]: """Yields individual bits corresponding to binary representation of x""" def to_bits_array(self, x_array: NDArray[Any]) -> NDArray[np.uint8]: @@ -165,7 +166,7 @@ def assert_valid_classical_val(self, val: int, debug_str: str = 'val'): def is_symbolic(self) -> bool: return False - def to_bits(self, x) -> List[int]: + def to_bits(self, x) -> list[int]: """Yields individual bits corresponding to binary representation of x""" self.assert_valid_classical_val(x) return [int(x)] @@ -223,7 +224,7 @@ def num_qubits(self): def get_classical_domain(self) -> Iterable[Any]: raise TypeError(f"Ambiguous domain for {self}. Please use a more specific type.") - def to_bits(self, x) -> List[int]: + def to_bits(self, x) -> list[int]: # TODO: Raise an error once usage of `QAny` is minimized across the library return QUInt(self.bitsize).to_bits(x) @@ -267,7 +268,7 @@ def get_classical_domain(self) -> Iterable[int]: max_val = 1 << (self.bitsize - 1) return range(-max_val, max_val) - def to_bits(self, x: int) -> List[int]: + def to_bits(self, x: int) -> list[int]: """Yields individual bits corresponding to binary representation of x""" if is_symbolic(self.bitsize): raise ValueError(f"cannot compute bits with symbolic {self.bitsize=}") @@ -333,7 +334,7 @@ def num_qubits(self): def is_symbolic(self) -> bool: return is_symbolic(self.bitsize) - def to_bits(self, x: int) -> List[int]: + def to_bits(self, x: int) -> list[int]: """Yields individual bits corresponding to binary representation of x""" self.assert_valid_classical_val(x) return [int(x < 0)] + [y ^ int(x < 0) for y in QUInt(self.bitsize - 1).to_bits(abs(x))] @@ -383,7 +384,7 @@ def is_symbolic(self) -> bool: def get_classical_domain(self) -> Iterable[Any]: return range(2**self.bitsize) - def to_bits(self, x: int) -> List[int]: + def to_bits(self, x: int) -> list[int]: """Yields individual bits corresponding to binary representation of x""" self.assert_valid_classical_val(x) return [int(x) for x in f'{int(x):0{self.bitsize}b}'] @@ -536,7 +537,7 @@ def assert_valid_classical_val(self, val: int, debug_str: str = 'val'): if val >= self.iteration_length: raise ValueError(f"Too-large classical value encountered in {debug_str}") - def to_bits(self, x: int) -> List[int]: + def to_bits(self, x: int) -> list[int]: """Yields individual bits corresponding to binary representation of x""" self.assert_valid_classical_val(x, debug_str='val') return QUInt(self.bitsize).to_bits(x) @@ -640,7 +641,7 @@ def get_classical_domain(self) -> Iterable[int]: """ yield from self._int_qdtype.get_classical_domain() - def to_bits(self, x) -> List[int]: + def to_bits(self, x) -> list[int]: """Use the underlying raw integer type. See class docstring section on "Classical Simulation" for more details. @@ -750,7 +751,7 @@ def _get_classical_domain_fxp(self) -> Iterable[Fxp]: def _fxp_to_bits( self, x: Union[float, Fxp], require_exact: bool = True, complement: bool = True - ) -> List[int]: + ) -> list[int]: """Yields individual bits corresponding to binary representation of `x`. Args: @@ -837,7 +838,7 @@ def get_classical_domain(self) -> Iterable[Any]: return range(2**self.bitsize) return range(1, int(self.modulus)) - def to_bits(self, x: int) -> List[int]: + def to_bits(self, x: int) -> list[int]: self.assert_valid_classical_val(x) return [int(x) for x in f'{int(x):0{self.bitsize}b}'] @@ -997,7 +998,7 @@ def gf_type(self): compile='python-calculate', ) - def to_bits(self, x) -> List[int]: + def to_bits(self, x) -> list[int]: """Returns individual bits corresponding to binary representation of x""" self.assert_valid_classical_val(x) return self._quint_equivalent.to_bits(int(x)) @@ -1117,7 +1118,7 @@ def from_gf_coefficients(self, f_x: galois.Array) -> galois.Poly: """Expects a big-endian array of coefficients that represent a polynomial f(x).""" return galois.Poly(f_x, field=self.qgf.gf_type) - def to_bits(self, x) -> List[int]: + def to_bits(self, x) -> list[int]: """Returns individual bits corresponding to binary representation of x""" self.assert_valid_classical_val(x) assert isinstance(x, galois.Poly) diff --git a/qualtran/_infra/data_types_test.py b/qualtran/_infra/data_types_test.py index 577ab9a524..f3be9e0c39 100644 --- a/qualtran/_infra/data_types_test.py +++ b/qualtran/_infra/data_types_test.py @@ -13,7 +13,8 @@ # limitations under the License. import math import random -from typing import Any, Sequence, Union +from collections.abc import Sequence +from typing import Any, Union import galois import numpy as np diff --git a/qualtran/_infra/gate_with_registers.py b/qualtran/_infra/gate_with_registers.py index 99026c66a1..a1c7da50d4 100644 --- a/qualtran/_infra/gate_with_registers.py +++ b/qualtran/_infra/gate_with_registers.py @@ -13,19 +13,8 @@ # limitations under the License. import abc -from typing import ( - cast, - Collection, - Dict, - Iterable, - List, - Optional, - overload, - Sequence, - Tuple, - TYPE_CHECKING, - Union, -) +from collections.abc import Collection, Iterable, Sequence +from typing import cast, Optional, overload, TYPE_CHECKING, Union import cirq import numpy as np @@ -50,7 +39,7 @@ def total_bits(registers: Iterable[Register]) -> int: def split_qubits( registers: Iterable[Register], qubits: Sequence['cirq.Qid'] -) -> Dict[str, NDArray['cirq.Qid']]: # type: ignore[type-var] +) -> dict[str, NDArray['cirq.Qid']]: # type: ignore[type-var] """Splits the flat list of qubits into a dictionary of appropriately shaped qubit arrays.""" qubit_regs = {} @@ -66,10 +55,10 @@ def split_qubits( def merge_qubits( registers: Iterable[Register], **qubit_regs: Union['cirq.Qid', Sequence['cirq.Qid'], NDArray['cirq.Qid']], -) -> List['cirq.Qid']: +) -> list['cirq.Qid']: """Merges the dictionary of appropriately shaped qubit arrays into a flat list of qubits.""" - ret: List['cirq.Qid'] = [] + ret: list['cirq.Qid'] = [] for reg in registers: if reg.name not in qubit_regs: raise ValueError(f"All qubit registers must be present. {reg.name} not in qubit_regs") @@ -84,7 +73,7 @@ def merge_qubits( return ret -def get_named_qubits(registers: Iterable[Register]) -> Dict[str, NDArray['cirq.Qid']]: +def get_named_qubits(registers: Iterable[Register]) -> dict[str, NDArray['cirq.Qid']]: """Returns a dictionary of appropriately shaped named qubit signature for input `signature`.""" def _qubit_array(reg: Register): @@ -115,8 +104,8 @@ def _qubits_for_reg(reg: Register): def _get_all_and_output_quregs_from_input( registers: Iterable[Register], qubit_manager: 'cirq.QubitManager', - in_quregs: Dict[str, 'CirqQuregT'], -) -> Tuple[Dict[str, 'CirqQuregT'], Dict[str, 'CirqQuregT']]: + in_quregs: dict[str, 'CirqQuregT'], +) -> tuple[dict[str, 'CirqQuregT'], dict[str, 'CirqQuregT']]: """Takes care of necessary (de-/)allocations to obtain output & all qubit registers from input. For every register `reg` in `registers`, this method checks: @@ -141,8 +130,8 @@ def _get_all_and_output_quregs_from_input( Returns: A tuple of `(all_quregs, out_quregs)` """ - all_quregs: Dict[str, 'CirqQuregT'] = {} - out_quregs: Dict[str, 'CirqQuregT'] = {} + all_quregs: dict[str, 'CirqQuregT'] = {} + out_quregs: dict[str, 'CirqQuregT'] = {} for reg in registers: full_shape = reg.shape + (reg.bitsize,) if reg.side & Side.LEFT: @@ -170,7 +159,7 @@ def _get_all_and_output_quregs_from_input( def _get_cirq_cv( num_controls: Optional[int] = None, control_values=None, - control_qid_shape: Optional[Tuple[int, ...]] = None, + control_qid_shape: Optional[tuple[int, ...]] = None, ) -> 'cirq.ops.AbstractControlValues': """Logic copied from `cirq.ControlledGate` to help convert cirq-style spec to `CtrlSpec`""" if isinstance(control_values, cirq.SumOfProducts) and len(control_values._conjunctions) == 1: @@ -294,7 +283,7 @@ def decompose_bloq(self) -> 'CompositeBloq': def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', **in_quregs: 'CirqQuregT' - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: """Allocates/Deallocates qubits for RIGHT/LEFT only registers to construct a Cirq operation Args: @@ -310,7 +299,7 @@ def as_cirq_op( ) return self.on_registers(**all_quregs), out_quregs - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': from qualtran.cirq_interop._cirq_to_bloq import _wire_symbol_from_gate from qualtran.drawing import Text @@ -378,7 +367,7 @@ def _get_ctrl_spec( cls, num_controls: Union[Optional[int], 'CtrlSpec'] = None, control_values=None, - control_qid_shape: Optional[Tuple[int, ...]] = None, + control_qid_shape: Optional[tuple[int, ...]] = None, *, ctrl_spec: Optional['CtrlSpec'] = None, ) -> 'CtrlSpec': @@ -443,7 +432,7 @@ def controlled( control_values: Optional[ Union['cirq.ops.AbstractControlValues', Sequence[Union[int, Collection[int]]]] ] = None, - control_qid_shape: Optional[Tuple[int, ...]] = None, + control_qid_shape: Optional[tuple[int, ...]] = None, ) -> 'GateWithRegisters': """Cirq-style API to construct a controlled gate. See `cirq.Gate.controlled()`""" @@ -458,7 +447,7 @@ def controlled( control_values: Optional[ Union['cirq.ops.AbstractControlValues', Sequence[Union[int, Collection[int]]]] ] = None, - control_qid_shape: Optional[Tuple[int, ...]] = None, + control_qid_shape: Optional[tuple[int, ...]] = None, *, ctrl_spec: Optional['CtrlSpec'] = None, ) -> 'Bloq': @@ -509,8 +498,8 @@ def _unitary_(self): return NotImplemented def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: if not self._unitary_.__qualname__.startswith('GateWithRegisters.'): from qualtran.cirq_interop._cirq_to_bloq import _my_tensors_from_gate diff --git a/qualtran/_infra/gate_with_registers_test.py b/qualtran/_infra/gate_with_registers_test.py index 31fd6f8635..3119c0f8d3 100644 --- a/qualtran/_infra/gate_with_registers_test.py +++ b/qualtran/_infra/gate_with_registers_test.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Iterator, TYPE_CHECKING +from collections.abc import Iterator +from typing import TYPE_CHECKING import cirq import numpy as np @@ -125,7 +126,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', l: 'SoquetT', t: 'SoquetT' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: l = bb.add(XGate(), q=l) bb.free(l) t = bb.add(YGate(), q=t) diff --git a/qualtran/_infra/quantum_graph.py b/qualtran/_infra/quantum_graph.py index 62d2e5567c..37690564cc 100644 --- a/qualtran/_infra/quantum_graph.py +++ b/qualtran/_infra/quantum_graph.py @@ -14,7 +14,7 @@ """Plumbing for bloq-to-bloq `Connection`s.""" from functools import cached_property -from typing import Tuple, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union from attrs import field, frozen @@ -72,7 +72,7 @@ def bloq_is(self, t) -> bool: return False -def _to_tuple(x: Union[int, Tuple[int, ...]]) -> Tuple[int, ...]: +def _to_tuple(x: Union[int, tuple[int, ...]]) -> tuple[int, ...]: if isinstance(x, int): return (x,) return x @@ -101,7 +101,7 @@ class Soquet: binst: Union[BloqInstance, DanglingT] reg: 'Register' - idx: Tuple[int, ...] = field(converter=_to_tuple, default=tuple()) + idx: tuple[int, ...] = field(converter=_to_tuple, default=tuple()) @idx.validator def _check_idx(self, attribute, value): diff --git a/qualtran/_infra/registers.py b/qualtran/_infra/registers.py index bfeb8578d0..0bba84d889 100644 --- a/qualtran/_infra/registers.py +++ b/qualtran/_infra/registers.py @@ -16,7 +16,8 @@ import enum import itertools from collections import defaultdict -from typing import cast, Dict, Iterable, Iterator, List, overload, Tuple, Union +from collections.abc import Iterable, Iterator +from typing import cast, overload, Union import attrs import sympy @@ -63,7 +64,7 @@ class Register: name: str dtype: QCDType - _shape: Tuple[SymbolicInt, ...] = field( + _shape: tuple[SymbolicInt, ...] = field( default=tuple(), converter=lambda v: (v,) if isinstance(v, int) else tuple(v) ) side: Side = Side.THRU @@ -76,20 +77,20 @@ def is_symbolic(self) -> bool: return is_symbolic(self.dtype, *self._shape) @property - def shape_symbolic(self) -> Tuple[SymbolicInt, ...]: + def shape_symbolic(self) -> tuple[SymbolicInt, ...]: return self._shape @property - def shape(self) -> Tuple[int, ...]: + def shape(self) -> tuple[int, ...]: if is_symbolic(*self._shape): raise ValueError(f"{self} is symbolic. Cannot get real-valued shape.") - return cast(Tuple[int, ...], self._shape) + return cast(tuple[int, ...], self._shape) @property def bitsize(self) -> int: return self.dtype.num_bits - def all_idxs(self) -> Iterable[Tuple[int, ...]]: + def all_idxs(self) -> Iterable[tuple[int, ...]]: """Iterate over all possible indices of a multidimensional register.""" yield from itertools.product(*[range(sh) for sh in self.shape]) @@ -127,7 +128,7 @@ def adjoint(self) -> 'Register': raise ValueError(f"Unknown side {self.side}") -def _dedupe(kv_iter: Iterable[Tuple[str, Register]]) -> Dict[str, Register]: +def _dedupe(kv_iter: Iterable[tuple[str, Register]]) -> dict[str, Register]: """Construct a dictionary, but check that there are no duplicate keys.""" # throw ValueError if duplicate keys are provided. d = {} @@ -195,7 +196,7 @@ def get_right(self, name: str) -> Register: """Get a right register by name.""" return self._rights[name] - def groups(self) -> Iterable[Tuple[str, List[Register]]]: + def groups(self) -> Iterable[tuple[str, list[Register]]]: """Iterate over register groups by name. Registers with shared names (but differing `side` attributes) can be implicitly grouped. @@ -257,7 +258,7 @@ def __getitem__(self, key: int) -> Register: pass @overload - def __getitem__(self, key: slice) -> Tuple[Register, ...]: + def __getitem__(self, key: slice) -> tuple[Register, ...]: pass def __getitem__(self, key): diff --git a/qualtran/bloqs/arithmetic/addition.py b/qualtran/bloqs/arithmetic/addition.py index d249031816..7eee22eca0 100644 --- a/qualtran/bloqs/arithmetic/addition.py +++ b/qualtran/bloqs/arithmetic/addition.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. from collections import Counter +from collections.abc import Iterator, Sequence from functools import cached_property -from typing import Dict, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import cirq import numpy as np @@ -115,7 +116,7 @@ def decompose_bloq(self) -> 'CompositeBloq': def on_classical_vals( self, a: 'ClassicalValT', b: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: unsigned = isinstance(self.a_dtype, (QUInt, QMontgomeryUInt)) b_bitsize = self.b_dtype.bitsize return { @@ -128,7 +129,7 @@ def _circuit_diagram_info_(self, _) -> cirq.CircuitDiagramInfo: wire_symbols += ["In(y)/Out(x+y)"] * int(self.b_dtype.bitsize) return cirq.CircuitDiagramInfo(wire_symbols=wire_symbols) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("") if reg.name == 'a': @@ -202,7 +203,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': n_cnot = (n - 2) * 6 + 3 return {And(): n - 1, And().adjoint(): n - 1, CNOT(): n_cnot} - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.arithmetic import CAdd return get_ctrl_system_1bit_cv( @@ -294,7 +295,7 @@ def registers(self) -> Sequence[Union[int, Sequence[int]]]: raise ValueError(f'Symbolic bitsize {self.bitsize} not supported') return [2] * self.bitsize, [2] * self.bitsize, [2] * self.out_bitsize - def apply(self, a: int, b: int, c: int) -> Tuple[int, int, int]: + def apply(self, a: int, b: int, c: int) -> tuple[int, int, int]: return a, b, c + a + b def adjoint(self) -> 'OutOfPlaceAdder': @@ -302,7 +303,7 @@ def adjoint(self) -> 'OutOfPlaceAdder': def on_classical_vals( self, *, a: 'ClassicalValT', b: 'ClassicalValT', c: Optional['ClassicalValT'] = None - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if isinstance(self.bitsize, sympy.Expr): raise ValueError(f'Classical simulation is not support for symbolic bloq {self}') if self.is_adjoint: @@ -324,7 +325,7 @@ def decompose_from_registers( if not isinstance(self.bitsize, int): raise ValueError(f'Symbolic bitsize {self.bitsize} not supported') a, b, c = quregs['a'][::-1], quregs['b'][::-1], quregs['c'][::-1] - optree: List[List[cirq.Operation]] = [ + optree: list[list[cirq.Operation]] = [ [ cirq.CX(a[i], b[i]), cirq.CX(a[i], c[i]), @@ -354,7 +355,7 @@ def __pow__(self, power: int): return OutOfPlaceAdder(self.bitsize, is_adjoint=not self.is_adjoint) raise NotImplementedError("OutOfPlaceAdder.__pow__ defined only for +1/-1.") - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('c=a+b') return super().wire_symbol(reg, idx) @@ -427,7 +428,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, x: 'ClassicalValT', **vals: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if is_symbolic(self.k) or is_symbolic(self.dtype): raise ValueError(f"Classical simulation isn't supported for symbolic block {self}") @@ -447,7 +448,7 @@ def _load_k_bloq(self) -> Bloq: return XorK(self.dtype, k) - def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> dict[str, 'SoquetT']: if is_symbolic(self.k) or is_symbolic(self.dtype): raise DecomposeTypeError(f"Cannot decompose symbolic {self}.") diff --git a/qualtran/bloqs/arithmetic/bitwise.py b/qualtran/bloqs/arithmetic/bitwise.py index 87dc2d84b2..cf454ac39a 100644 --- a/qualtran/bloqs/arithmetic/bitwise.py +++ b/qualtran/bloqs/arithmetic/bitwise.py @@ -11,8 +11,9 @@ # 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 collections.abc import Sequence from functools import cached_property -from typing import Dict, Optional, Sequence, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np import sympy @@ -222,7 +223,7 @@ def wire_symbol( return TextBox("~x") - def on_classical_vals(self, x: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, x: 'ClassicalValT') -> dict[str, 'ClassicalValT']: x = -x - 1 if isinstance(self.dtype, (QUInt, QMontgomeryUInt)): x %= 2**self.dtype.bitsize diff --git a/qualtran/bloqs/arithmetic/comparison.py b/qualtran/bloqs/arithmetic/comparison.py index 044d80ed8d..d38ce69bcc 100644 --- a/qualtran/bloqs/arithmetic/comparison.py +++ b/qualtran/bloqs/arithmetic/comparison.py @@ -14,8 +14,9 @@ import abc from collections import defaultdict +from collections.abc import Iterable, Iterator, Sequence from functools import cached_property -from typing import Dict, Iterable, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import attrs import cirq @@ -77,7 +78,7 @@ def signature(self) -> Signature: return Signature.build_from_dtypes(x=QUInt(self.bitsize), target=QBit()) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text("") @@ -97,7 +98,7 @@ def apply(self, *register_vals: int) -> Union[int, Iterable[int]]: input_val, less_than_val, target_register_val = register_vals return input_val, less_than_val, target_register_val ^ (input_val < less_than_val) - def on_classical_vals(self, *, x: int, target: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, x: int, target: int) -> dict[str, 'ClassicalValT']: return {'x': x, 'target': target ^ (x < self.less_than_val)} def _circuit_diagram_info_(self, _) -> cirq.CircuitDiagramInfo: @@ -461,7 +462,7 @@ def apply(self, *register_vals: int) -> Union[int, int, Iterable[int]]: return x_val, y_val, target_val ^ (x_val <= y_val) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('') @@ -473,7 +474,7 @@ def wire_symbol( return TextBox('z∧(x<=y)') raise ValueError(f'Unknown register name {reg.name}') - def on_classical_vals(self, *, x: int, y: int, target: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, x: int, y: int, target: int) -> dict[str, 'ClassicalValT']: return {'x': x, 'y': y, 'target': target ^ (x <= y)} def _circuit_diagram_info_(self, _) -> cirq.CircuitDiagramInfo: @@ -516,7 +517,7 @@ def decompose_from_registers( n = min(len(lhs), len(rhs)) prefix_equality = None - adjoint: List[cirq.Operation] = [] + adjoint: list[cirq.Operation] = [] # if one of the registers is longer than the other store equality with |0--0> # into `prefix_equality` using d = |len(P) - len(Q)| And operations => 4d T. @@ -582,7 +583,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': n = min(self.x_bitsize, self.y_bitsize) d = max(self.x_bitsize, self.y_bitsize) - n is_second_longer = self.y_bitsize > self.x_bitsize - ret: Dict['Bloq', int] = defaultdict(lambda: 0) + ret: dict['Bloq', int] = defaultdict(lambda: 0) if d > 0: if d == 1: ret[CNOT()] += 2 @@ -666,7 +667,7 @@ def signature(self): a=QUInt(self.a_bitsize), b=QUInt(self.b_bitsize), target=QBit() ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> WireSymbol: + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> WireSymbol: if reg is None: return Text("a>b") if reg.name == 'a': @@ -679,7 +680,7 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) - def build_composite_bloq( self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet', target: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: a, b, target = bb.add( LessThanEqual(self.a_bitsize, self.b_bitsize), x=a, y=b, target=target ) @@ -739,7 +740,7 @@ def signature(self): def on_classical_vals( self, a: 'ClassicalValT', b: 'ClassicalValT', target: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: # target is a 1-bit register so we assert that it's classical value is binary. assert target == (target % 2) @@ -750,7 +751,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', a: Soquet, b: Soquet, target: SoquetT - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if isinstance(self.bitsize, sympy.Expr): raise DecomposeTypeError(f"Cannot decompose symbolic {self}.") @@ -767,7 +768,7 @@ def build_composite_bloq( # Allocate lists to store ancillas generated by the logical-and and control pairs input # into logical-ands. - ancillas: List[SoquetT] = [] + ancillas: list[SoquetT] = [] and_ctrls = [] # If the input registers are unsigned we need to append a sign bit to them in order to use @@ -868,7 +869,7 @@ def build_composite_bloq( return {'a': a, 'b': b, 'target': target} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('') @@ -927,7 +928,7 @@ class GreaterThanConstant(Bloq): def signature(self) -> Signature: return Signature.build_from_dtypes(x=QUInt(self.bitsize), target=QBit()) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> WireSymbol: + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> WireSymbol: if reg is None: return Text("") if reg.name == 'x': @@ -975,7 +976,7 @@ def bitsize(self) -> SymbolicInt: def is_symbolic(self): return is_symbolic(self.dtype) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> WireSymbol: + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> WireSymbol: if reg is None: return Text("") if reg.name == 'x': @@ -988,7 +989,7 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) - def build_composite_bloq( self, bb: 'BloqBuilder', x: 'Soquet', y: 'Soquet', target: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") @@ -1014,7 +1015,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': cvs = HasLength(self.bitsize) return {Xor(self.dtype): 2, MultiControlX(cvs=cvs): 1} - def on_classical_vals(self, x: int, y: int, target: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, x: int, y: int, target: int) -> dict[str, 'ClassicalValT']: return {'x': x, 'y': y, 'target': target ^ (x == y)} @@ -1050,7 +1051,7 @@ class EqualsAConstant(Bloq): def signature(self) -> Signature: return Signature.build_from_dtypes(x=QUInt(self.bitsize), target=QBit()) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> WireSymbol: + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> WireSymbol: if reg is None: return Text("") if reg.name == 'x': @@ -1071,7 +1072,7 @@ def bits_k(self) -> Union[tuple[int, ...], HasLength]: def build_composite_bloq( self, bb: 'BloqBuilder', x: 'Soquet', target: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic {self.bitsize=}") @@ -1138,7 +1139,7 @@ def signature(self) -> Signature: return Signature.build_from_dtypes(ctrl=QBit(), a=self.dtype, b=self.dtype, target=QBit()) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('') @@ -1154,7 +1155,7 @@ def wire_symbol( def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: 'Soquet', a: 'Soquet', b: 'Soquet', target: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.dtype.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") @@ -1204,7 +1205,7 @@ def build_composite_bloq( def on_classical_vals( self, ctrl: int, a: int, b: int, target: int - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == self.cv: return {'ctrl': ctrl, 'a': a, 'b': b, 'target': target ^ (a > b)} return {'ctrl': ctrl, 'a': a, 'b': b, 'target': target} @@ -1276,7 +1277,7 @@ def signature(self) -> Signature: def adjoint(self) -> '_HalfLinearDepthGreaterThan': return attrs.evolve(self, uncompute=self.uncompute ^ True) - def _compute(self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet') -> Dict[str, 'SoquetT']: + def _compute(self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet') -> dict[str, 'SoquetT']: if isinstance(self.dtype, QInt): a = bb.add(SignExtend(self.dtype, QInt(self.dtype.bitsize + 1)), x=a) b = bb.add(SignExtend(self.dtype, QInt(self.dtype.bitsize + 1)), x=b) @@ -1317,7 +1318,7 @@ def _compute(self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet') -> Dict[str, 'So def _uncompute( self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet', c: 'Soquet', target: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if isinstance(self.dtype, QInt): a = bb.add(SignExtend(self.dtype, QInt(self.dtype.bitsize + 1)), x=a) b = bb.add(SignExtend(self.dtype, QInt(self.dtype.bitsize + 1)), x=b) @@ -1365,7 +1366,7 @@ def build_composite_bloq( b: 'Soquet', c: Optional['Soquet'] = None, target: Optional['Soquet'] = None, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.dtype.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") @@ -1470,7 +1471,7 @@ def on_classical_vals( b: 'ClassicalValT', c: Optional['ClassicalValT'] = None, target: Optional['ClassicalValT'] = None, - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if self._op_symbol in ('>', '<='): c_val = add_ints(-int(a), int(b), num_bits=self.dtype.bitsize + 1, is_signed=False) else: @@ -1483,7 +1484,7 @@ def on_classical_vals( assert target is None return {'a': a, 'b': b, 'c': c_val, 'target': int(self._classical_comparison(a, b))} - def _compute(self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet') -> Dict[str, 'SoquetT']: + def _compute(self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet') -> dict[str, 'SoquetT']: if self._op_symbol in ('>', '<='): a, b, c, target = bb.add_from(self._half_greater_than_bloq, a=a, b=b) # type: ignore else: @@ -1496,7 +1497,7 @@ def _compute(self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet') -> Dict[str, 'So def _uncompute( self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet', c: 'Soquet', target: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if self._op_symbol in ('<=', '>='): target = bb.add(XGate(), q=target) @@ -1514,7 +1515,7 @@ def build_composite_bloq( b: 'Soquet', c: Optional['Soquet'] = None, target: Optional['Soquet'] = None, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if self.uncompute: assert c is not None assert target is not None diff --git a/qualtran/bloqs/arithmetic/controlled_addition.py b/qualtran/bloqs/arithmetic/controlled_addition.py index dc6751d23a..c861b684ac 100644 --- a/qualtran/bloqs/arithmetic/controlled_addition.py +++ b/qualtran/bloqs/arithmetic/controlled_addition.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import numpy as np import sympy @@ -102,7 +102,7 @@ def signature(self): [Register("ctrl", QBit()), Register("a", self.a_dtype), Register("b", self.b_dtype)] ) - def on_classical_vals(self, **kwargs) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, **kwargs) -> dict[str, 'ClassicalValT']: a, b = kwargs['a'], kwargs['b'] ctrl = kwargs['ctrl'] if ctrl != self.cv: @@ -135,7 +135,7 @@ def wire_symbol(self, soq: 'Soquet') -> 'WireSymbol': def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: 'Soquet', a: 'Soquet', b: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.a_dtype.bitsize, self.b_dtype.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") diff --git a/qualtran/bloqs/arithmetic/conversions/contiguous_index.py b/qualtran/bloqs/arithmetic/conversions/contiguous_index.py index 79f552805b..f5caeac6ed 100644 --- a/qualtran/bloqs/arithmetic/conversions/contiguous_index.py +++ b/qualtran/bloqs/arithmetic/conversions/contiguous_index.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -66,10 +66,10 @@ def signature(self) -> Signature: def on_classical_vals( self, mu: 'ClassicalValT', nu: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: return {'mu': mu, 'nu': nu, 's': nu * (nu + 1) // 2 + mu} - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> WireSymbol: + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> WireSymbol: if reg is None: return Text('') if reg.name == 'mu': diff --git a/qualtran/bloqs/arithmetic/hamming_weight.py b/qualtran/bloqs/arithmetic/hamming_weight.py index 2322fd8404..79789bc717 100644 --- a/qualtran/bloqs/arithmetic/hamming_weight.py +++ b/qualtran/bloqs/arithmetic/hamming_weight.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator from functools import cached_property -from typing import Iterator, List, TYPE_CHECKING +from typing import TYPE_CHECKING import cirq from attrs import frozen @@ -87,7 +88,7 @@ def _three_to_two_adder(self, a, b, c, out) -> cirq.OP_TREE: ] def _decompose_using_three_to_two_adders( - self, x: List[cirq.Qid], junk: List[cirq.Qid], out: List[cirq.Qid] + self, x: list[cirq.Qid], junk: list[cirq.Qid], out: list[cirq.Qid] ) -> Iterator[cirq.OP_TREE]: for out_idx in range(len(out)): y = [] @@ -109,9 +110,9 @@ def decompose_from_registers( ) -> Iterator[cirq.OP_TREE]: # Qubit order needs to be reversed because the registers store Big Endian representation # of integers. - x: List[cirq.Qid] = [*quregs['x'][::-1]] - junk: List[cirq.Qid] = [*quregs['junk'][::-1]] - out: List[cirq.Qid] = [*quregs['out'][::-1]] + x: list[cirq.Qid] = [*quregs['x'][::-1]] + junk: list[cirq.Qid] = [*quregs['junk'][::-1]] + out: list[cirq.Qid] = [*quregs['out'][::-1]] yield self._decompose_using_three_to_two_adders(x, junk, out) def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': diff --git a/qualtran/bloqs/arithmetic/multiplication.py b/qualtran/bloqs/arithmetic/multiplication.py index efed2d6652..35e3587d71 100644 --- a/qualtran/bloqs/arithmetic/multiplication.py +++ b/qualtran/bloqs/arithmetic/multiplication.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from collections.abc import Iterable, Sequence +from typing import Optional, TYPE_CHECKING, Union import cirq import numpy as np @@ -73,7 +74,7 @@ def __attrs_post_init__(self): f"bitsizes {self.a_bitsize} + {self.b_bitsize}" ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("result -= a*b") if self.is_adjoint else Text("result += a*b") return super().wire_symbol(reg, idx) @@ -112,7 +113,7 @@ def apply(self, a: int, b: int, result: int) -> Union[int, Iterable[int]]: def with_registers(self, *new_registers: Union[int, Sequence[int]]): raise NotImplementedError("Not needed.") - def on_classical_vals(self, a: int, b: int, result: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, a: int, b: int, result: int) -> dict[str, 'ClassicalValT']: result_out = (result + a * b * ((-1) ** self.is_adjoint)) % (2**self.result_bitsize) return {'a': a, 'b': b, 'result': result_out} @@ -128,8 +129,8 @@ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.Circ return cirq.CircuitDiagramInfo(wire_symbols=wire_symbols) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: from qualtran.cirq_interop._cirq_to_bloq import _my_tensors_from_gate return _my_tensors_from_gate(self, self.signature, incoming=incoming, outgoing=outgoing) @@ -181,7 +182,7 @@ def signature(self): ] ) - def on_classical_vals(self, **vals: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, **vals: int) -> dict[str, 'ClassicalValT']: if self.uncompute: a, result = vals["a"], vals["result"] assert result == a**2 @@ -189,7 +190,7 @@ def on_classical_vals(self, **vals: int) -> Dict[str, 'ClassicalValT']: a = vals["a"] return {'a': a, 'result': a**2} - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("a^2") return super().wire_symbol(reg, idx) @@ -202,8 +203,8 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {Toffoli(): num_toff} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn if is_symbolic(self.bitsize): @@ -277,7 +278,7 @@ def signature(self): ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('SOS') return super().wire_symbol(reg, idx) @@ -332,7 +333,7 @@ def signature(self): ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('a*b') return super().wire_symbol(reg, idx) @@ -395,7 +396,7 @@ def signature(self): ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('r*i') return super().wire_symbol(reg, idx) @@ -454,7 +455,7 @@ def signature(self): ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('a*b') return super().wire_symbol(reg, idx) @@ -515,7 +516,7 @@ def signature(self): ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('a^2') return super().wire_symbol(reg, idx) @@ -573,7 +574,7 @@ def signature(self): ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('1/a') return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/arithmetic/permutation.py b/qualtran/bloqs/arithmetic/permutation.py index 8c294d5934..d5507fdd22 100644 --- a/qualtran/bloqs/arithmetic/permutation.py +++ b/qualtran/bloqs/arithmetic/permutation.py @@ -23,8 +23,9 @@ # 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 collections.abc import Iterable, Sequence from functools import cached_property -from typing import cast, Iterable, Sequence, Set, TYPE_CHECKING, TypeAlias, Union +from typing import cast, TYPE_CHECKING, TypeAlias, Union from attrs import field, frozen @@ -126,7 +127,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', x: 'SoquetT') -> dict[str, 'So def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if is_symbolic(self.cycle): x = ssa.new_symbol('x') cycle_len = slen(self.cycle) @@ -275,7 +276,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', x: 'Soquet') -> dict[str, 'Soq def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if is_symbolic(self.cycles): # worst case cost: single cycle of length N cycle = Shaped((self.N,)) diff --git a/qualtran/bloqs/arithmetic/sorting.py b/qualtran/bloqs/arithmetic/sorting.py index 5014d74bc1..f6247de40d 100644 --- a/qualtran/bloqs/arithmetic/sorting.py +++ b/qualtran/bloqs/arithmetic/sorting.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict import numpy as np import sympy @@ -152,7 +151,7 @@ def num_comparisons(self) -> SymbolicInt: rest = self.k % (2 * self.offset) return full + max(rest - self.offset, 0) - def build_composite_bloq(self, bb: 'BloqBuilder', xs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', xs: 'SoquetT') -> dict[str, 'SoquetT']: if is_symbolic(self.k) or is_symbolic(self.offset): raise DecomposeTypeError(f"Cannot decompose symbolic {self=}") diff --git a/qualtran/bloqs/arithmetic/subtraction.py b/qualtran/bloqs/arithmetic/subtraction.py index f062557083..441030bfe4 100644 --- a/qualtran/bloqs/arithmetic/subtraction.py +++ b/qualtran/bloqs/arithmetic/subtraction.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Optional, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import numpy as np import sympy @@ -121,7 +121,7 @@ def b_dtype_as_unsigned(self): def on_classical_vals( self, a: 'ClassicalValT', b: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: unsigned = isinstance(self.a_dtype, (QUInt, QMontgomeryUInt)) b_bitsize = self.b_dtype.bitsize N = 2**b_bitsize @@ -138,7 +138,7 @@ def on_classical_vals( return {'a': a, 'b': int((a - b + half_n) % N) - half_n} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': from qualtran.drawing import directional_text_box @@ -164,7 +164,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': costs[MultiTargetCNOT(delta)] = 2 return costs - def build_composite_bloq(self, bb: 'BloqBuilder', a: Soquet, b: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', a: Soquet, b: Soquet) -> dict[str, 'SoquetT']: delta = self.b_dtype.bitsize - self.a_dtype.bitsize n_bits = self.b_dtype.bitsize if delta: @@ -269,7 +269,7 @@ def signature(self): def on_classical_vals( self, a: 'ClassicalValT', b: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: return { 'a': a, 'b': add_ints( @@ -281,7 +281,7 @@ def on_classical_vals( } def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': from qualtran.drawing import directional_text_box @@ -297,7 +297,7 @@ def wire_symbol( def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {BitwiseNot(self.dtype): 2, Add(self.dtype, self.dtype): 1} - def build_composite_bloq(self, bb: 'BloqBuilder', a: Soquet, b: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', a: Soquet, b: Soquet) -> dict[str, 'SoquetT']: b = bb.add(BitwiseNot(self.dtype), x=b) # a, -1 - b a, b = bb.add_t(Add(self.dtype, self.dtype), a=a, b=b) # a, a - 1 - b b = bb.add(BitwiseNot(self.dtype), x=b) # a, -1 - (a - 1 - b) = a, -a + b diff --git a/qualtran/bloqs/arithmetic/trigonometric/arcsin.py b/qualtran/bloqs/arithmetic/trigonometric/arcsin.py index 2405e65efa..bb6365b374 100644 --- a/qualtran/bloqs/arithmetic/trigonometric/arcsin.py +++ b/qualtran/bloqs/arithmetic/trigonometric/arcsin.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict - import numpy as np from attrs import frozen @@ -74,7 +72,7 @@ def signature(self): def on_classical_vals( self, x: ClassicalValT, result: ClassicalValT - ) -> Dict[str, ClassicalValT]: + ) -> dict[str, ClassicalValT]: if is_symbolic(self.bitsize): raise ValueError(f"Symbolic bitsize {self.bitsize} not supported") x_fxp: float = _fxp(x / 2**self.bitsize, self.bitsize).astype(float) diff --git a/qualtran/bloqs/arithmetic/trigonometric/arctan.py b/qualtran/bloqs/arithmetic/trigonometric/arctan.py index 746411d9f4..8fb10d09d3 100644 --- a/qualtran/bloqs/arithmetic/trigonometric/arctan.py +++ b/qualtran/bloqs/arithmetic/trigonometric/arctan.py @@ -11,8 +11,9 @@ # 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 collections.abc import Iterable, Sequence from functools import cached_property -from typing import Iterable, Sequence, Union +from typing import Union import attrs import cirq diff --git a/qualtran/bloqs/basic_gates/cnot.py b/qualtran/bloqs/basic_gates/cnot.py index d2c2002a22..c25d4157ac 100644 --- a/qualtran/bloqs/basic_gates/cnot.py +++ b/qualtran/bloqs/basic_gates/cnot.py @@ -13,8 +13,9 @@ # limitations under the License. import itertools +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np from attrs import frozen @@ -72,8 +73,8 @@ def adjoint(self) -> 'Bloq': return self def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: # This bloq uses the factored form of CNOT composed of a COPY and XOR tensor joined # by an internal index. # [Lectures on Quantum Tensor Networks](https://arxiv.org/abs/1912.10049). Biamonte 2019. @@ -93,10 +94,10 @@ def my_tensors( ), ] - def on_classical_vals(self, ctrl: int, target: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, ctrl: int, target: int) -> dict[str, 'ClassicalValT']: return {'ctrl': ctrl, 'target': (ctrl + target) % 2} - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.basic_gates.toffoli import Toffoli if ctrl_spec != CtrlSpec(): @@ -105,8 +106,8 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlled bloq = Toffoli() def add_controlled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: (new_ctrl,) = ctrl_soqs (new_ctrl, existing_ctrl), target = bb.add( bloq, ctrl=np.array([new_ctrl, in_soqs['ctrl']]), target=in_soqs['target'] @@ -117,7 +118,7 @@ def add_controlled( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', ctrl: 'CirqQuregT', target: 'CirqQuregT' # type: ignore[type-var] - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: # type: ignore[type-var] import cirq (ctrl,) = ctrl @@ -129,7 +130,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.CNOT(wires=wires) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'ctrl': diff --git a/qualtran/bloqs/basic_gates/global_phase.py b/qualtran/bloqs/basic_gates/global_phase.py index 08e0273e6e..af991b420f 100644 --- a/qualtran/bloqs/basic_gates/global_phase.py +++ b/qualtran/bloqs/basic_gates/global_phase.py @@ -11,8 +11,9 @@ # 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 collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, List, Sequence, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import cirq @@ -93,13 +94,13 @@ def adjoint(self) -> 'GlobalPhase': return attrs.evolve(self, exponent=-self.exponent) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [qtn.Tensor(data=self.coefficient, inds=[], tags=[str(self)])] - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: # Delegate to superclass logic for more than one control. if ctrl_spec != CtrlSpec(): return super().get_ctrl_system(ctrl_spec=ctrl_spec) @@ -109,8 +110,8 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlled bloq = ZPowGate(exponent=self.exponent, eps=self.eps) def _add_ctrled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: (ctrl,) = ctrl_soqs ctrl = bb.add(bloq, q=ctrl) return [ctrl], [] diff --git a/qualtran/bloqs/basic_gates/hadamard.py b/qualtran/bloqs/basic_gates/hadamard.py index 371672f6e3..4be0681d99 100644 --- a/qualtran/bloqs/basic_gates/hadamard.py +++ b/qualtran/bloqs/basic_gates/hadamard.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import numpy as np from attrs import frozen @@ -74,8 +75,8 @@ def decompose_bloq(self) -> 'CompositeBloq': raise DecomposeTypeError(f"{self} is atomic") def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ @@ -84,15 +85,15 @@ def my_tensors( ) ] - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: if ctrl_spec != CtrlSpec(): return super().get_ctrl_system(ctrl_spec=ctrl_spec) bloq = CHadamard() def _add_ctrled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: (ctrl,) = ctrl_soqs ctrl, q = bb.add(bloq, ctrl=ctrl, target=in_soqs['q']) return ((ctrl,), (q,)) @@ -101,7 +102,7 @@ def _add_ctrled( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q: 'CirqQuregT' # type: ignore[type-var] - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: # type: ignore[type-var] import cirq (q,) = q @@ -112,7 +113,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.Hadamard(wires=wires) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox('H') @@ -150,8 +151,8 @@ def adjoint(self) -> 'Bloq': return self def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn unitary = np.eye(4, dtype=np.complex128).reshape((2, 2, 2, 2)) @@ -168,7 +169,7 @@ def my_tensors( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', ctrl: 'CirqQuregT', target: 'CirqQuregT' - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: import cirq (ctrl,) = ctrl @@ -191,7 +192,7 @@ def my_static_costs(self, cost_key: 'CostKey'): return NotImplemented - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'ctrl': diff --git a/qualtran/bloqs/basic_gates/identity.py b/qualtran/bloqs/basic_gates/identity.py index 379717e0ec..4451a511f9 100644 --- a/qualtran/bloqs/basic_gates/identity.py +++ b/qualtran/bloqs/basic_gates/identity.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np from attrs import frozen @@ -69,8 +70,8 @@ def decompose_bloq(self) -> 'CompositeBloq': raise DecomposeTypeError(f"{self} is atomic") def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ @@ -82,7 +83,7 @@ def my_tensors( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q: 'CirqQuregT' # type: ignore[type-var] - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: # type: ignore[type-var] import cirq if is_symbolic(self.bitsize): @@ -95,12 +96,12 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.Identity(wires=wires) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox('I') - def on_classical_vals(self, q: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, q: int) -> dict[str, 'ClassicalValT']: return {'q': q} def __str__(self) -> str: @@ -113,8 +114,8 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlled ctrl_I = Identity(ctrl_spec.num_qubits + self.bitsize) def ctrl_adder( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: parts = [ (Register(f'ctrl_{i}', dtype=dtype, shape=shape), 'q') for i, (dtype, shape) in enumerate(ctrl_spec.activation_function_dtypes()) diff --git a/qualtran/bloqs/basic_gates/on_each.py b/qualtran/bloqs/basic_gates/on_each.py index 0d8a190709..fb7d19fdc3 100644 --- a/qualtran/bloqs/basic_gates/on_each.py +++ b/qualtran/bloqs/basic_gates/on_each.py @@ -14,7 +14,7 @@ """Classes to apply single qubit bloq to multiple qubits.""" from functools import cached_property -from typing import Dict, Optional, Tuple +from typing import Optional import attrs import sympy @@ -70,7 +70,7 @@ def signature(self) -> Signature: ) return Signature([reg]) - def build_composite_bloq(self, bb: BloqBuilder, *, q: Soquet) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, *, q: Soquet) -> dict[str, SoquetT]: if isinstance(self.n, sympy.Expr): raise DecomposeTypeError(f'Cannote decompose {self} with symbolic bitsize {self.n}') qs = bb.split(q) @@ -81,7 +81,7 @@ def build_composite_bloq(self, bb: BloqBuilder, *, q: Soquet) -> Dict[str, Soque def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {self.gate: self.n} - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> WireSymbol: + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> WireSymbol: one_reg = self.gate.wire_symbol(reg=reg, idx=idx) if isinstance(one_reg, TextBox): new_text = f'{one_reg.text}⨂{self.n}' diff --git a/qualtran/bloqs/basic_gates/power.py b/qualtran/bloqs/basic_gates/power.py index 5331c3afd2..b8e1888fec 100644 --- a/qualtran/bloqs/basic_gates/power.py +++ b/qualtran/bloqs/basic_gates/power.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np from attrs import frozen @@ -59,7 +59,7 @@ def adjoint(self) -> 'Bloq': def signature(self) -> Signature: return self.bloq.signature - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: if not isinstance(self.power, int): raise ValueError(f'Symbolic power {self.power} not supported') for _ in range(self.power): diff --git a/qualtran/bloqs/basic_gates/rotation.py b/qualtran/bloqs/basic_gates/rotation.py index 3acb1681db..1d573f58b2 100644 --- a/qualtran/bloqs/basic_gates/rotation.py +++ b/qualtran/bloqs/basic_gates/rotation.py @@ -42,9 +42,9 @@ Barenco et. al. 1995. """ - +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import attrs import cirq @@ -135,15 +135,15 @@ def decompose_bloq(self) -> 'CompositeBloq': def cirq_gate(self) -> cirq.Gate: return cirq.ZPowGate(exponent=self.exponent, global_shift=0) - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: if ctrl_spec != CtrlSpec(): return super().get_ctrl_system(ctrl_spec) ctrl_bloq = CZPowGate(exponent=self.exponent, eps=self.eps) def add_ctrled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: (ctrl_soq,) = ctrl_soqs ctrl_soq, q = bb.add(ctrl_bloq, q=np.array([ctrl_soq, in_soqs['q']])) return (ctrl_soq,), (q,) @@ -157,7 +157,7 @@ def __pow__(self, power): def adjoint(self) -> 'ZPowGate': return attrs.evolve(self, exponent=-self.exponent) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox(f'Z^{self.exponent}') @@ -215,7 +215,7 @@ class CZPowGate(Bloq): def signature(self) -> 'Signature': return Signature([Register('q', QBit(), shape=(2,))]) - def build_composite_bloq(self, bb: 'BloqBuilder', q: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', q: 'SoquetT') -> dict[str, 'SoquetT']: from qualtran.bloqs.mcmt import And q1, q2 = q # type: ignore @@ -299,7 +299,7 @@ def cirq_gate(self) -> cirq.Gate: def adjoint(self) -> 'XPowGate': return attrs.evolve(self, exponent=-self.exponent) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox(f'X^{self.exponent}') @@ -373,7 +373,7 @@ def cirq_gate(self) -> cirq.Gate: def adjoint(self) -> 'YPowGate': return attrs.evolve(self, exponent=-self.exponent) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox(f'Y^{self.exponent}') @@ -449,7 +449,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.RZ(phi=self.angle, wires=wires) - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: if ctrl_spec != CtrlSpec(): return super().get_ctrl_system(ctrl_spec) @@ -466,7 +466,7 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlled def adjoint(self) -> 'Rz': return attrs.evolve(self, angle=-self.angle) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox(str(self)) @@ -527,7 +527,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: 'Soquet', q: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: from qualtran.bloqs.basic_gates import CNOT t = self.angle / np.pi @@ -607,7 +607,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': def adjoint(self) -> 'Rx': return attrs.evolve(self, angle=-self.angle) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox(str(self)) @@ -671,7 +671,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': def adjoint(self) -> 'Ry': return attrs.evolve(self, angle=-self.angle) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox(str(self)) diff --git a/qualtran/bloqs/basic_gates/s_gate.py b/qualtran/bloqs/basic_gates/s_gate.py index 6111677a1e..3c9217ee50 100644 --- a/qualtran/bloqs/basic_gates/s_gate.py +++ b/qualtran/bloqs/basic_gates/s_gate.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import attrs import numpy as np @@ -59,8 +59,8 @@ def signature(self) -> 'Signature': return Signature.build(q=1) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn data = _SMATRIX.conj().T if self.is_adjoint else _SMATRIX @@ -70,7 +70,7 @@ def my_tensors( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q: 'CirqQuregT' # type:ignore[type-var] - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: # type:ignore[type-var] + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: # type:ignore[type-var] import cirq (q,) = q @@ -86,7 +86,7 @@ def __str__(self) -> str: maybe_dag = '†' if self.is_adjoint else '' return f'S{maybe_dag}' - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') return TextBox(str(self)) diff --git a/qualtran/bloqs/basic_gates/su2_rotation.py b/qualtran/bloqs/basic_gates/su2_rotation.py index 91283ba182..5b043a24ff 100644 --- a/qualtran/bloqs/basic_gates/su2_rotation.py +++ b/qualtran/bloqs/basic_gates/su2_rotation.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np import sympy @@ -147,8 +147,8 @@ def from_euler_zxz_angles( return cls(su2_theta, su2_phi, su2_lambd, su2_global_shift) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ @@ -164,7 +164,7 @@ def _unitary_(self): return None return self.rotation_matrix - def build_composite_bloq(self, bb: 'BloqBuilder', q: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', q: 'SoquetT') -> dict[str, 'SoquetT']: # TODO implement controlled version, and pass eps/4 to each rotation (incl. global phase) # https://github.com/quantumlib/Qualtran/issues/1330 bb.add( @@ -209,7 +209,7 @@ def __str__(self): return f'SU_2({self.theta},{self.phi},{self.lambd},{self.global_shift})' return f'SU_2({self.theta:.2f},{self.phi:.2f},{self.lambd:.2f},{self.global_shift:.2f})' - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: if self.is_symbolic(): return Text(f'({self.theta},{self.phi},{self.lambd},{self.global_shift})') diff --git a/qualtran/bloqs/basic_gates/swap.py b/qualtran/bloqs/basic_gates/swap.py index 5c2481f7a1..cdc0b37afd 100644 --- a/qualtran/bloqs/basic_gates/swap.py +++ b/qualtran/bloqs/basic_gates/swap.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import numpy as np import sympy @@ -81,7 +82,7 @@ def decompose_bloq(self) -> 'CompositeBloq': def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', x: 'CirqQuregT', y: 'CirqQuregT' # type: ignore[type-var] - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: # type: ignore[type-var] (x,) = x (y,) = y import cirq @@ -94,8 +95,8 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.SWAP(wires=wires) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn matrix = _swap_matrix() @@ -105,7 +106,7 @@ def my_tensors( def on_classical_vals( self, x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: return {'x': y, 'y': x} def adjoint(self) -> 'Bloq': @@ -175,8 +176,8 @@ def to_clifford_t_circuit(self) -> 'cirq.FrozenCircuit': return circuit.freeze() def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn matrix = _controlled_swap_matrix() @@ -186,7 +187,7 @@ def my_tensors( def on_classical_vals( self, ctrl: 'ClassicalValT', x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == 0: return {'ctrl': 0, 'x': x, 'y': y} if ctrl == 1: @@ -201,7 +202,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.CSWAP(wires=wires) - def wire_symbol(self, reg: Optional['Register'], idx: Tuple[int, ...] = ()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional['Register'], idx: tuple[int, ...] = ()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'ctrl': @@ -250,7 +251,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', x: 'Soquet', y: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if isinstance(self.bitsize, sympy.Expr): raise DecomposeTypeError("`bitsize` must be a concrete value.") @@ -267,10 +268,10 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': def on_classical_vals( self, x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: return {'x': y, 'y': x} - def wire_symbol(self, reg: Optional['Register'], idx: Tuple[int, ...] = ()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional['Register'], idx: tuple[int, ...] = ()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'x': @@ -289,8 +290,8 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlled cswap = CSwap(self.bitsize) def adder( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: (ctrl,) = ctrl_soqs ctrl, x, y = bb.add(cswap, ctrl=ctrl, x=in_soqs['x'], y=in_soqs['y']) return [ctrl], [x, y] @@ -344,7 +345,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: 'SoquetT', x: 'Soquet', y: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if isinstance(self.bitsize, sympy.Expr): raise DecomposeTypeError("`bitsize` must be a concrete value.") @@ -361,7 +362,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': def on_classical_vals( self, ctrl: 'ClassicalValT', x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == 0: return {'ctrl': 0, 'x': x, 'y': y} if ctrl == 1: @@ -386,7 +387,7 @@ def _circuit_diagram_info_( ) return cirq.CircuitDiagramInfo(("@",) + ("×(x)",) * self.bitsize + ("×(y)",) * self.bitsize) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'x': diff --git a/qualtran/bloqs/basic_gates/t_gate.py b/qualtran/bloqs/basic_gates/t_gate.py index 77cc66bbed..dac98af48e 100644 --- a/qualtran/bloqs/basic_gates/t_gate.py +++ b/qualtran/bloqs/basic_gates/t_gate.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import attrs import numpy as np @@ -77,8 +77,8 @@ def signature(self) -> 'Signature': return Signature.build(q=1) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn data = _TMATRIX.conj().T if self.is_adjoint else _TMATRIX @@ -91,7 +91,7 @@ def adjoint(self) -> 'Bloq': def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q: 'CirqQuregT' # type: ignore[type-var] - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: # type: ignore[type-var] import cirq (q,) = q @@ -107,7 +107,7 @@ def __str__(self): maybe_dag = '†' if self.is_adjoint else '' return f'T{maybe_dag}' - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') maybe_dag = '†' if self.is_adjoint else '' diff --git a/qualtran/bloqs/basic_gates/t_gate_test.py b/qualtran/bloqs/basic_gates/t_gate_test.py index 3bfc107c31..6caff3a717 100644 --- a/qualtran/bloqs/basic_gates/t_gate_test.py +++ b/qualtran/bloqs/basic_gates/t_gate_test.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict import cirq import numpy as np @@ -71,7 +70,7 @@ class TestTStateMaker(Bloq): def signature(self) -> 'Signature': return Signature.build(x=1) - def build_composite_bloq(self, bb: 'BloqBuilder', x: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: 'SoquetT') -> dict[str, 'SoquetT']: x = bb.add(Hadamard(), q=x) x = bb.add(TGate(), q=x) return {'x': x} diff --git a/qualtran/bloqs/basic_gates/toffoli.py b/qualtran/bloqs/basic_gates/toffoli.py index 65733ee460..9cff9e15f8 100644 --- a/qualtran/bloqs/basic_gates/toffoli.py +++ b/qualtran/bloqs/basic_gates/toffoli.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. import itertools +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import cast, Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import cast, Optional, TYPE_CHECKING, Union import numpy as np from attrs import frozen @@ -71,9 +72,9 @@ def decompose_bloq(self) -> 'CompositeBloq': def my_tensors( self, - incoming: Dict[str, NDArray[Connection]], # type: ignore[type-var] - outgoing: Dict[str, NDArray[Connection]], # type: ignore[type-var] - ) -> List['qtn.Tensor']: + incoming: dict[str, NDArray[Connection]], # type: ignore[type-var] + outgoing: dict[str, NDArray[Connection]], # type: ignore[type-var] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn from qualtran.bloqs.basic_gates.cnot import XOR @@ -104,7 +105,7 @@ def my_tensors( def on_classical_vals( self, ctrl: NDArray[np.integer], target: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: assert target in [0, 1] if ctrl[0] == 1 and ctrl[1] == 1: target = (target + 1) % 2 @@ -113,7 +114,7 @@ def on_classical_vals( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', ctrl: 'CirqQuregT', target: 'CirqQuregT' # type: ignore[type-var] - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: # type: ignore[type-var] import cirq (trg,) = target @@ -124,7 +125,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.Toffoli(wires=wires) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': from qualtran.drawing import Circle, ModPlus, Text if reg is None: @@ -136,7 +137,7 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) - return ModPlus() raise ValueError(f'Unknown wire symbol register name: {reg.name}') - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.basic_gates import CNOT from qualtran.bloqs.mcmt import ControlledViaAnd diff --git a/qualtran/bloqs/basic_gates/x_basis.py b/qualtran/bloqs/basic_gates/x_basis.py index 5b50f5da8d..c40b1c94ba 100644 --- a/qualtran/bloqs/basic_gates/x_basis.py +++ b/qualtran/bloqs/basic_gates/x_basis.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import numpy as np from attrs import frozen @@ -75,8 +76,8 @@ def signature(self) -> 'Signature': return Signature([Register('q', QBit(), side=Side.RIGHT if self.state else Side.LEFT)]) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn side = outgoing if self.state else incoming @@ -86,7 +87,7 @@ def my_tensors( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', **cirq_quregs: 'CirqQuregT' # type: ignore[type-var] - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: # type: ignore[type-var] if not self.state: raise ValueError(f"There is no Cirq equivalent for {self}") @@ -106,7 +107,7 @@ def __str__(self) -> str: return f'|{s}>' if self.state else f'<{s}|' def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('') @@ -216,8 +217,8 @@ def adjoint(self) -> 'Bloq': return self def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ @@ -226,7 +227,7 @@ def my_tensors( ) ] - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.basic_gates import CNOT, Toffoli if ctrl_spec == CtrlSpec(): @@ -237,20 +238,20 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlled return super().get_ctrl_system(ctrl_spec) def add_controlled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: (ctrl_soq,) = ctrl_soqs ctrl_soq, target = bb.add(bloq, ctrl=ctrl_soq, target=in_soqs['q']) return (ctrl_soq,), (target,) return bloq, add_controlled - def on_classical_vals(self, q: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, q: int) -> dict[str, 'ClassicalValT']: return {'q': (q + 1) % 2} def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', **cirq_quregs: 'CirqQuregT' - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: import cirq q = cirq_quregs.pop('q') @@ -263,7 +264,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.PauliX(wires=wires) - def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Register, idx: tuple[int, ...] = tuple()) -> 'WireSymbol': from qualtran.drawing import ModPlus if reg is None: diff --git a/qualtran/bloqs/basic_gates/y_gate.py b/qualtran/bloqs/basic_gates/y_gate.py index a3b3056796..d9c8c87428 100644 --- a/qualtran/bloqs/basic_gates/y_gate.py +++ b/qualtran/bloqs/basic_gates/y_gate.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import numpy as np from attrs import frozen @@ -66,8 +67,8 @@ def adjoint(self) -> 'Bloq': return self def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ @@ -76,15 +77,15 @@ def my_tensors( ) ] - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: if ctrl_spec != CtrlSpec(): return super().get_ctrl_system(ctrl_spec=ctrl_spec) bloq = CYGate() def _add_ctrled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: (ctrl,) = ctrl_soqs ctrl, q = bb.add(bloq, ctrl=ctrl, target=in_soqs['q']) return ((ctrl,), (q,)) @@ -93,7 +94,7 @@ def _add_ctrled( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q: 'CirqQuregT' - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: import cirq (q,) = q @@ -105,7 +106,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.PauliY(wires=wires) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('') @@ -141,8 +142,8 @@ def adjoint(self) -> 'Bloq': return self def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn unitary = np.eye(4, dtype=np.complex128).reshape((2, 2, 2, 2)) @@ -159,7 +160,7 @@ def my_tensors( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', ctrl: 'CirqQuregT', target: 'CirqQuregT' - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: import cirq (ctrl,) = ctrl @@ -175,7 +176,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.CY(wires=wires) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('') @@ -185,7 +186,7 @@ def wire_symbol( return TextBox('Y') raise ValueError(f"Unknown register {reg}.") - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv_from_bloqs return get_ctrl_system_1bit_cv_from_bloqs( diff --git a/qualtran/bloqs/basic_gates/z_basis.py b/qualtran/bloqs/basic_gates/z_basis.py index b5e5a73844..3aa0175703 100644 --- a/qualtran/bloqs/basic_gates/z_basis.py +++ b/qualtran/bloqs/basic_gates/z_basis.py @@ -12,19 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable, Mapping, Sequence from functools import cached_property -from typing import ( - cast, - Dict, - Iterable, - List, - Mapping, - Optional, - Sequence, - Tuple, - TYPE_CHECKING, - Union, -) +from typing import cast, Optional, TYPE_CHECKING, Union import attrs import numpy as np @@ -101,8 +91,8 @@ def decompose_bloq(self) -> CompositeBloq: raise DecomposeTypeError(f"{self} is atomic") def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn side = outgoing if self.state else incoming @@ -110,7 +100,7 @@ def my_tensors( qtn.Tensor(data=_ONE if self.bit else _ZERO, inds=[(side['q'], 0)], tags=[str(self)]) ] - def on_classical_vals(self, *, q: Optional[int] = None) -> Dict[str, int]: + def on_classical_vals(self, *, q: Optional[int] = None) -> dict[str, int]: """Return or consume 1 or 0 depending on `self.state` and `self.bit`. If `self.state`, we return a bit in the `q` register. Otherwise, @@ -126,7 +116,7 @@ def on_classical_vals(self, *, q: Optional[int] = None) -> Dict[str, int]: def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', **cirq_quregs: 'CirqQuregT' # type: ignore[type-var] - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: # type: ignore[type-var] if not self.state: raise ValueError(f"There is no Cirq equivalent for {self}") @@ -145,7 +135,7 @@ def __str__(self) -> str: return f'|{s}>' if self.state else f'<{s}|' def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('') @@ -258,8 +248,8 @@ def decompose_bloq(self) -> 'CompositeBloq': raise DecomposeTypeError(f"{self} is atomic") def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ @@ -268,7 +258,7 @@ def my_tensors( ) ] - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: if ctrl_spec != CtrlSpec(): # Delegate to the general superclass behavior return super().get_ctrl_system(ctrl_spec=ctrl_spec) @@ -276,8 +266,8 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlled bloq = CZ() def add_controlled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: (ctrl_soq,) = ctrl_soqs ctrl_soq, q2 = bb.add(bloq, q1=ctrl_soq, q2=in_soqs['q']) return (ctrl_soq,), (q2,) @@ -286,7 +276,7 @@ def add_controlled( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q: 'CirqQuregT' - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: import cirq (q,) = q @@ -298,7 +288,7 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.Z(wires=wires) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('') @@ -335,8 +325,8 @@ def adjoint(self) -> 'Bloq': return self def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn unitary = np.diag(np.array([1, 1, 1, -1], dtype=np.complex128)).reshape((2, 2, 2, 2)) @@ -346,7 +336,7 @@ def my_tensors( def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q1: 'CirqQuregT', q2: 'CirqQuregT' - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: import cirq (q1,) = q1 @@ -358,21 +348,21 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return qml.CZ(wires=wires) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'q1' or reg.name == 'q2': return Circle() raise ValueError(f'Unknown wire symbol register name: {reg.name}') - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv_from_bloqs return get_ctrl_system_1bit_cv_from_bloqs( self, ctrl_spec, current_ctrl_bit=1, bloq_with_ctrl=self, ctrl_reg_name='q1' ) - def on_classical_vals(self, **vals: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, **vals: 'ClassicalValT') -> dict[str, 'ClassicalValT']: # Diagonal, but causes phases: see `basis_state_phase` return vals @@ -410,8 +400,8 @@ def on_classical_vals(self, q: int) -> Mapping[str, 'ClassicalValRetT']: return {'c': q} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn from qualtran.simulation.tensor import DiscardInd @@ -469,7 +459,7 @@ def signature(self) -> Signature: return Signature([Register('val', self.dtype, side=side)]) @staticmethod - def _build_composite_state(bb: 'BloqBuilder', bits: NDArray[np.uint8]) -> Dict[str, 'SoquetT']: + def _build_composite_state(bb: 'BloqBuilder', bits: NDArray[np.uint8]) -> dict[str, 'SoquetT']: states = [ZeroState(), OneState()] xs = [] for bit in bits: @@ -482,14 +472,14 @@ def _build_composite_state(bb: 'BloqBuilder', bits: NDArray[np.uint8]) -> Dict[s @staticmethod def _build_composite_effect( bb: 'BloqBuilder', val: 'Soquet', bits: NDArray[np.uint8] - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: xs = bb.split(val) effects = [ZeroEffect(), OneEffect()] for i, bit in enumerate(bits): bb.add(effects[bit], q=xs[i]) return {} - def build_composite_bloq(self, bb: 'BloqBuilder', **val: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **val: 'SoquetT') -> dict[str, 'SoquetT']: if isinstance(self.bitsize, sympy.Expr): raise DecomposeTypeError(f'Symbolic bitsize {self.bitsize} not supported') bits = np.asarray(self.dtype.to_bits(self.val)) @@ -499,7 +489,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **val: 'SoquetT') -> Dict[str, else: return self._build_composite_effect(bb, cast(Soquet, val['val']), bits) - def on_classical_vals(self, *, val: Optional[int] = None) -> Dict[str, Union[int, sympy.Expr]]: + def on_classical_vals(self, *, val: Optional[int] = None) -> dict[str, Union[int, sympy.Expr]]: if self.state: assert val is None return {'val': self.val} @@ -514,7 +504,7 @@ def __str__(self) -> str: s = f'{self.val}' return f'|{s}>' if self.state else f'<{s}|' - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') diff --git a/qualtran/bloqs/block_encoding/chebyshev_polynomial.py b/qualtran/bloqs/block_encoding/chebyshev_polynomial.py index 327d0ace4b..38728f98b9 100644 --- a/qualtran/bloqs/block_encoding/chebyshev_polynomial.py +++ b/qualtran/bloqs/block_encoding/chebyshev_polynomial.py @@ -13,7 +13,7 @@ # limitations under the License. from collections import Counter from functools import cached_property -from typing import Dict, Tuple, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import attrs import numpy as np @@ -123,7 +123,7 @@ def reflection_bloq(self): bitsizes=(self.ancilla_bitsize,), global_phase=-1 ) - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: if is_symbolic(self.ancilla_bitsize): raise DecomposeTypeError(f"Cannot decompose symbolic {self=}") for _ in range(self.order // 2): @@ -233,15 +233,15 @@ def epsilon(self) -> SymbolicFloat: return self.linear_combination.epsilon @property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return tuple(self.signature.rights()) @property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return (self.signature.get_right("resource"),) if self.resource_bitsize > 0 else () @property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (self.signature.get_right("ancilla"),) if self.ancilla_bitsize > 0 else () @property @@ -264,7 +264,7 @@ def linear_combination(self) -> Union[LinearCombination, ChebyshevPolynomial]: self.lambd_bits, ) - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: return bb.add_d(self.linear_combination, **soqs) def __str__(self) -> str: diff --git a/qualtran/bloqs/block_encoding/chebyshev_polynomial_test.py b/qualtran/bloqs/block_encoding/chebyshev_polynomial_test.py index 2bc29ea862..9ace3a038b 100644 --- a/qualtran/bloqs/block_encoding/chebyshev_polynomial_test.py +++ b/qualtran/bloqs/block_encoding/chebyshev_polynomial_test.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Tuple import numpy as np import pytest @@ -180,7 +179,7 @@ class TestBlockEncoding(BlockEncoding): """Instance of `BlockEncoding` to block encode a matrix with one system qubit by adding one ancilla qubit and one resource qubit.""" - matrix: Tuple[Tuple[complex, ...], ...] = field( + matrix: tuple[tuple[complex, ...], ...] = field( converter=lambda mat: tuple(tuple(row) for row in mat) ) alpha: SymbolicFloat = 1 @@ -210,7 +209,7 @@ def signal_state(self) -> BlackBoxPrepare: def build_composite_bloq( self, bb: BloqBuilder, system: Soquet, ancilla: Soquet, resource: Soquet - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: bits = bb.join(np.array([system, ancilla, resource])) bits = bb.add(MatrixGate(3, self.matrix, atol=3e-8), q=bits) system, ancilla, resource = bb.split(bits) diff --git a/qualtran/bloqs/block_encoding/lcu_block_encoding.py b/qualtran/bloqs/block_encoding/lcu_block_encoding.py index 679ac7964b..1996a4138e 100644 --- a/qualtran/bloqs/block_encoding/lcu_block_encoding.py +++ b/qualtran/bloqs/block_encoding/lcu_block_encoding.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple, Union +from typing import Optional, Union import attrs @@ -40,7 +40,7 @@ from qualtran.symbolics import SymbolicFloat -def _total_bits(registers: Union[Tuple[Register, ...], Signature]) -> int: +def _total_bits(registers: Union[tuple[Register, ...], Signature]) -> int: """Get the bitsize of a collection of registers""" return sum(r.total_bits() for r in registers) @@ -111,15 +111,15 @@ def system_bitsize(self) -> int: return _total_bits(self.select.target_registers) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.select.selection_registers @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return () @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return self.select.target_registers @property @@ -139,12 +139,12 @@ def signature(self) -> Signature: def signal_state(self) -> Union[BlackBoxPrepare, PrepareOracle]: return self.prepare - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: SoquetT) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: SoquetT) -> dict[str, 'SoquetT']: select_reg = {reg.name: soqs[reg.name] for reg in self.select.signature} soqs |= bb.add_d(self.select, **select_reg) return soqs - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') else: @@ -205,7 +205,7 @@ class LCUBlockEncoding(BlockEncoding): control_val: Optional[int] = None @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('ctrl', QBit()),) @cached_property @@ -221,15 +221,15 @@ def system_bitsize(self) -> int: return _total_bits(self.select.target_registers) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.prepare.selection_registers @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return tuple(reg for reg in self.prepare.junk_registers if reg.side == Side.THRU) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return self.select.target_registers @property @@ -257,8 +257,8 @@ def signature(self) -> Signature: def signal_state(self) -> Union[BlackBoxPrepare, PrepareOracle]: return PrepareIdentity(self.selection_registers) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: SoquetT) -> Dict[str, 'SoquetT']: - def _extract_soqs(bloq: Bloq) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: SoquetT) -> dict[str, 'SoquetT']: + def _extract_soqs(bloq: Bloq) -> dict[str, 'SoquetT']: return {reg.name: soqs.pop(reg.name) for reg in bloq.signature.lefts()} soqs |= bb.add_d(self.prepare, **_extract_soqs(self.prepare)) @@ -276,7 +276,7 @@ def _extract_soqs(bloq: Bloq) -> Dict[str, 'SoquetT']: return soqs - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'control': diff --git a/qualtran/bloqs/block_encoding/linear_combination.py b/qualtran/bloqs/block_encoding/linear_combination.py index 48c93ef48d..37890f5b80 100644 --- a/qualtran/bloqs/block_encoding/linear_combination.py +++ b/qualtran/bloqs/block_encoding/linear_combination.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import cast, Dict, List, Optional, Tuple, Union +from typing import cast, Optional, Union import numpy as np from attrs import evolve, field, frozen, validators @@ -83,10 +83,10 @@ class LinearCombination(BlockEncoding): Dalzell et al. (2023). Ch. 10.2. """ - _block_encodings: Tuple[BlockEncoding, ...] = field( + _block_encodings: tuple[BlockEncoding, ...] = field( converter=lambda x: x if isinstance(x, tuple) else tuple(x), validator=validators.min_len(2) ) - _lambd: Tuple[float, ...] = field(converter=lambda x: x if isinstance(x, tuple) else tuple(x)) + _lambd: tuple[float, ...] = field(converter=lambda x: x if isinstance(x, tuple) else tuple(x)) lambd_bits: SymbolicInt _prepare: Optional[BlackBoxPrepare] = None @@ -121,7 +121,7 @@ def __attrs_post_init__(self): ) @classmethod - def of_terms(cls, *terms: Tuple[float, BlockEncoding], lambd_bits: SymbolicInt = 1) -> Self: + def of_terms(cls, *terms: tuple[float, BlockEncoding], lambd_bits: SymbolicInt = 1) -> Self: """Construct a `LinearCombination` from pairs of (coefficient, block encoding).""" return cls(tuple(t[1] for t in terms), tuple(t[0] for t in terms), lambd_bits) @@ -232,11 +232,11 @@ def select(self) -> BlackBoxSelect: assert not is_symbolic(be.ancilla_bitsize) assert not is_symbolic(be.resource_bitsize) - partitions: List[Tuple[Register, List[Union[str, Unused]]]] = [ + partitions: list[tuple[Register, list[Union[str, Unused]]]] = [ (Register("system", QAny(self.system_bitsize)), ["system"]) ] if self.be_ancilla_bitsize > 0: - regs: List[Union[str, Unused]] = [] + regs: list[Union[str, Unused]] = [] if be.ancilla_bitsize > 0: regs.append("ancilla") if self.be_ancilla_bitsize > be.ancilla_bitsize: @@ -259,7 +259,7 @@ def select(self) -> BlackBoxSelect: def build_composite_bloq( self, bb: BloqBuilder, system: Soquet, ancilla: Soquet, **soqs: SoquetT - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: if ( is_symbolic(self.system_bitsize) or is_symbolic(self.ancilla_bitsize) @@ -272,7 +272,7 @@ def build_composite_bloq( assert not is_symbolic(self.select.system_bitsize) # partition ancilla register - be_system_soqs: Dict[str, SoquetT] = {"system": system} + be_system_soqs: dict[str, SoquetT] = {"system": system} anc_regs = [Register("selection", QAny(self.prepare.selection_bitsize))] if self.be_ancilla_bitsize > 0: anc_regs.append(Register("ancilla", QAny(self.be_ancilla_bitsize))) @@ -331,7 +331,7 @@ def build_composite_bloq( # partition system register of Select into system, ancilla, resource of block encoding be_soqs = bb.add_d(be_part, x=select_out_soqs.pop("system")) - out: Dict[str, SoquetT] = {"system": be_soqs.pop("system")} + out: dict[str, SoquetT] = {"system": be_soqs.pop("system")} if self.is_controlled: out["ctrl"] = select_out_soqs.pop("ctrl") diff --git a/qualtran/bloqs/block_encoding/phase.py b/qualtran/bloqs/block_encoding/phase.py index d7e6b03237..f6cc0955af 100644 --- a/qualtran/bloqs/block_encoding/phase.py +++ b/qualtran/bloqs/block_encoding/phase.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict from attrs import frozen @@ -82,7 +81,7 @@ def signal_state(self) -> BlackBoxPrepare: def build_call_graph(self, ssa: SympySymbolAllocator) -> BloqCountDictT: return {self.block_encoding: 1, GlobalPhase(exponent=self.phi, eps=self.eps): 1} - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: bb.add(GlobalPhase(exponent=self.phi, eps=self.eps)) return bb.add_d(self.block_encoding, **soqs) diff --git a/qualtran/bloqs/block_encoding/product.py b/qualtran/bloqs/block_encoding/product.py index 6a28762a12..3879c27ee9 100644 --- a/qualtran/bloqs/block_encoding/product.py +++ b/qualtran/bloqs/block_encoding/product.py @@ -13,8 +13,9 @@ # limitations under the License. from collections import Counter +from collections.abc import Sequence from functools import cached_property -from typing import cast, Dict, List, Sequence, Tuple, Union +from typing import cast, Union from attrs import field, frozen, validators from numpy.typing import NDArray @@ -85,7 +86,7 @@ class Product(BlockEncoding): Dalzell et al. (2023). Ch. 10.2. """ - block_encodings: Tuple[BlockEncoding, ...] = field( + block_encodings: tuple[BlockEncoding, ...] = field( converter=lambda x: x if isinstance(x, tuple) else tuple(x), validator=validators.min_len(1) ) @@ -151,11 +152,11 @@ def constituents(self) -> Sequence[Bloq]: anc_bits = self.ancilla_bitsize - (n - 1) ret = [] for u in reversed(self.block_encodings): - partition: List[Tuple[Register, List[Union[str, Unused]]]] = [ + partition: list[tuple[Register, list[Union[str, Unused]]]] = [ (Register("system", dtype=QAny(u.system_bitsize)), ["system"]) ] if is_symbolic(u.ancilla_bitsize) or u.ancilla_bitsize > 0: - regs: List[Union[str, Unused]] = ["ancilla"] + regs: list[Union[str, Unused]] = ["ancilla"] if ( is_symbolic(anc_bits) or is_symbolic(u.ancilla_bitsize) @@ -184,7 +185,7 @@ def build_call_graph(self, ssa: SympySymbolAllocator) -> BloqCountDictT: def build_composite_bloq( self, bb: BloqBuilder, system: SoquetT, **soqs: SoquetT - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: if ( is_symbolic(self.system_bitsize) or is_symbolic(self.ancilla_bitsize) @@ -242,7 +243,7 @@ def build_composite_bloq( if self.resource_bitsize > 0: out["resource"] = res_soq if self.ancilla_bitsize > 0: - anc_soqs: Dict[str, SoquetT] = dict() + anc_soqs: dict[str, SoquetT] = dict() if n - 1 > 0: anc_soqs["flag_bits"] = flag_bits_soq if anc_bits > 0: diff --git a/qualtran/bloqs/block_encoding/product_test.py b/qualtran/bloqs/block_encoding/product_test.py index 389ffb997e..fc98b83929 100644 --- a/qualtran/bloqs/block_encoding/product_test.py +++ b/qualtran/bloqs/block_encoding/product_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import cast, Tuple +from typing import cast import cirq import numpy as np @@ -71,11 +71,11 @@ def test_product_signature(): @frozen class TestPrepareOracle(PrepareOracle): @property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('z', QBit()),) @property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return (Register('a', QAny(5)),) diff --git a/qualtran/bloqs/block_encoding/rewrites.py b/qualtran/bloqs/block_encoding/rewrites.py index 209c5aad53..028e3068e7 100644 --- a/qualtran/bloqs/block_encoding/rewrites.py +++ b/qualtran/bloqs/block_encoding/rewrites.py @@ -15,7 +15,6 @@ r"""Rewrite rules to optimize the construction of block encodings.""" from collections import defaultdict -from typing import Dict from qualtran.bloqs.block_encoding import ( BlockEncoding, @@ -57,7 +56,7 @@ def collect_like_terms(x: BlockEncoding) -> BlockEncoding: if isinstance(x, Product): return Product(tuple(collect_like_terms(y) for y in x.block_encodings)) if isinstance(x, LinearCombination): - block_encodings: Dict[BlockEncoding, float] = defaultdict(float) + block_encodings: dict[BlockEncoding, float] = defaultdict(float) terms = tuple(collect_like_terms(y) for y in x._block_encodings) lambd_bits = x.lambd_bits for y, l in zip(terms, x._lambd): diff --git a/qualtran/bloqs/block_encoding/sparse_matrix.py b/qualtran/bloqs/block_encoding/sparse_matrix.py index 7c126c77a9..dc461a50cc 100644 --- a/qualtran/bloqs/block_encoding/sparse_matrix.py +++ b/qualtran/bloqs/block_encoding/sparse_matrix.py @@ -13,8 +13,8 @@ # limitations under the License. import abc +from collections.abc import Iterable from functools import cached_property -from typing import Dict, Iterable, Tuple import numpy as np import sympy @@ -233,7 +233,7 @@ def build_call_graph(self, ssa: SympySymbolAllocator) -> BloqCountDictT: def build_composite_bloq( self, bb: BloqBuilder, system: SoquetT, ancilla: SoquetT - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: if is_symbolic(self.system_bitsize) or is_symbolic(self.row_oracle.num_nonzero): raise DecomposeTypeError(f"Cannot decompose symbolic {self=}") @@ -281,7 +281,7 @@ def _num_nonzero_default(self): def num_nonzero(self) -> SymbolicInt: return self._num_nonzero - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: # the l-th non-zero entry is at position l, so do nothing return soqs @@ -319,7 +319,7 @@ def __attrs_post_init__(self): f"bandsize={self.bandsize} too large for system_bitsize={self.system_bitsize}" ) - def call_classically(self, l: ClassicalValT, i: ClassicalValT) -> Tuple[ClassicalValT, ...]: + def call_classically(self, l: ClassicalValT, i: ClassicalValT) -> tuple[ClassicalValT, ...]: if ( is_symbolic(self.bandsize) or is_symbolic(self.system_bitsize) @@ -338,7 +338,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> BloqCountDictT: AddK(QInt(self.system_bitsize), -self.bandsize): 1, } - def build_composite_bloq(self, bb: BloqBuilder, l: SoquetT, i: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, l: SoquetT, i: SoquetT) -> dict[str, SoquetT]: if is_symbolic(self.system_bitsize) or is_symbolic(self.bandsize): raise DecomposeTypeError(f"Cannot decompose symbolic {self=}") @@ -357,7 +357,7 @@ class UniformEntryOracle(EntryOracle): def build_composite_bloq( self, bb: BloqBuilder, q: Soquet, **soqs: SoquetT - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: # Either Rx or Ry work here; Rx would induce a phase on the subspace with non-zero ancilla # See https://arxiv.org/abs/2302.10949 for reference that uses Rx soqs["q"] = bb.add(Ry(2 * np.arccos(self.entry)), q=q) @@ -404,7 +404,7 @@ def __attrs_post_init__(self): def build_composite_bloq( self, bb: BloqBuilder, q: SoquetT, i: SoquetT, j: SoquetT - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: if is_symbolic(self.entry_bitsize): raise DecomposeTypeError(f"Cannot decompose symbolic {self=}") # load from QROM diff --git a/qualtran/bloqs/block_encoding/tensor_product.py b/qualtran/bloqs/block_encoding/tensor_product.py index d1a01a8ecc..3efa7dff71 100644 --- a/qualtran/bloqs/block_encoding/tensor_product.py +++ b/qualtran/bloqs/block_encoding/tensor_product.py @@ -14,7 +14,6 @@ from collections import Counter from functools import cached_property -from typing import Dict, Tuple from attrs import evolve, field, frozen, validators from typing_extensions import Self @@ -61,7 +60,7 @@ class TensorProduct(BlockEncoding): [Quantum algorithms: A survey of applications and end-to-end complexities](https://arxiv.org/abs/2310.03011). Dalzell et al. (2023). Ch. 10.2. """ - block_encodings: Tuple[BlockEncoding, ...] = field( + block_encodings: tuple[BlockEncoding, ...] = field( converter=lambda x: x if isinstance(x, tuple) else tuple(x), validator=validators.min_len(1) ) @@ -111,7 +110,7 @@ def build_call_graph(self, ssa: SympySymbolAllocator) -> BloqCountDictT: def build_composite_bloq( self, bb: BloqBuilder, system: SoquetT, **soqs: SoquetT - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: if ( is_symbolic(self.system_bitsize) or is_symbolic(self.ancilla_bitsize) diff --git a/qualtran/bloqs/block_encoding/unitary.py b/qualtran/bloqs/block_encoding/unitary.py index bbcff63d78..1cd795a10e 100644 --- a/qualtran/bloqs/block_encoding/unitary.py +++ b/qualtran/bloqs/block_encoding/unitary.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict from attrs import frozen @@ -79,7 +78,7 @@ def build_call_graph(self, ssa: SympySymbolAllocator) -> BloqCountDictT: def build_composite_bloq( self, bb: BloqBuilder, system: SoquetT, **soqs: SoquetT - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: partitions = [(self.signature.get_left("system"), tuple(r.name for r in self.U.signature))] return { "system": bb.add_and_partition(self.U, partitions=partitions, system=system), diff --git a/qualtran/bloqs/bookkeeping/_bookkeeping_bloq.py b/qualtran/bloqs/bookkeeping/_bookkeeping_bloq.py index 32b9b74984..3217fc57eb 100644 --- a/qualtran/bloqs/bookkeeping/_bookkeeping_bloq.py +++ b/qualtran/bloqs/bookkeeping/_bookkeeping_bloq.py @@ -13,7 +13,8 @@ # limitations under the License. import abc -from typing import Dict, Iterable, Optional, Sequence, Tuple, TYPE_CHECKING +from collections.abc import Iterable, Sequence +from typing import Optional, TYPE_CHECKING from qualtran import Bloq, BloqBuilder, SoquetT @@ -32,10 +33,10 @@ class _BookkeepingBloq(Bloq, metaclass=abc.ABCMeta): def get_ctrl_system( self, ctrl_spec: Optional['CtrlSpec'] = None - ) -> Tuple['Bloq', 'AddControlledT']: + ) -> tuple['Bloq', 'AddControlledT']: def add_controlled( - bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT'] - ) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]: + bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT'] + ) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]: # ignore `ctrl_soq` and pass it through for bookkeeping operation. out_soqs = bb.add_t(self, **in_soqs) return ctrl_soqs, out_soqs diff --git a/qualtran/bloqs/bookkeeping/allocate.py b/qualtran/bloqs/bookkeeping/allocate.py index e459095285..74df4525be 100644 --- a/qualtran/bloqs/bookkeeping/allocate.py +++ b/qualtran/bloqs/bookkeeping/allocate.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, List, Tuple, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import numpy as np import sympy @@ -70,12 +70,12 @@ def adjoint(self) -> 'Bloq': return Free(self.dtype, self.dirty) - def on_classical_vals(self) -> Dict[str, int]: + def on_classical_vals(self) -> dict[str, int]: return {'reg': self.dtype.from_bits([0] * self.dtype.num_qubits)} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn from qualtran.bloqs.basic_gates.z_basis import _ZERO @@ -85,7 +85,7 @@ def my_tensors( for i in range(self.dtype.num_qubits) ] - def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Register, idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') assert reg.name == 'reg' @@ -93,7 +93,7 @@ def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSym def as_cirq_op( self, qubit_manager: 'cirq.QubitManager' - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: shape = (*self.signature[0].shape, self.signature[0].bitsize) qubits = ( qubit_manager.qborrow(self.signature.n_qubits()) diff --git a/qualtran/bloqs/bookkeeping/always.py b/qualtran/bloqs/bookkeeping/always.py index 070e34eaf9..c297bc8c62 100644 --- a/qualtran/bloqs/bookkeeping/always.py +++ b/qualtran/bloqs/bookkeeping/always.py @@ -11,7 +11,8 @@ # 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 typing import Iterable, Optional, Sequence +from collections.abc import Iterable, Sequence +from typing import Optional import attrs diff --git a/qualtran/bloqs/bookkeeping/auto_partition.py b/qualtran/bloqs/bookkeeping/auto_partition.py index 93cddd9cbb..cc65abe662 100644 --- a/qualtran/bloqs/bookkeeping/auto_partition.py +++ b/qualtran/bloqs/bookkeeping/auto_partition.py @@ -11,9 +11,10 @@ # 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 collections.abc import Sequence from functools import cached_property from itertools import chain -from typing import Dict, Sequence, Tuple, Union +from typing import Union from attrs import evolve, field, frozen @@ -70,7 +71,7 @@ class AutoPartition(Bloq): """ bloq: Bloq - partitions: Sequence[Tuple[Register, Sequence[Union[str, Unused]]]] = field( + partitions: Sequence[tuple[Register, Sequence[Union[str, Unused]]]] = field( converter=lambda s: tuple((r, tuple(rs)) for r, rs in s) ) left_only: bool = False @@ -99,10 +100,10 @@ def signature(self) -> Signature: else: return Signature(r for r, _ in self.partitions) - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: - parts: Dict[str, Partition] = dict() - in_regs: Dict[str, SoquetT] = dict() - unused_regs: Dict[str, SoquetT] = dict() + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: + parts: dict[str, Partition] = dict() + in_regs: dict[str, SoquetT] = dict() + unused_regs: dict[str, SoquetT] = dict() for parti, (out_reg, bloq_regs) in enumerate(self.partitions): part = Partition( out_reg.bitsize, diff --git a/qualtran/bloqs/bookkeeping/cast.py b/qualtran/bloqs/bookkeeping/cast.py index 9fd7bee565..c42c8d71c5 100644 --- a/qualtran/bloqs/bookkeeping/cast.py +++ b/qualtran/bloqs/bookkeeping/cast.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, List, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import numpy as np @@ -67,7 +67,7 @@ class Cast(_BookkeepingBloq): inp_dtype: QCDType out_dtype: QCDType - shape: Tuple[int, ...] = attrs.field( + shape: tuple[int, ...] = attrs.field( default=tuple(), converter=lambda v: (v,) if isinstance(v, int) else tuple(v) ) allow_quantum_to_classical: bool = attrs.field(default=False, kw_only=True) @@ -108,8 +108,8 @@ def adjoint(self) -> 'Bloq': return Cast(inp_dtype=self.out_dtype, out_dtype=self.inp_dtype) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ @@ -119,11 +119,11 @@ def my_tensors( for j in range(self.out_dtype.num_bits) ] - def on_classical_vals(self, reg: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, reg: int) -> dict[str, 'ClassicalValT']: res = self.out_dtype.from_bits(self.inp_dtype.to_bits(reg)) return {'reg': res} - def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> Tuple[None, Dict[str, 'CirqQuregT']]: + def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> tuple[None, dict[str, 'CirqQuregT']]: return None, {'reg': reg} def as_pl_op(self, wires: 'Wires') -> 'Operation': diff --git a/qualtran/bloqs/bookkeeping/free.py b/qualtran/bloqs/bookkeeping/free.py index 8a0c73db71..611240ea94 100644 --- a/qualtran/bloqs/bookkeeping/free.py +++ b/qualtran/bloqs/bookkeeping/free.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, List, Tuple, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import sympy from attrs import frozen @@ -78,14 +78,14 @@ def adjoint(self) -> 'Bloq': return Allocate(self.dtype, self.dirty) - def on_classical_vals(self, reg: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, reg: int) -> dict[str, 'ClassicalValT']: if reg != 0 and not self.dirty: raise ValueError(f"Tried to free a non-zero register: {reg} with {self.dirty=}") return {} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn from qualtran.bloqs.basic_gates.z_basis import _ZERO @@ -95,7 +95,7 @@ def my_tensors( for i in range(self.dtype.num_qubits) ] - def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Register, idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') assert reg.name == 'reg' @@ -103,7 +103,7 @@ def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSym def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', reg: 'CirqQuregT' - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: qubit_manager.qfree(reg.flatten().tolist()) return (None, {}) diff --git a/qualtran/bloqs/bookkeeping/join.py b/qualtran/bloqs/bookkeeping/join.py index b194add90d..8fa8d24c29 100644 --- a/qualtran/bloqs/bookkeeping/join.py +++ b/qualtran/bloqs/bookkeeping/join.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import cast, Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import cast, Optional, TYPE_CHECKING import numpy as np from attrs import field, frozen @@ -79,15 +79,15 @@ def adjoint(self) -> 'Bloq': return Split(dtype=self.dtype) - def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> Tuple[None, Dict[str, 'CirqQuregT']]: + def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> tuple[None, dict[str, 'CirqQuregT']]: return None, {'reg': reg.reshape(self.dtype.num_qubits)} def as_pl_op(self, wires: 'Wires') -> 'Operation': return None def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn eye = np.eye(2) @@ -98,10 +98,10 @@ def my_tensors( for i in range(self.dtype.num_qubits) ] - def on_classical_vals(self, reg: 'NDArray[np.uint]') -> Dict[str, int]: + def on_classical_vals(self, reg: 'NDArray[np.uint]') -> dict[str, int]: return {'reg': self.dtype.from_bits(reg.tolist())} - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.shape: diff --git a/qualtran/bloqs/bookkeeping/partition.py b/qualtran/bloqs/bookkeeping/partition.py index 5c2d44881b..af5333ebb2 100644 --- a/qualtran/bloqs/bookkeeping/partition.py +++ b/qualtran/bloqs/bookkeeping/partition.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, List, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np from attrs import evolve, field, frozen, validators @@ -58,7 +58,7 @@ class Partition(_BookkeepingBloq): """ n: SymbolicInt - regs: Tuple[Register, ...] = field( + regs: tuple[Register, ...] = field( converter=lambda x: x if isinstance(x, tuple) else tuple(x), validator=validators.min_len(1) ) partition: bool = True @@ -89,7 +89,7 @@ def decompose_bloq(self) -> 'CompositeBloq': def adjoint(self): return evolve(self, partition=not self.partition) - def as_cirq_op(self, qubit_manager, **cirq_quregs) -> Tuple[None, Dict[str, 'CirqQuregT']]: + def as_cirq_op(self, qubit_manager, **cirq_quregs) -> tuple[None, dict[str, 'CirqQuregT']]: if self.partition: outregs = {} start = 0 @@ -106,8 +106,8 @@ def as_pl_op(self, wires: 'Wires') -> 'Operation': return None def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn if is_symbolic(self.n): @@ -131,7 +131,7 @@ def my_tensors( for j in range(self.n) ] - def _classical_partition(self, x: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + def _classical_partition(self, x: 'ClassicalValT') -> dict[str, 'ClassicalValT']: out_vals = {} xbits = self.lumped_dtype.to_bits(x) start = 0 @@ -155,7 +155,7 @@ def _classical_unpartition_to_bits(self, **vals: 'ClassicalValT') -> NDArray[np. out_vals.append(bitstrings.ravel()) return np.concatenate(out_vals) - def on_classical_vals(self, **vals: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, **vals: 'ClassicalValT') -> dict[str, 'ClassicalValT']: if self.partition: return self._classical_partition(vals['x']) else: @@ -163,7 +163,7 @@ def on_classical_vals(self, **vals: 'ClassicalValT') -> Dict[str, 'ClassicalValT big_int = self.lumped_dtype.from_bits(big_int_bits.tolist()) return {'x': big_int} - def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Register, idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.shape: diff --git a/qualtran/bloqs/bookkeeping/partition_test.py b/qualtran/bloqs/bookkeeping/partition_test.py index 42dce656ea..a97a0cfc4e 100644 --- a/qualtran/bloqs/bookkeeping/partition_test.py +++ b/qualtran/bloqs/bookkeeping/partition_test.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict import cirq import numpy as np @@ -55,7 +54,7 @@ def bitsize(self): def signature(self) -> Signature: return Signature.build(test_regs=self.bitsize) - def build_composite_bloq(self, bb: 'BloqBuilder', test_regs: 'SoquetT') -> Dict[str, 'Soquet']: + def build_composite_bloq(self, bb: 'BloqBuilder', test_regs: 'SoquetT') -> dict[str, 'Soquet']: bloq_regs = self.test_bloq.signature partition = Partition(self.bitsize, bloq_regs) # type: ignore[arg-type] out_regs = bb.add(partition, x=test_regs) diff --git a/qualtran/bloqs/bookkeeping/split.py b/qualtran/bloqs/bookkeeping/split.py index ab02e2e6f4..4ed8ad9c0b 100644 --- a/qualtran/bloqs/bookkeeping/split.py +++ b/qualtran/bloqs/bookkeeping/split.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import cast, Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import cast, Optional, TYPE_CHECKING import numpy as np from attrs import field, frozen @@ -85,18 +85,18 @@ def adjoint(self) -> 'Bloq': return Join(dtype=self.dtype) - def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> Tuple[None, Dict[str, 'CirqQuregT']]: + def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> tuple[None, dict[str, 'CirqQuregT']]: return None, {'reg': reg.reshape((self.dtype.num_qubits, 1))} def as_pl_op(self, wires: 'Wires') -> 'Operation': return None - def on_classical_vals(self, reg: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, reg: int) -> dict[str, 'ClassicalValT']: return {'reg': np.asarray(self.dtype.to_bits(reg))} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn eye = np.eye(2) @@ -107,7 +107,7 @@ def my_tensors( for i in range(self.dtype.num_qubits) ] - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.shape: diff --git a/qualtran/bloqs/chemistry/black_boxes.py b/qualtran/bloqs/chemistry/black_boxes.py index f9670a2eba..032870579a 100644 --- a/qualtran/bloqs/chemistry/black_boxes.py +++ b/qualtran/bloqs/chemistry/black_boxes.py @@ -16,7 +16,7 @@ These are for temporary convenience to lock-in the quoted literature costs. """ from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import attrs import numpy as np @@ -190,7 +190,7 @@ class ApplyControlledZs(Bloq): system: system register """ - cvs: Tuple[int, ...] = field(converter=lambda v: (v,) if isinstance(v, int) else tuple(v)) + cvs: tuple[int, ...] = field(converter=lambda v: (v,) if isinstance(v, int) else tuple(v)) bitsize: int @cached_property @@ -202,7 +202,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("C" * len(self.cvs) + "Z") if reg.name == 'system': diff --git a/qualtran/bloqs/chemistry/chem_tutorials.py b/qualtran/bloqs/chemistry/chem_tutorials.py index e2ae163c0e..18e3d6f14e 100644 --- a/qualtran/bloqs/chemistry/chem_tutorials.py +++ b/qualtran/bloqs/chemistry/chem_tutorials.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. """Some utility functions for chemistry tutorials""" -from typing import Optional, Tuple +from typing import Optional import matplotlib.pyplot as plt import numpy as np @@ -34,7 +34,7 @@ def linear(x: NDArray[np.float64], a: float, c: float) -> NDArray[np.float64]: return a * x + c -def fit_linear(x: NDArray[np.float64], y: NDArray[np.float64]) -> Tuple[float, float]: +def fit_linear(x: NDArray[np.float64], y: NDArray[np.float64]) -> tuple[float, float]: """Fit a line given x and y values. Args: diff --git a/qualtran/bloqs/chemistry/df/double_factorization.py b/qualtran/bloqs/chemistry/df/double_factorization.py index e83b385240..c1f8b236a2 100644 --- a/qualtran/bloqs/chemistry/df/double_factorization.py +++ b/qualtran/bloqs/chemistry/df/double_factorization.py @@ -30,8 +30,9 @@ $$ where $\Xi^{(l)} $ is the rank of second factorization. """ +from collections.abc import Iterable from functools import cached_property -from typing import Dict, Iterable, TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np from attrs import frozen @@ -193,7 +194,7 @@ def build_composite_bloq( rot: SoquetT, rotations: SoquetT, sys: NDArray[Soquet], # type: ignore[type-var] - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: # 1st half in_prep = InnerPrepareDoubleFactorization( num_aux=self.num_aux, @@ -438,7 +439,7 @@ def build_composite_bloq( rot: SoquetT, rotations: SoquetT, sys: SoquetT, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: succ_l, l_ne_zero, theta, succ_p = ctrl n_n = (self.num_spin_orb // 2 - 1).bit_length() # C14 outer_prep = OuterPrepareDoubleFactorization( diff --git a/qualtran/bloqs/chemistry/hubbard_model/qubitization/prepare_hubbard.py b/qualtran/bloqs/chemistry/hubbard_model/qubitization/prepare_hubbard.py index cfdbf20b0b..0b60b3b29f 100644 --- a/qualtran/bloqs/chemistry/hubbard_model/qubitization/prepare_hubbard.py +++ b/qualtran/bloqs/chemistry/hubbard_model/qubitization/prepare_hubbard.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator from functools import cached_property -from typing import Iterator, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import cirq @@ -79,7 +80,7 @@ def __attrs_post_init__(self): raise NotImplementedError("Currently only supports the case where x_dim=y_dim.") @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return ( Register('U', BQUInt(1, 2)), Register('V', BQUInt(1, 2)), @@ -92,7 +93,7 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return (Register('temp', QAny(2)),) @cached_property diff --git a/qualtran/bloqs/chemistry/hubbard_model/qubitization/select_hubbard.py b/qualtran/bloqs/chemistry/hubbard_model/qubitization/select_hubbard.py index 66a123fa5b..8d968134ac 100644 --- a/qualtran/bloqs/chemistry/hubbard_model/qubitization/select_hubbard.py +++ b/qualtran/bloqs/chemistry/hubbard_model/qubitization/select_hubbard.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator from functools import cached_property -from typing import Iterator, Optional, Tuple +from typing import Optional import attrs import cirq @@ -96,11 +97,11 @@ def __attrs_post_init__(self): ) @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('control', QBit()),) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return ( Register('U', BQUInt(1, 2)), Register('V', BQUInt(1, 2)), @@ -113,7 +114,7 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register('target', QAny(self.x_dim * self.y_dim * 2)),) @cached_property @@ -194,7 +195,7 @@ def __str__(self): return f'C{s}' return s - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv_from_bloqs return get_ctrl_system_1bit_cv_from_bloqs( diff --git a/qualtran/bloqs/chemistry/ising/hamiltonian.py b/qualtran/bloqs/chemistry/ising/hamiltonian.py index e71db3d184..b979b7a154 100644 --- a/qualtran/bloqs/chemistry/ising/hamiltonian.py +++ b/qualtran/bloqs/chemistry/ising/hamiltonian.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. """Functions for specifying the Ising model and building LCU coefficients.""" -from typing import List, Sequence +from collections.abc import Sequence import cirq import numpy as np @@ -39,8 +39,8 @@ def get_1d_ising_pauli_terms( x_terms: The list of PauliStrings for the X terms. """ n_sites = len(qubits) - zz_terms: List[cirq.PauliString] = [] - x_terms: List[cirq.PauliString] = [] + zz_terms: list[cirq.PauliString] = [] + x_terms: list[cirq.PauliString] = [] for k in range(n_sites): zz_terms.append( cirq.PauliString( diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_nu.py b/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_nu.py index ae1e4e6bc2..e0487a655b 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_nu.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_nu.py @@ -13,7 +13,7 @@ # limitations under the License. r"""Bloqs for preparation of the U and V parts of the first quantized chemistry Hamiltonian.""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import evolve, frozen @@ -63,7 +63,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {Toffoli(): (self.num_bits_p - 1)} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(r'PREP √(2^μ)|μ⟩') @@ -115,7 +115,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {Toffoli(): (3 * (self.num_bits_p - 1))} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(r'PREP (2^-μ)|μ⟩|ν⟩') @@ -165,7 +165,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {Toffoli(): (3 * self.num_bits_p + 2)} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(r'ν≠−0') @@ -215,7 +215,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {Toffoli(): 3 * self.num_bits_p} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(r'ν<2^(μ−2)') @@ -298,7 +298,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return dict([cost_1, cost_2, cost_3, cost_4]) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(r'(2^(μ-2))^2 M > m ν^2') @@ -368,7 +368,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: BloqBuilder, mu: SoquetT, nu: SoquetT, m: SoquetT, flag_nu: SoquetT - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: mu, flag_mu = bb.add(PrepareMuUnaryEncodedOneHot(self.num_bits_p), mu=mu) mu, nu = bb.add(PrepareNuSuperPositionState(self.num_bits_p), mu=mu, nu=nu) nu, flag_zero = bb.add(FlagZeroAsFailure(self.num_bits_p), nu=nu) @@ -404,7 +404,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return dict([cost_1, cost_2, cost_3, cost_4, cost_6]) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(r"PREP 1/‖ν‖ ∣ν⟩") diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_t.py b/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_t.py index cb69fc70b1..fb666699f8 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_t.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_t.py @@ -13,7 +13,7 @@ # limitations under the License. r"""Bloqs for PREPARE T for the first quantized chemistry Hamiltonian.""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -61,7 +61,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {Toffoli(): (self.bitsize - 2)} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(r'PREP 2^(r/2) |r⟩') @@ -109,7 +109,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: BloqBuilder, w: SoquetT, r: SoquetT, s: SoquetT - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: w = bb.add(PrepareUniformSuperposition(3), target=w) r = bb.add(PreparePowerTwoState(self.num_bits_p), r=r) s = bb.add(PreparePowerTwoState(self.num_bits_p), r=s) @@ -124,7 +124,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {Toffoli(): 13, PreparePowerTwoState(bitsize=self.num_bits_p): 2} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(r'PREP T') diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_uv.py b/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_uv.py index 2c5e79f0c5..0132fd447e 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_uv.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/prepare_uv.py @@ -13,7 +13,7 @@ # limitations under the License. r"""PREPARE the potential energy terms of the first quantized chemistry Hamiltonian.""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -85,7 +85,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: BloqBuilder, mu: SoquetT, nu: SoquetT, m: SoquetT, l: SoquetT, flag_nu: SoquetT - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: mu, nu, m, flag_nu = bb.add( PrepareNuState(self.num_bits_p, self.m_param), mu=mu, nu=nu, m=m, flag_nu=flag_nu ) @@ -101,7 +101,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': } def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('PREP UV') diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_nu.py b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_nu.py index 682ab3c654..6f3c864d71 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_nu.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_nu.py @@ -13,7 +13,7 @@ # limitations under the License. r"""Bloqs for preparing the $\nu$ state for the first quantized chemistry Hamiltonian.""" from functools import cached_property -from typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING from attrs import evolve, frozen @@ -135,7 +135,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: BloqBuilder, mu: SoquetT, nu: SoquetT, m: SoquetT, flag_nu: SoquetT - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: mu, flag_mu = bb.add( PrepareMuUnaryEncodedOneHotWithProj(self.num_bits_n, self.num_bits_p), mu=mu ) diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_uv.py b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_uv.py index f66875a9c0..95b4ee8a65 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_uv.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_uv.py @@ -11,10 +11,9 @@ # 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. -r"""PREPARE the potential energy terms of the first quantized chemistry Hamiltonian with projectile. -""" +r"""PREPARE the potential energy terms of the first quantized chemistry Hamiltonian with projectile.""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -77,14 +76,14 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("PREP UV") return super().wire_symbol(reg, idx) def build_composite_bloq( self, bb: BloqBuilder, mu: SoquetT, nu: SoquetT, m: SoquetT, l: SoquetT, flag_nu: SoquetT - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: mu, nu, m, flag_nu = bb.add( PrepareNuStateWithProj(self.num_bits_p, self.num_bits_n, self.m_param), mu=mu, diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_and_prepare.py b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_and_prepare.py index dde8e7eb6c..7ba76c5991 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_and_prepare.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_and_prepare.py @@ -13,7 +13,7 @@ # limitations under the License. r"""SELECT and PREPARE for the first quantized chemistry Hamiltonian with a quantum projectile.""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np from attrs import evolve, field, frozen @@ -104,7 +104,7 @@ def signature(self) -> Signature: def adjoint(self) -> 'Bloq': return evolve(self, is_adjoint=not self.is_adjoint) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("PREP TUV") return super().wire_symbol(reg, idx) @@ -127,7 +127,7 @@ class ControlledMultiplexedCSwap3D(MultiplexedCSwap3D): num_bits_p: int num_bits_n: int eta: int - cvs: Tuple[int, ...] = field(converter=lambda v: (v,) if isinstance(v, int) else tuple(v)) + cvs: tuple[int, ...] = field(converter=lambda v: (v,) if isinstance(v, int) else tuple(v)) @cached_property def signature(self) -> Signature: @@ -141,7 +141,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('MultiSwap') if reg.name == 'sel': @@ -158,7 +158,7 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) - def build_composite_bloq( self, bb: BloqBuilder, ctrl: SoquetT, sel: SoquetT, targets: SoquetT, junk: SoquetT - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: flat_sys = self._reshape_reg(bb, targets, (self.eta,), bitsize=3 * self.num_bits_p) # we need to extract first n_p bits of each n_n sized ancilla register (i.e. pad with zeros). # This is not a contiguous chunk of qubits so we need to first flatten, @@ -247,7 +247,7 @@ class PrepareFirstQuantizationWithProj(PrepareOracle): num_bits_rot_aa: int = 8 @property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: n_nu = self.num_bits_n + 1 n_eta = (self.eta - 1).bit_length() n_at = (self.num_atoms - 1).bit_length() @@ -277,14 +277,14 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return ( Register("succ_nu", QBit()), Register("plus_t", QBit()), Register('flags', QBit(), shape=(4,)), ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("PREP") return super().wire_symbol(reg, idx) @@ -310,7 +310,7 @@ def build_composite_bloq( succ_nu: SoquetT, l: SoquetT, flags: SoquetT, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: prep_tuv = PrepareTUVSuperpositions( self.num_bits_t, self.eta, self.lambda_zeta, self.num_bits_rot_aa ) @@ -422,7 +422,7 @@ class SelectFirstQuantizationWithProj(SelectOracle): num_bits_rot_aa: int = 8 @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return ( # flags for which component of Hamiltonian to apply. Register("ham_ctrl", QBit(), shape=(4,)), @@ -431,7 +431,7 @@ def control_registers(self) -> Tuple[Register, ...]: ) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: n_nu = self.num_bits_n + 1 n_eta = (self.eta - 1).bit_length() n_at = (self.num_atoms - 1).bit_length() @@ -452,7 +452,7 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return ( Register("sys", QAny(bitsize=self.num_bits_p), shape=(self.eta, 3)), Register('proj', QAny(bitsize=self.num_bits_n), shape=(3,)), @@ -464,7 +464,7 @@ def signature(self) -> Signature: [*self.control_registers, *self.selection_registers, *self.target_registers] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("SELECT") return super().wire_symbol(reg, idx) @@ -489,7 +489,7 @@ def build_composite_bloq( l: SoquetT, sys: SoquetT, proj: NDArray[Soquet], # type: ignore[type-var] - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: # ancilla for swaps from electronic and projectile system registers. # we assume these are left in a clean state after SELECT operations # We only need one of the ancilla registers to be of the size of the projectile's register. diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_t.py b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_t.py index efa2e943f7..20982a7552 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_t.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_t.py @@ -13,7 +13,7 @@ # limitations under the License. r"""Bloqs for SELECT T for the first quantized chemistry Hamiltonian with a quantum projectile.""" from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -71,7 +71,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("SEL T") return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_uv.py b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_uv.py index 6ef6283cfb..6683e66629 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_uv.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_uv.py @@ -14,7 +14,7 @@ r"""Bloqs for SELECT for the U and V parts of the first quantized chemistry Hamiltonian.""" from collections import Counter from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -76,7 +76,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('SEL UV') return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/select_and_prepare.py b/qualtran/bloqs/chemistry/pbc/first_quantization/select_and_prepare.py index 5f5001c60a..d36d80a4ee 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/select_and_prepare.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/select_and_prepare.py @@ -13,7 +13,7 @@ # limitations under the License. r"""SELECT and PREPARE for the first quantized chemistry Hamiltonian.""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np from attrs import frozen @@ -74,7 +74,7 @@ class PrepareTUVSuperpositions(Bloq): def signature(self) -> Signature: return Signature.build(tuv=1, uv=1) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("PREP TUV") return super().wire_symbol(reg, idx) @@ -138,7 +138,7 @@ def signature(self) -> Signature: @staticmethod def _reshape_reg( - bb: BloqBuilder, in_reg: SoquetT, out_shape: Tuple[int, ...], bitsize: int + bb: BloqBuilder, in_reg: SoquetT, out_shape: tuple[int, ...], bitsize: int ) -> NDArray[Soquet]: # type: ignore[type-var] """Reshape registers allocated as a big register. @@ -163,7 +163,7 @@ def _reshape_reg( ) return merged_qubits.reshape(out_shape) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('MultiSwap') if reg.name == 'sel': @@ -176,7 +176,7 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) - def build_composite_bloq( self, bb: BloqBuilder, sel: SoquetT, targets: SoquetT, junk: SoquetT - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: flat_sys = self._reshape_reg(bb, targets, (self.eta,), bitsize=3 * self.num_bits_p) flat_p = self._reshape_reg(bb, junk, (), bitsize=3 * self.num_bits_p) sel, flat_sys, flat_p = bb.add( @@ -244,7 +244,7 @@ class PrepareFirstQuantization(PrepareOracle): sum_of_l1_coeffs: Optional[SymbolicFloat] = None @property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: n_nu = self.num_bits_p + 1 n_eta = (self.eta - 1).bit_length() n_at = (self.num_atoms - 1).bit_length() @@ -272,7 +272,7 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return (Register("succ_nu", QBit()), Register("plus_t", QBit())) @property @@ -283,7 +283,7 @@ def l1_norm_coeffs(self) -> SymbolicFloat: ) return self.sum_of_l1_coeffs - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("PREP") return super().wire_symbol(reg, idx) @@ -306,7 +306,7 @@ def build_composite_bloq( m: SoquetT, succ_nu: SoquetT, l: SoquetT, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: tuv, uv = bb.add( PrepareTUVSuperpositions( self.num_bits_t, self.eta, self.lambda_zeta, self.num_bits_rot_aa @@ -412,7 +412,7 @@ class SelectFirstQuantization(SelectOracle): num_bits_rot_aa: int = 8 @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return ( Register("tuv", QBit()), Register("uv", QBit()), @@ -421,7 +421,7 @@ def control_registers(self) -> Tuple[Register, ...]: ) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: n_nu = self.num_bits_p + 1 n_eta = (self.eta - 1).bit_length() n_at = (self.num_atoms - 1).bit_length() @@ -441,7 +441,7 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register("sys", QAny(bitsize=self.num_bits_p), shape=(self.eta, 3)),) @cached_property @@ -450,7 +450,7 @@ def signature(self) -> Signature: [*self.control_registers, *self.selection_registers, *self.target_registers] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("SELECT") return super().wire_symbol(reg, idx) @@ -474,7 +474,7 @@ def build_composite_bloq( m: SoquetT, l: SoquetT, sys: SoquetT, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: # ancilla for swaps from electronic system registers. # we assume these are left in a clean state after SELECT operations p = [bb.allocate(self.num_bits_p) for _ in range(3)] diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/select_t.py b/qualtran/bloqs/chemistry/pbc/first_quantization/select_t.py index ca7938daa3..3b6de7438d 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/select_t.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/select_t.py @@ -13,7 +13,7 @@ # limitations under the License. r"""Bloqs for SELECT T for the first quantized chemistry Hamiltonian.""" from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -59,7 +59,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("SEL T") return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/chemistry/pbc/first_quantization/select_uv.py b/qualtran/bloqs/chemistry/pbc/first_quantization/select_uv.py index 86bd0fdb40..f08c8ed186 100644 --- a/qualtran/bloqs/chemistry/pbc/first_quantization/select_uv.py +++ b/qualtran/bloqs/chemistry/pbc/first_quantization/select_uv.py @@ -13,7 +13,7 @@ # limitations under the License. r"""Bloqs for SELECT for the U and V parts of the first quantized chemistry Hamiltonian.""" from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -57,7 +57,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text(r'-e^(-k_ν⋅R_l)') return super().wire_symbol(reg, idx) @@ -114,7 +114,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("SEL UV") return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/chemistry/quad_fermion/givens_bloq.py b/qualtran/bloqs/chemistry/quad_fermion/givens_bloq.py index 8546f518da..563fc420f5 100644 --- a/qualtran/bloqs/chemistry/quad_fermion/givens_bloq.py +++ b/qualtran/bloqs/chemistry/quad_fermion/givens_bloq.py @@ -46,7 +46,6 @@ """ from functools import cached_property -from typing import Dict from attrs import frozen @@ -120,7 +119,7 @@ def build_composite_bloq( target_j: SoquetT, rom_data: SoquetT, phase_gradient: SoquetT, - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: # clifford block target_i = bb.add(XGate(), q=target_i) target_j = bb.add(SGate(), q=target_j) @@ -214,7 +213,7 @@ def build_composite_bloq( real_rom_data: SoquetT, cplx_rom_data: SoquetT, phase_gradient: SoquetT, - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: real_givens_gate = RealGivensRotationByPhaseGradient( phasegrad_bitsize=self.phasegrad_bitsize ) diff --git a/qualtran/bloqs/chemistry/sf/prepare.py b/qualtran/bloqs/chemistry/sf/prepare.py index 1ad5861baa..6671f2bff1 100644 --- a/qualtran/bloqs/chemistry/sf/prepare.py +++ b/qualtran/bloqs/chemistry/sf/prepare.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -70,7 +70,7 @@ class InnerPrepareSingleFactorization(Bloq): kp1: int = 1 kp2: int = 1 - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("In-Prep") return super().wire_symbol(reg, idx) @@ -136,7 +136,7 @@ class OuterPrepareSingleFactorization(Bloq): num_bits_state_prep: int num_bits_rot_aa: int = 8 - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("OuterPrep") return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/chemistry/sf/single_factorization.py b/qualtran/bloqs/chemistry/sf/single_factorization.py index 5e1104df8a..cf39c70f36 100644 --- a/qualtran/bloqs/chemistry/sf/single_factorization.py +++ b/qualtran/bloqs/chemistry/sf/single_factorization.py @@ -22,8 +22,9 @@ electron repulsion integrals. """ +from collections.abc import Iterable from functools import cached_property -from typing import Dict, Iterable, TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np from attrs import evolve, frozen @@ -203,7 +204,7 @@ def build_composite_bloq( swap_pq: SoquetT, spin: SoquetT, sys: SoquetT, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: iprep = InnerPrepareSingleFactorization( self.num_aux, self.num_spin_orb, @@ -394,7 +395,7 @@ def build_composite_bloq( swap_pq: SoquetT, spin: SoquetT, sys: SoquetT, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: succ_l, l_ne_zero, succ_pq = ctrl p, q = pq # prepare_l diff --git a/qualtran/bloqs/chemistry/sparse/prepare.py b/qualtran/bloqs/chemistry/sparse/prepare.py index 02e4b38109..5a90926f0d 100644 --- a/qualtran/bloqs/chemistry/sparse/prepare.py +++ b/qualtran/bloqs/chemistry/sparse/prepare.py @@ -15,7 +15,7 @@ import itertools from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import attrs import numpy as np @@ -173,19 +173,19 @@ class PrepareSparse(PrepareOracle): num_spin_orb: int num_non_zero: int num_bits_state_prep: int - alt_pqrs: Tuple[Tuple[int, ...], ...] = attrs.field(repr=False) - alt_theta: Tuple[int, ...] = attrs.field(repr=False) - alt_one_body: Tuple[int, ...] = attrs.field(repr=False) - ind_pqrs: Tuple[Tuple[int, ...], ...] = attrs.field(repr=False) - theta: Tuple[int, ...] = attrs.field(repr=False) - one_body: Tuple[int, ...] = attrs.field(repr=False) - keep: Tuple[int, ...] = attrs.field(repr=False) + alt_pqrs: tuple[tuple[int, ...], ...] = attrs.field(repr=False) + alt_theta: tuple[int, ...] = attrs.field(repr=False) + alt_one_body: tuple[int, ...] = attrs.field(repr=False) + ind_pqrs: tuple[tuple[int, ...], ...] = attrs.field(repr=False) + theta: tuple[int, ...] = attrs.field(repr=False) + one_body: tuple[int, ...] = attrs.field(repr=False) + keep: tuple[int, ...] = attrs.field(repr=False) num_bits_rot_aa: int = 8 sum_of_l1_coeffs: SymbolicFloat = 0.0 log_block_size: SymbolicInt = 1 @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return ( Register( "d", @@ -203,12 +203,12 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: extra_junk = (Register("less_than", QBit()),) return extra_junk + self.qroam_target_registers + self.qroam_extra_target_registers @cached_property - def qroam_target_registers(self) -> Tuple[Register, ...]: + def qroam_target_registers(self) -> tuple[Register, ...]: """Target registers for QROAMClean.""" bs = (self.num_spin_orb // 2 - 1).bit_length() return ( @@ -228,7 +228,7 @@ def qroam_target_registers(self) -> Tuple[Register, ...]: ) @cached_property - def qroam_extra_target_registers(self) -> Tuple[Register, ...]: + def qroam_extra_target_registers(self) -> tuple[Register, ...]: """Extra registers required for QROAMClean.""" if self.log_block_size == 0: return () @@ -345,12 +345,12 @@ def build_qrom_bloq(self) -> 'Bloq': ) return qrom - def add_qrom(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def add_qrom(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: qrom = self.build_qrom_bloq() # The qroam_junk_regs won't be present initially when building the # composite bloq as they're RIGHT registers. qroam_out_soqs = bb.add_d(qrom, selection=soqs['d']) - out_soqs: Dict[str, 'SoquetT'] = {'d': qroam_out_soqs.pop('selection')} + out_soqs: dict[str, 'SoquetT'] = {'d': qroam_out_soqs.pop('selection')} # map output soqs to Prepare junk registers names out_soqs |= { reg.name: qroam_out_soqs.pop(f'target{i}_') @@ -362,7 +362,7 @@ def add_qrom(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT'] } return soqs | out_soqs - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: n_n = self.num_bits_spat_orb # 1. Prepare \sum_d |d\rangle soqs['d'] = bb.add(PrepareUniformSuperposition(self.num_non_zero), target=soqs['d']) diff --git a/qualtran/bloqs/chemistry/sparse/select_bloq.py b/qualtran/bloqs/chemistry/sparse/select_bloq.py index 1c7fd5595a..43f8b0ddc7 100644 --- a/qualtran/bloqs/chemistry/sparse/select_bloq.py +++ b/qualtran/bloqs/chemistry/sparse/select_bloq.py @@ -14,7 +14,7 @@ """SELECT for the sparse chemistry Hamiltonian in second quantization.""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import attrs import cirq @@ -71,11 +71,11 @@ class SelectSparse(SelectOracle): control_val: Optional[int] = None @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('control', QBit()),) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return ( Register( "p", @@ -111,10 +111,10 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register("sys", QAny(bitsize=self.num_spin_orb)),) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: p, q, r, s = soqs['p'], soqs['q'], soqs['r'], soqs['s'] alpha, beta = soqs['alpha'], soqs['beta'] flag_1b = soqs['flag_1b'] @@ -169,7 +169,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': c_maj_y = SelectedMajoranaFermion(sel_pa, target_gate=cirq.Y) return {SGate(): 1, maj_x: 1, c_maj_x: 1, maj_y: 1, c_maj_y: 1} - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv return get_ctrl_system_1bit_cv( diff --git a/qualtran/bloqs/chemistry/thc/prepare.py b/qualtran/bloqs/chemistry/thc/prepare.py index f93891e727..d367ebc424 100644 --- a/qualtran/bloqs/chemistry/thc/prepare.py +++ b/qualtran/bloqs/chemistry/thc/prepare.py @@ -13,7 +13,7 @@ # limitations under the License. """PREPARE for the molecular tensor hypercontraction (THC) hamiltonian""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np from attrs import field, frozen @@ -110,7 +110,7 @@ def signature(self) -> Signature: def __str__(self) -> str: return r'$\sum_{\mu < \nu} |\mu\nu\rangle$' - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('Σ |μν>') return super().wire_symbol(reg, idx) @@ -123,7 +123,7 @@ def build_composite_bloq( succ: SoquetT, nu_eq_mp1: SoquetT, rot: SoquetT, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: # If we introduce comparators using out of place adders these will be left/right registers. # See: https://github.com/quantumlib/Qualtran/issues/390 lte_mu_nu, lte_nu_mp1, gt_mu_n, junk = bb.split(bb.allocate(4)) @@ -260,11 +260,11 @@ class PrepareTHC(PrepareOracle): num_mu: int num_spin_orb: int - alt_mu: Tuple[int, ...] = field(repr=False) - alt_nu: Tuple[int, ...] = field(repr=False) - alt_theta: Tuple[int, ...] = field(repr=False) - theta: Tuple[int, ...] = field(repr=False) - keep: Tuple[int, ...] = field(repr=False) + alt_mu: tuple[int, ...] = field(repr=False) + alt_nu: tuple[int, ...] = field(repr=False) + alt_theta: tuple[int, ...] = field(repr=False) + theta: tuple[int, ...] = field(repr=False) + keep: tuple[int, ...] = field(repr=False) keep_bitsize: int sum_of_l1_coeffs: SymbolicFloat log_block_size: SymbolicInt = 0 @@ -348,7 +348,7 @@ def l1_norm_of_coeffs(self) -> SymbolicFloat: return self.sum_of_l1_coeffs @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return ( Register( "mu", BQUInt(bitsize=(self.num_mu).bit_length(), iteration_length=self.num_mu + 1) @@ -366,7 +366,7 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: data_size = self.num_spin_orb // 2 + self.num_mu * (self.num_mu + 1) // 2 junk = ( Register('s', QAny(bitsize=(data_size - 1).bit_length())), @@ -376,7 +376,7 @@ def junk_registers(self) -> Tuple[Register, ...]: return junk + self.qroam_target_registers + self.qroam_extra_target_registers @cached_property - def qroam_target_registers(self) -> Tuple[Register, ...]: + def qroam_target_registers(self) -> tuple[Register, ...]: """Target registers for QROAMClean.""" return ( Register('theta', QBit(), side=Side.RIGHT), @@ -387,7 +387,7 @@ def qroam_target_registers(self) -> Tuple[Register, ...]: ) @cached_property - def qroam_extra_target_registers(self) -> Tuple[Register, ...]: + def qroam_extra_target_registers(self) -> tuple[Register, ...]: """Extra registers required for QROAMClean.""" return tuple( Register( @@ -412,12 +412,12 @@ def build_qrom_bloq(self) -> 'Bloq': ) return qroam - def add_qrom(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def add_qrom(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: qrom = self.build_qrom_bloq() # The qroam_junk_regs won't be present initially when building the # composite bloq as they're RIGHT registers. qroam_out_soqs = bb.add_d(qrom, selection=soqs['s']) - out_soqs: Dict[str, 'SoquetT'] = {'s': qroam_out_soqs.pop('selection')} + out_soqs: dict[str, 'SoquetT'] = {'s': qroam_out_soqs.pop('selection')} # map output soqs to Prepare junk registers names out_soqs |= { reg.name: qroam_out_soqs.pop(f'target{i}_') @@ -429,7 +429,7 @@ def add_qrom(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT'] } return soqs | out_soqs - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: # 1. Prepare THC uniform superposition over mu, nu. succ flags success. soqs['mu'], soqs['nu'], soqs['succ'], soqs['nu_eq_mp1'], soqs['rot'] = bb.add( UniformSuperpositionTHC(num_mu=self.num_mu, num_spin_orb=self.num_spin_orb), diff --git a/qualtran/bloqs/chemistry/thc/select_bloq.py b/qualtran/bloqs/chemistry/thc/select_bloq.py index a3b825950f..9bf8679778 100644 --- a/qualtran/bloqs/chemistry/thc/select_bloq.py +++ b/qualtran/bloqs/chemistry/thc/select_bloq.py @@ -14,7 +14,7 @@ """SELECT for the molecular tensor hypercontraction (THC) hamiltonian""" from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np from attrs import evolve, frozen @@ -163,11 +163,11 @@ class SelectTHC(SelectOracle): control_val: Optional[int] = None @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('control', QBit()),) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return ( Register("succ", BQUInt(bitsize=1)), Register("nu_eq_mp1", BQUInt(bitsize=1)), @@ -185,13 +185,13 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return ( Register("sys_a", QAny(bitsize=self.num_spin_orb // 2)), Register("sys_b", QAny(bitsize=self.num_spin_orb // 2)), ) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: succ = soqs['succ'] nu_eq_mp1 = soqs['nu_eq_mp1'] mu = soqs['mu'] @@ -314,7 +314,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str return out_soqs - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv return get_ctrl_system_1bit_cv( diff --git a/qualtran/bloqs/chemistry/trotter/grid_ham/inverse_sqrt.py b/qualtran/bloqs/chemistry/trotter/grid_ham/inverse_sqrt.py index d9beebf871..c888946367 100644 --- a/qualtran/bloqs/chemistry/trotter/grid_ham/inverse_sqrt.py +++ b/qualtran/bloqs/chemistry/trotter/grid_ham/inverse_sqrt.py @@ -13,7 +13,7 @@ # limitations under the License. """Bloqs for computing the inverse Square root of a fixed point number.""" from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np from attrs import frozen @@ -27,7 +27,7 @@ from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator -def get_inverse_square_root_poly_coeffs() -> Tuple[NDArray, NDArray]: +def get_inverse_square_root_poly_coeffs() -> tuple[NDArray, NDArray]: """Polynomial coefficients for approximating inverse square root. This function returns the coefficients of a piecewise cubic polynomial @@ -59,7 +59,7 @@ def get_inverse_square_root_poly_coeffs() -> Tuple[NDArray, NDArray]: def build_qrom_data_for_poly_fit( - selection_bitsize: int, target_bitsize: int, poly_coeffs: Tuple[NDArray, NDArray] + selection_bitsize: int, target_bitsize: int, poly_coeffs: tuple[NDArray, NDArray] ) -> NDArray: """Build QROM data from polynomial coefficients from the referenence. @@ -165,7 +165,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("y=x^{-1/2}") return super().wire_symbol(reg, idx) @@ -217,7 +217,7 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("y~x^{-1/2}") return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/chemistry/trotter/grid_ham/kinetic.py b/qualtran/bloqs/chemistry/trotter/grid_ham/kinetic.py index 50dd860c59..5c7a7a4088 100644 --- a/qualtran/bloqs/chemistry/trotter/grid_ham/kinetic.py +++ b/qualtran/bloqs/chemistry/trotter/grid_ham/kinetic.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple +from typing import Optional from attrs import frozen from numpy.typing import NDArray @@ -66,12 +66,12 @@ def signature(self) -> Signature: ] ) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("U_T(dt)") return super().wire_symbol(reg, idx) - def build_composite_bloq(self, bb: BloqBuilder, *, system: NDArray[Soquet]) -> Dict[str, SoquetT]: # type: ignore[type-var] + def build_composite_bloq(self, bb: BloqBuilder, *, system: NDArray[Soquet]) -> dict[str, SoquetT]: # type: ignore[type-var] bitsize = (self.num_grid - 1).bit_length() + 1 for i in range(self.num_elec): system[i], sos = bb.add(SumOfSquares(bitsize=bitsize, k=3), input=system[i]) diff --git a/qualtran/bloqs/chemistry/trotter/grid_ham/potential.py b/qualtran/bloqs/chemistry/trotter/grid_ham/potential.py index 6fd2fae98f..4749d93270 100644 --- a/qualtran/bloqs/chemistry/trotter/grid_ham/potential.py +++ b/qualtran/bloqs/chemistry/trotter/grid_ham/potential.py @@ -14,7 +14,7 @@ """Bloqs for the Potential energy of a 3D grid based Hamiltonian.""" from functools import cached_property -from typing import Dict, Optional, Tuple +from typing import Optional import numpy as np from attrs import field, frozen @@ -67,7 +67,7 @@ class PairPotential(Bloq): """ bitsize: int - qrom_data: Tuple[Tuple[int], ...] = field( + qrom_data: tuple[tuple[int], ...] = field( repr=False, converter=lambda d: tuple(tuple(x) for x in d) ) poly_bitsize: int = 15 @@ -84,7 +84,7 @@ def signature(self) -> Signature: ) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(f'U_{self.label}(dt)_ij') @@ -92,7 +92,7 @@ def wire_symbol( def build_composite_bloq( self, bb: BloqBuilder, *, system_i: SoquetT, system_j: SoquetT - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: if isinstance(system_i, Soquet) or isinstance(system_j, Soquet): raise ValueError("system_i and system_j must be numpy arrays of Soquet") # compute r_i - r_j @@ -220,13 +220,13 @@ def signature(self) -> Signature: ) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(f'U_{self.label}(dt)') return super().wire_symbol(reg, idx) - def build_composite_bloq(self, bb: BloqBuilder, *, system: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, *, system: SoquetT) -> dict[str, SoquetT]: if isinstance(system, Soquet): raise ValueError("system must be a numpy array of Soquet") bitsize = (self.num_grid - 1).bit_length() + 1 diff --git a/qualtran/bloqs/chemistry/trotter/grid_ham/qvr.py b/qualtran/bloqs/chemistry/trotter/grid_ham/qvr.py index 0809fd98bc..9c0eb4349c 100644 --- a/qualtran/bloqs/chemistry/trotter/grid_ham/qvr.py +++ b/qualtran/bloqs/chemistry/trotter/grid_ham/qvr.py @@ -14,7 +14,7 @@ """Quantum Variable Rotation.""" from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -54,7 +54,7 @@ class QuantumVariableRotation(Bloq): def signature(self) -> Signature: return Signature([Register('phi', QAny(bitsize=self.phi_bitsize))]) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("e^{i*phi}") return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/chemistry/trotter/hubbard/hopping.py b/qualtran/bloqs/chemistry/trotter/hubbard/hopping.py index 7e9a93856c..78cd57c880 100644 --- a/qualtran/bloqs/chemistry/trotter/hubbard/hopping.py +++ b/qualtran/bloqs/chemistry/trotter/hubbard/hopping.py @@ -13,7 +13,7 @@ # limitations under the License. """Bloqs implementing unitary evolution under the one-body hopping Hamiltonian in 2D.""" from functools import cached_property -from typing import Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING from attrs import frozen @@ -121,7 +121,7 @@ def __attrs_post_init__(self): if isinstance(self.length, int) and self.length % 2 != 0: raise ValueError('Only even length lattices are supported') - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: l = 'p' if self.pink else 'g' return Text(f'H_h^{l}') diff --git a/qualtran/bloqs/chemistry/trotter/hubbard/trotter_step.py b/qualtran/bloqs/chemistry/trotter/hubbard/trotter_step.py index 807d1bbe6f..78fa885cb8 100644 --- a/qualtran/bloqs/chemistry/trotter/hubbard/trotter_step.py +++ b/qualtran/bloqs/chemistry/trotter/hubbard/trotter_step.py @@ -21,7 +21,7 @@ $$ """ -from typing import Sequence +from collections.abc import Sequence from qualtran.bloqs.chemistry.trotter.hubbard.hopping import HoppingTile, HoppingTileHWP from qualtran.bloqs.chemistry.trotter.hubbard.interaction import Interaction, InteractionHWP diff --git a/qualtran/bloqs/chemistry/trotter/ising/unitaries.py b/qualtran/bloqs/chemistry/trotter/ising/unitaries.py index c9f9b14ce5..0a401d0d44 100644 --- a/qualtran/bloqs/chemistry/trotter/ising/unitaries.py +++ b/qualtran/bloqs/chemistry/trotter/ising/unitaries.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple +from typing import Optional import attrs @@ -42,12 +42,12 @@ class IsingXUnitary(Bloq): def signature(self) -> Signature: return Signature.build(system=self.nsites) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("U_X") return super().wire_symbol(reg, idx) - def build_composite_bloq(self, bb: 'BloqBuilder', system: 'Soquet') -> Dict[str, 'Soquet']: + def build_composite_bloq(self, bb: 'BloqBuilder', system: 'Soquet') -> dict[str, 'Soquet']: system = bb.split(system) for iq in range(self.nsites): system[iq] = bb.add(Rx(self.angle), q=system[iq]) @@ -75,12 +75,12 @@ class IsingZZUnitary(Bloq): def signature(self) -> Signature: return Signature.build(system=self.nsites) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text("U_ZZ") return super().wire_symbol(reg, idx) - def build_composite_bloq(self, bb: 'BloqBuilder', system: 'Soquet') -> Dict[str, 'Soquet']: + def build_composite_bloq(self, bb: 'BloqBuilder', system: 'Soquet') -> dict[str, 'Soquet']: system = bb.split(system) for iq_a in range(self.nsites): iq_b = (iq_a + 1) % self.nsites diff --git a/qualtran/bloqs/chemistry/trotter/trotterized_unitary.py b/qualtran/bloqs/chemistry/trotter/trotterized_unitary.py index f362ad22ed..39f561875b 100644 --- a/qualtran/bloqs/chemistry/trotter/trotterized_unitary.py +++ b/qualtran/bloqs/chemistry/trotter/trotterized_unitary.py @@ -13,8 +13,8 @@ # limitations under the License. """Bloq for building a Trotterized unitary""" +from collections.abc import Sequence from functools import cached_property -from typing import Dict, Sequence import attrs @@ -102,7 +102,7 @@ def __attrs_post_init__(self): def signature(self) -> Signature: return self.bloqs[0].signature - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: SoquetT) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: SoquetT) -> dict[str, 'SoquetT']: for i, a in zip(self.indices, self.coeffs): # Bloqs passed in are supposed to be attrs dataclasses per docs # It would be nice to somehow specify that self.bloqs are both bloqs and AttrsInstance diff --git a/qualtran/bloqs/cryptography/_factoring_shims.py b/qualtran/bloqs/cryptography/_factoring_shims.py index 1bc32a5c6d..6ed5d47834 100644 --- a/qualtran/bloqs/cryptography/_factoring_shims.py +++ b/qualtran/bloqs/cryptography/_factoring_shims.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple +from typing import Optional import numpy as np import sympy @@ -46,7 +46,7 @@ class MeasureQFT(Bloq): def signature(self) -> 'Signature': return Signature([Register('x', QBit(), shape=(self.n,), side=Side.LEFT)]) - def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> dict[str, 'SoquetT']: if isinstance(self.n, sympy.Expr): raise DecomposeTypeError("Cannot decompose symbolic `n`.") @@ -63,7 +63,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {QFTTextBook(self.n): 1, Measure(): self.n} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('MeasureQFT') diff --git a/qualtran/bloqs/cryptography/ecc/ec_add.py b/qualtran/bloqs/cryptography/ecc/ec_add.py index 0401890bdf..8c48f89898 100644 --- a/qualtran/bloqs/cryptography/ecc/ec_add.py +++ b/qualtran/bloqs/cryptography/ecc/ec_add.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Union +from typing import Union import numpy as np import sympy @@ -102,7 +102,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, a: 'ClassicalValT', b: 'ClassicalValT', x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: f1 = int(a == x) f2 = int(b == (-y % self.mod)) f3 = int(a == b == 0) @@ -122,7 +122,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', a: Soquet, b: Soquet, x: Soquet, y: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.n): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `n`.") @@ -249,7 +249,7 @@ def on_classical_vals( x: 'ClassicalValT', y: 'ClassicalValT', lam_r: 'ClassicalValT', - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: x = (x - a) % self.mod if ctrl == 1: y = (y - b) % self.mod @@ -274,7 +274,7 @@ def build_composite_bloq( x: Soquet, y: Soquet, lam_r: Soquet, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.n): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `n`.") @@ -429,7 +429,7 @@ def on_classical_vals( x: 'ClassicalValT', y: 'ClassicalValT', lam: 'ClassicalValT', - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == 1: x = (x + 3 * a) % self.mod y = 0 @@ -444,7 +444,7 @@ def build_composite_bloq( x: Soquet, y: Soquet, lam: Soquet, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.n): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `n`.") @@ -557,7 +557,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, x: 'ClassicalValT', y: 'ClassicalValT', lam: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: x = ( x - QMontgomeryUInt(self.n, self.mod).montgomery_product(int(lam), int(lam)) ) % self.mod @@ -567,7 +567,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', x: Soquet, y: Soquet, lam: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.n): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `n`.") @@ -715,7 +715,7 @@ def on_classical_vals( y: 'ClassicalValT', lam_r: 'ClassicalValT', lam: 'ClassicalValT', - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == 1: x = (a - x) % self.mod y = (y - b) % self.mod @@ -733,7 +733,7 @@ def build_composite_bloq( y: Soquet, lam_r: Soquet, lam: Soquet, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.n): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `n`.") @@ -885,7 +885,7 @@ def on_classical_vals( b: 'ClassicalValT', x: 'ClassicalValT', y: 'ClassicalValT', - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if f4 == 1: x = a y = b @@ -906,7 +906,7 @@ def build_composite_bloq( b: Soquet, x: Soquet, y: Soquet, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.n): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `n`.") @@ -1076,7 +1076,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', a: Soquet, b: Soquet, x: Soquet, y: Soquet, lam_r: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: f1, f2, f3, f4, ctrl, a, b, x, y = bb.add( _ECAddStepOne(n=self.n, mod=self.mod), a=a, b=b, x=x, y=y ) @@ -1127,7 +1127,7 @@ def build_composite_bloq( return {'a': a, 'b': b, 'x': x, 'y': y, 'lam_r': lam_r} - def on_classical_vals(self, a, b, x, y, lam_r) -> Dict[str, Union['ClassicalValT', sympy.Expr]]: + def on_classical_vals(self, a, b, x, y, lam_r) -> dict[str, Union['ClassicalValT', sympy.Expr]]: dtype = QMontgomeryUInt(self.n, self.mod) curve_a = ( dtype.montgomery_to_uint(lam_r) * 2 * dtype.montgomery_to_uint(b) diff --git a/qualtran/bloqs/cryptography/ecc/ec_add_r.py b/qualtran/bloqs/cryptography/ecc/ec_add_r.py index 195654d5b4..076f87f2b0 100644 --- a/qualtran/bloqs/cryptography/ecc/ec_add_r.py +++ b/qualtran/bloqs/cryptography/ecc/ec_add_r.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple, Union +from typing import Optional, Union import numpy as np import sympy @@ -83,7 +83,7 @@ def signature(self) -> 'Signature': [Register('ctrl', QBit()), Register('x', QUInt(self.n)), Register('y', QUInt(self.n))] ) - def on_classical_vals(self, ctrl, x, y) -> Dict[str, Union['ClassicalValT', sympy.Expr]]: + def on_classical_vals(self, ctrl, x, y) -> dict[str, Union['ClassicalValT', sympy.Expr]]: if ctrl == 0: return {'ctrl': ctrl, 'x': x, 'y': y} @@ -91,7 +91,7 @@ def on_classical_vals(self, ctrl, x, y) -> Dict[str, Union['ClassicalValT', symp result: ECPoint = A + self.R return {'ctrl': 1, 'x': result.x, 'y': result.y} - def wire_symbol(self, reg: 'Register', idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: 'Register', idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'ctrl': @@ -199,7 +199,7 @@ def qrom(self) -> QROAMClean: def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: 'SoquetT', x: 'Soquet', y: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: ctrl = bb.join(np.array(ctrl)) ctrl, a, b, lam_r, *junk = bb.add(self.qrom, selection=ctrl) @@ -241,7 +241,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': self.qrom.adjoint(): 1, } - def on_classical_vals(self, ctrl, x, y) -> Dict[str, Union['ClassicalValT', sympy.Expr]]: + def on_classical_vals(self, ctrl, x, y) -> dict[str, Union['ClassicalValT', sympy.Expr]]: # TODO(https://github.com/quantumlib/Qualtran/issues/1476): make ECAdd accept SymbolicInt. dtype = QMontgomeryUInt(self.n, self.R.mod) A = ECPoint( @@ -259,7 +259,7 @@ def on_classical_vals(self, ctrl, x, y) -> Dict[str, Union['ClassicalValT', symp } def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(f'ECWindowAddR({self.n=})') diff --git a/qualtran/bloqs/cryptography/ecc/ec_phase_estimate_r.py b/qualtran/bloqs/cryptography/ecc/ec_phase_estimate_r.py index eb991c19ab..e2e79261a4 100644 --- a/qualtran/bloqs/cryptography/ecc/ec_phase_estimate_r.py +++ b/qualtran/bloqs/cryptography/ecc/ec_phase_estimate_r.py @@ -14,7 +14,7 @@ import functools from functools import cached_property -from typing import Dict, Union +from typing import Union import numpy as np import sympy @@ -83,7 +83,7 @@ def ec_add(self) -> Union[functools.partial[ECAddR], functools.partial[ECWindowA def num_windows(self) -> int: return self.n // self.add_window_size - def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet, y: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet, y: Soquet) -> dict[str, 'SoquetT']: if isinstance(self.n, sympy.Expr): raise DecomposeTypeError("Cannot decompose symbolic `n`.") ctrl = [bb.add(PlusState()) for _ in range(self.n)] diff --git a/qualtran/bloqs/cryptography/ecc/find_ecc_private_key.py b/qualtran/bloqs/cryptography/ecc/find_ecc_private_key.py index f6129af801..d0df45817b 100644 --- a/qualtran/bloqs/cryptography/ecc/find_ecc_private_key.py +++ b/qualtran/bloqs/cryptography/ecc/find_ecc_private_key.py @@ -14,7 +14,6 @@ import functools from functools import cached_property -from typing import Dict import sympy from attrs import frozen @@ -106,7 +105,7 @@ def ec_pe_r(self) -> functools.partial[ECPhaseEstimateR]: mul_window_size=self.mul_window_size, ) - def build_composite_bloq(self, bb: 'BloqBuilder') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder') -> dict[str, 'SoquetT']: x = bb.add(IntState(bitsize=self.n, val=self.base_point.x)) y = bb.add(IntState(bitsize=self.n, val=self.base_point.y)) diff --git a/qualtran/bloqs/cryptography/rsa/rsa_mod_exp.py b/qualtran/bloqs/cryptography/rsa/rsa_mod_exp.py index 280bc11da4..0176271de6 100644 --- a/qualtran/bloqs/cryptography/rsa/rsa_mod_exp.py +++ b/qualtran/bloqs/cryptography/rsa/rsa_mod_exp.py @@ -13,7 +13,7 @@ # limitations under the License. import math from functools import cached_property -from typing import cast, Dict, Optional, Tuple, Union +from typing import cast, Optional, Union import attrs import numpy as np @@ -121,7 +121,7 @@ def _CtrlModMul(self, k: 'SymbolicInt'): """Helper method to return a `CModMulK` with attributes forwarded.""" return CModMulK(QUInt(self.x_bitsize), k=k, mod=self.mod) - def build_composite_bloq(self, bb: 'BloqBuilder', exponent: 'Soquet') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', exponent: 'Soquet') -> dict[str, 'SoquetT']: if is_symbolic(self.exp_bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `exp_bitsize`.") # https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method @@ -139,11 +139,11 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': k = ssa.new_symbol('k') return {self._CtrlModMul(k=k): self.exp_bitsize, IntState(val=1, bitsize=self.x_bitsize): 1} - def on_classical_vals(self, exponent) -> Dict[str, Union['ClassicalValT', sympy.Expr]]: + def on_classical_vals(self, exponent) -> dict[str, Union['ClassicalValT', sympy.Expr]]: return {'exponent': exponent, 'x': (self.base**exponent) % self.mod} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(f'{self.base}^e % {self.mod}') diff --git a/qualtran/bloqs/cryptography/rsa/rsa_phase_estimate.py b/qualtran/bloqs/cryptography/rsa/rsa_phase_estimate.py index 9416620d05..4737768cde 100644 --- a/qualtran/bloqs/cryptography/rsa/rsa_phase_estimate.py +++ b/qualtran/bloqs/cryptography/rsa/rsa_phase_estimate.py @@ -14,7 +14,7 @@ import math from functools import cached_property -from typing import Dict, Optional +from typing import Optional import attrs import numpy as np @@ -104,7 +104,7 @@ def _CtrlModMul(self, k: 'SymbolicInt'): """Helper method to return a `CModMulK` with attributes forwarded.""" return CModMulK(QUInt(self.n), k=k, mod=self.mod) - def build_composite_bloq(self, bb: 'BloqBuilder') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder') -> dict[str, 'SoquetT']: if is_symbolic(self.n): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `n`.") exponent = [bb.add(PlusState()) for _ in range(2 * self.n)] diff --git a/qualtran/bloqs/data_loading/qroam_clean.py b/qualtran/bloqs/data_loading/qroam_clean.py index ab53dc58b9..9c80b0fec9 100644 --- a/qualtran/bloqs/data_loading/qroam_clean.py +++ b/qualtran/bloqs/data_loading/qroam_clean.py @@ -14,7 +14,7 @@ import numbers from collections import defaultdict from functools import cached_property -from typing import cast, Dict, List, Optional, Tuple, Type, TYPE_CHECKING, Union +from typing import cast, Optional, Type, TYPE_CHECKING, Union import attrs import numpy as np @@ -45,7 +45,7 @@ def _alloc_anc_for_reg_except_first( - bb: 'BloqBuilder', dtype: 'QDType', shape: Tuple[int, ...], dirty: bool + bb: 'BloqBuilder', dtype: 'QDType', shape: tuple[int, ...], dirty: bool ) -> 'SoquetT': if not shape: return bb.allocate(dtype=dtype, dirty=dirty) @@ -119,7 +119,7 @@ class QROAMCleanAdjoint(QROMBase, GateWithRegisters): # type: ignore[misc] Berry et al. (2019). Appendix C. """ - log_block_sizes: Tuple[SymbolicInt, ...] = attrs.field( + log_block_sizes: tuple[SymbolicInt, ...] = attrs.field( converter=lambda x: tuple(x.tolist() if isinstance(x, np.ndarray) else x) ) @@ -131,10 +131,10 @@ def _target_reg_side(self) -> Side: def build_from_data( cls: Type['QROAMCleanAdjoint'], *data: ArrayLike, - target_bitsizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, - target_shapes: Tuple[Tuple[SymbolicInt, ...], ...] = (), + target_bitsizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, + target_shapes: tuple[tuple[SymbolicInt, ...], ...] = (), num_controls: SymbolicInt = 0, - log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, ) -> 'QROAMCleanAdjoint': qroam: 'QROAMCleanAdjoint' = cls._build_from_data( *data, @@ -147,13 +147,13 @@ def build_from_data( @classmethod def build_from_bitsize( cls: Type['QROAMCleanAdjoint'], - data_len_or_shape: Union[SymbolicInt, Tuple[SymbolicInt, ...]], - target_bitsizes: Union[SymbolicInt, Tuple[SymbolicInt, ...]], + data_len_or_shape: Union[SymbolicInt, tuple[SymbolicInt, ...]], + target_bitsizes: Union[SymbolicInt, tuple[SymbolicInt, ...]], *, - target_shapes: Tuple[Tuple[SymbolicInt, ...], ...] = (), - selection_bitsizes: Tuple[SymbolicInt, ...] = (), + target_shapes: tuple[tuple[SymbolicInt, ...], ...] = (), + selection_bitsizes: tuple[SymbolicInt, ...] = (), num_controls: SymbolicInt = 0, - log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, ) -> 'QROAMCleanAdjoint': qroam: 'QROAMCleanAdjoint' = cls._build_from_bitsize( data_len_or_shape, @@ -165,7 +165,7 @@ def build_from_bitsize( return qroam.with_log_block_sizes(log_block_sizes=log_block_sizes) @log_block_sizes.default - def _default_log_block_sizes(self) -> Tuple[SymbolicInt, ...]: + def _default_log_block_sizes(self) -> tuple[SymbolicInt, ...]: target_bitsize = sum( bs * prod(shape) for (bs, shape) in zip(self.target_bitsizes, self.target_shapes) ) @@ -175,7 +175,7 @@ def _default_log_block_sizes(self) -> Tuple[SymbolicInt, ...]: ) def with_log_block_sizes( - self, log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None + self, log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None ) -> 'QROAMCleanAdjoint': if log_block_sizes is None: return self @@ -202,7 +202,7 @@ def signature(self) -> Signature: def adjoint(self) -> 'QROAMClean': return QROAMClean(**attrs.asdict(self)) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('QROAM').adjoint() name = reg.name @@ -223,7 +223,7 @@ class QROAMCleanAdjointWrapper(Bloq): """Wrapper bloq with signature matching Adjoint(QROAMClean). Delegates to QROAMCleanAdjoint""" qroam_clean: 'QROAMClean' - log_block_sizes: Tuple[SymbolicInt, ...] = attrs.field( + log_block_sizes: tuple[SymbolicInt, ...] = attrs.field( converter=lambda x: ( x if x is None else tuple(x.tolist() if isinstance(x, np.ndarray) else x) ) @@ -234,7 +234,7 @@ def signature(self) -> 'Signature': return self.qroam_clean.signature.adjoint() @log_block_sizes.default - def _log_block_sizes(self) -> Tuple[SymbolicInt, ...]: + def _log_block_sizes(self) -> tuple[SymbolicInt, ...]: # Note: Target bitsize does not matter for adjoint, so setting to 0. return tuple( get_optimal_log_block_size_clean_ancilla(ilen, 0, adjoint=True) @@ -262,8 +262,8 @@ def qroam_clean_adjoint_bloq(self) -> 'QROAMCleanAdjoint': num_controls=self.qroam_clean.num_controls, ) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: - block_sizes = cast(Tuple[int, ...], self.qroam_clean.block_sizes) + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: + block_sizes = cast(tuple[int, ...], self.qroam_clean.block_sizes) for target, adj_target in zip( self.qroam_clean.target_registers, self.qroam_clean_adjoint_bloq.target_registers ): @@ -288,11 +288,11 @@ def adjoint(self) -> 'QROAMClean': return self.qroam_clean def with_log_block_sizes( - self, log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None + self, log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None ) -> 'QROAMCleanAdjointWrapper': return attrs.evolve(self, log_block_sizes=log_block_sizes) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('QROAM').adjoint() name = reg.name @@ -357,7 +357,7 @@ class QROAMClean(SelectSwapQROM): Berry et al. (2019). Appendix A. and B. """ - log_block_sizes: Tuple[SymbolicInt, ...] = attrs.field( + log_block_sizes: tuple[SymbolicInt, ...] = attrs.field( converter=lambda x: tuple(x.tolist() if isinstance(x, np.ndarray) else x) ) use_dirty_ancilla: bool = attrs.field(init=False, default=False, repr=False) @@ -367,7 +367,7 @@ def _target_reg_side(self) -> Side: return Side.RIGHT @log_block_sizes.default - def _default_log_block_sizes(self) -> Tuple[SymbolicInt, ...]: + def _default_log_block_sizes(self) -> tuple[SymbolicInt, ...]: target_bitsize = sum( bs * prod(shape) for (bs, shape) in zip(self.target_bitsizes, self.target_shapes) ) @@ -380,9 +380,9 @@ def _default_log_block_sizes(self) -> Tuple[SymbolicInt, ...]: def build_from_data( cls: Type['QROAMClean'], *data: ArrayLike, - target_bitsizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + target_bitsizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, num_controls: SymbolicInt = 0, - log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, ) -> 'QROAMClean': qroam: 'QROAMClean' = cls._build_from_data( *data, target_bitsizes=target_bitsizes, num_controls=num_controls @@ -392,12 +392,12 @@ def build_from_data( @classmethod def build_from_bitsize( cls: Type['QROAMClean'], - data_len_or_shape: Union[SymbolicInt, Tuple[SymbolicInt, ...]], - target_bitsizes: Union[SymbolicInt, Tuple[SymbolicInt, ...]], + data_len_or_shape: Union[SymbolicInt, tuple[SymbolicInt, ...]], + target_bitsizes: Union[SymbolicInt, tuple[SymbolicInt, ...]], *, - selection_bitsizes: Tuple[SymbolicInt, ...] = (), + selection_bitsizes: tuple[SymbolicInt, ...] = (), num_controls: SymbolicInt = 0, - log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, ) -> 'QROAMClean': qroam: 'QROAMClean' = cls._build_from_bitsize( data_len_or_shape, @@ -419,16 +419,16 @@ def signature(self) -> Signature: ) @cached_property - def batched_data_permuted(self) -> List[np.ndarray]: + def batched_data_permuted(self) -> list[np.ndarray]: if is_symbolic(*self.block_sizes): raise ValueError( f"Cannot decompose SelectSwapQROM bloq with symbolic block sizes. Found {self.block_sizes=}" ) - block_sizes = cast(Tuple[int, ...], self.block_sizes) + block_sizes = cast(tuple[int, ...], self.block_sizes) ret = [] for data, swz in zip(self.batched_data, self.swap_with_zero_bloqs): permuted_batched_data = np.zeros(data.shape + block_sizes, dtype=data.dtype) - for sel_l in np.ndindex(cast(Tuple[int, ...], self.batched_qrom_shape)): + for sel_l in np.ndindex(cast(tuple[int, ...], self.batched_qrom_shape)): for sel_k in np.ndindex(block_sizes): sel_kwargs = {reg.name: sel for reg, sel in zip(swz.selection_registers, sel_k)} curr_data = swz.call_classically(**sel_kwargs, targets=np.copy(data[sel_l]))[-1] @@ -449,7 +449,7 @@ def batched_data_permuted(self) -> List[np.ndarray]: return ret @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: # The newly allocated registers should be kept around for measurement based uncomputation. junk_regs = [] block_size = prod(self.block_sizes) @@ -460,7 +460,7 @@ def junk_registers(self) -> Tuple[Register, ...]: return tuple(junk_regs) def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': - ret: Dict[Bloq, SymbolicInt] = defaultdict(lambda: 0) + ret: dict[Bloq, SymbolicInt] = defaultdict(lambda: 0) ret[self.qrom_bloq] += 1 for swz in self.swap_with_zero_bloqs: if any(is_symbolic(s) or s > 0 for s in swz.selection_bitsizes): @@ -479,17 +479,17 @@ def my_static_costs(self, cost_key: "CostKey"): def _build_composite_bloq_with_swz_clean( self, bb: 'BloqBuilder', - ctrl: List['SoquetT'], - selection: List['SoquetT'], - qrom_targets: List['SoquetT'], - ) -> Tuple[List['SoquetT'], List['SoquetT'], List['SoquetT']]: + ctrl: list['SoquetT'], + selection: list['SoquetT'], + qrom_targets: list['SoquetT'], + ) -> tuple[list['SoquetT'], list['SoquetT'], list['SoquetT']]: sel_l, sel_k = self._partition_sel_register(bb, selection) ctrl, sel_l, qrom_targets = self._add_qrom_bloq(bb, ctrl, sel_l, qrom_targets) sel_k, qrom_targets = self._add_swap_with_zero_bloq(bb, sel_k, qrom_targets) selection = self._unpartition_sel_register(bb, sel_l, sel_k) return ctrl, selection, qrom_targets - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: # Get the ctrl and target register for the SelectSwapQROM. ctrl = [soqs.pop(reg.name) for reg in self.control_registers] selection = [soqs.pop(reg.name) for reg in self.selection_registers] @@ -497,7 +497,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str raise ValueError( f"Cannot decompose QROAM bloq with symbolic block sizes. Found {self.block_sizes=}" ) - block_sizes = cast(Tuple[int, ...], self.block_sizes) + block_sizes = cast(tuple[int, ...], self.block_sizes) # Allocate intermediate clean/dirty ancilla for the underlying QROM call. qrom_targets = [] for reg in self.target_registers: @@ -526,9 +526,9 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str def on_classical_vals( self, **vals: Union['sympy.Symbol', 'ClassicalValT'] - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: vals_without_junk = super().on_classical_vals(**vals) - selection = cast(Tuple[int, ...], tuple(vals[reg.name] for reg in self.selection_registers)) + selection = cast(tuple[int, ...], tuple(vals[reg.name] for reg in self.selection_registers)) for d, junk_reg in zip(self.batched_data_permuted, self.junk_registers): vals_without_junk[junk_reg.name] = d[selection].flat[1:] return vals_without_junk @@ -536,7 +536,7 @@ def on_classical_vals( def adjoint(self) -> 'QROAMCleanAdjointWrapper': return QROAMCleanAdjointWrapper(self) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('QROAM') name = reg.name diff --git a/qualtran/bloqs/data_loading/qrom.py b/qualtran/bloqs/data_loading/qrom.py index 51b8bcacaa..ad10c2a63d 100644 --- a/qualtran/bloqs/data_loading/qrom.py +++ b/qualtran/bloqs/data_loading/qrom.py @@ -14,7 +14,8 @@ """Quantum read-only memory.""" import numbers -from typing import cast, Iterable, Iterator, Optional, Sequence, Set, Tuple, TYPE_CHECKING, Union +from collections.abc import Iterable, Iterator, Sequence +from typing import cast, Optional, TYPE_CHECKING, Union import attrs import cirq @@ -85,8 +86,8 @@ class QROM(QROMBase, UnaryIterationGate): # type: ignore[misc] def build_from_data( cls, *data: ArrayLike, - target_bitsizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, - target_shapes: Tuple[Tuple[SymbolicInt, ...], ...] = (), + target_bitsizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, + target_shapes: tuple[tuple[SymbolicInt, ...], ...] = (), num_controls: SymbolicInt = 0, ) -> 'QROM': return cls._build_from_data( @@ -99,11 +100,11 @@ def build_from_data( @classmethod def build_from_bitsize( cls, - data_len_or_shape: Union[SymbolicInt, Tuple[SymbolicInt, ...]], - target_bitsizes: Union[SymbolicInt, Tuple[SymbolicInt, ...]], + data_len_or_shape: Union[SymbolicInt, tuple[SymbolicInt, ...]], + target_bitsizes: Union[SymbolicInt, tuple[SymbolicInt, ...]], *, - target_shapes: Tuple[Tuple[SymbolicInt, ...], ...] = (), - selection_bitsizes: Tuple[SymbolicInt, ...] = (), + target_shapes: tuple[tuple[SymbolicInt, ...], ...] = (), + selection_bitsizes: tuple[SymbolicInt, ...] = (), num_controls: SymbolicInt = 0, ) -> 'QROM': return cls._build_from_bitsize( @@ -116,15 +117,15 @@ def build_from_bitsize( def _load_nth_data( self, - selection_idx: Tuple[int, ...], - ctrl_qubits: Tuple[cirq.Qid, ...] = (), + selection_idx: tuple[int, ...], + ctrl_qubits: tuple[cirq.Qid, ...] = (), **target_regs: NDArray[cirq.Qid], # type: ignore[type-var] ) -> Iterator[cirq.OP_TREE]: for i, d in enumerate(self.data): target = target_regs.get(f'target{i}_', np.array([])) target_bitsize, target_shape = self.target_bitsizes[i], self.target_shapes[i] assert all(isinstance(x, (int, numbers.Integral)) for x in target_shape) - for idx in np.ndindex(cast(Tuple[int, ...], target_shape)): + for idx in np.ndindex(cast(tuple[int, ...], target_shape)): data_to_load = int(d[selection_idx + idx]) yield XorK(QUInt(target_bitsize), data_to_load).on(*target[idx]).controlled_by( *ctrl_qubits @@ -160,7 +161,7 @@ def decompose_from_registers( return super().decompose_from_registers(context=context, **quregs) raise DecomposeTypeError(f"Cannot decompose symbolic {self} with no data.") - def _break_early(self, selection_index_prefix: Tuple[int, ...], l: int, r: int): + def _break_early(self, selection_index_prefix: tuple[int, ...], l: int, r: int): if not self.has_data(): return False @@ -195,7 +196,7 @@ def my_static_costs(self, cost_key: "CostKey"): def __str__(self): return f'QROM({self.data_shape}, {self.target_shapes}, {self.target_bitsizes})' - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('QROM') name = reg.name @@ -215,20 +216,20 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) - return Circle() raise ValueError(f'Unrecognized register name {name}') - def nth_operation_callgraph(self, **kwargs: int) -> Set['BloqCountT']: + def nth_operation_callgraph(self, **kwargs: int) -> set['BloqCountT']: selection_idx = tuple(kwargs[reg.name] for reg in self.selection_registers) ret = 0 for i, d in enumerate(self.data): target_bitsize, target_shape = self.target_bitsizes[i], self.target_shapes[i] assert all(isinstance(x, (int, numbers.Integral)) for x in target_shape) - for idx in np.ndindex(cast(Tuple[int, ...], target_shape)): + for idx in np.ndindex(cast(tuple[int, ...], target_shape)): data_to_load = int(d[selection_idx + idx]) ret += data_to_load.bit_count() return {(CNOT(), ret)} def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if self.has_data(): return super().build_call_graph(ssa=ssa) n_and = prod(self.data_shape) - 2 + self.num_controls diff --git a/qualtran/bloqs/data_loading/qrom_base.py b/qualtran/bloqs/data_loading/qrom_base.py index efe1c5e230..4eba8a4599 100644 --- a/qualtran/bloqs/data_loading/qrom_base.py +++ b/qualtran/bloqs/data_loading/qrom_base.py @@ -16,7 +16,7 @@ import abc import numbers from functools import cached_property -from typing import cast, Dict, Optional, Tuple, Type, TypeVar, Union +from typing import cast, Optional, Type, TypeVar, Union import attrs import numpy as np @@ -30,7 +30,7 @@ QROM_T = TypeVar('QROM_T', bound='QROMBase') -def _data_or_shape_to_tuple(data_or_shape: Tuple[Union[NDArray, Shaped], ...]) -> Tuple: +def _data_or_shape_to_tuple(data_or_shape: tuple[Union[NDArray, Shaped], ...]) -> tuple: return tuple(tuple(d.flatten()) if isinstance(d, np.ndarray) else d for d in data_or_shape) @@ -150,17 +150,17 @@ class QROMBase(metaclass=abc.ABCMeta): num_controls: The number of controls to instanstiate a controlled version of this bloq. """ - data_or_shape: Tuple[Union[NDArray, Shaped], ...] = attrs.field( + data_or_shape: tuple[Union[NDArray, Shaped], ...] = attrs.field( converter=lambda x: tuple(np.array(y) if isinstance(y, (list, tuple)) else y for y in x), eq=_data_or_shape_to_tuple, ) - selection_bitsizes: Tuple[SymbolicInt, ...] = attrs.field( + selection_bitsizes: tuple[SymbolicInt, ...] = attrs.field( converter=lambda x: tuple(x.tolist() if isinstance(x, np.ndarray) else x) ) - target_bitsizes: Tuple[SymbolicInt, ...] = attrs.field( + target_bitsizes: tuple[SymbolicInt, ...] = attrs.field( converter=lambda x: tuple(x.tolist() if isinstance(x, np.ndarray) else x) ) - target_shapes: Tuple[Tuple[SymbolicInt, ...], ...] = attrs.field( + target_shapes: tuple[tuple[SymbolicInt, ...], ...] = attrs.field( converter=lambda x: tuple(tuple(y) for y in x) ) num_controls: SymbolicInt = 0 @@ -179,8 +179,8 @@ def _default_target_shapes(self): return ((),) * len(self.data_or_shape) @cached_property - def data_shape(self) -> Tuple[SymbolicInt, ...]: - ret: Tuple[SymbolicInt, ...] = () + def data_shape(self) -> tuple[SymbolicInt, ...]: + ret: tuple[SymbolicInt, ...] = () for data_or_shape, target_shape in zip(self.data_or_shape, self.target_shapes): data_shape = shape(data_or_shape) if target_shape: @@ -195,11 +195,11 @@ def has_data(self) -> bool: return all(isinstance(d, np.ndarray) for d in self.data_or_shape) @property - def data(self) -> Tuple[np.ndarray, ...]: + def data(self) -> tuple[np.ndarray, ...]: if not self.has_data(): raise ValueError(f"Data not available for symbolic QROM {self}") assert all(isinstance(d, np.ndarray) for d in self.data_or_shape) - return cast(Tuple[np.ndarray, ...], self.data_or_shape) + return cast(tuple[np.ndarray, ...], self.data_or_shape) def __attrs_post_init__(self): assert all([is_symbolic(s) or isinstance(s, int) for s in self.selection_bitsizes]) @@ -220,8 +220,8 @@ def __attrs_post_init__(self): def _build_from_data( cls: Type[QROM_T], *data: ArrayLike, - target_bitsizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, - target_shapes: Tuple[Tuple[SymbolicInt, ...], ...] = (), + target_bitsizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, + target_shapes: tuple[tuple[SymbolicInt, ...], ...] = (), num_controls: SymbolicInt = 0, ) -> QROM_T: _data = [np.array(d, dtype=int) for d in data] @@ -250,14 +250,14 @@ def with_data(self: QROM_T, *data: ArrayLike) -> QROM_T: @classmethod def _build_from_bitsize( cls: Type[QROM_T], - data_len_or_shape: Union[SymbolicInt, Tuple[SymbolicInt, ...]], - target_bitsizes: Union[SymbolicInt, Tuple[SymbolicInt, ...]], + data_len_or_shape: Union[SymbolicInt, tuple[SymbolicInt, ...]], + target_bitsizes: Union[SymbolicInt, tuple[SymbolicInt, ...]], *, - target_shapes: Tuple[Tuple[SymbolicInt, ...], ...] = (), - selection_bitsizes: Tuple[SymbolicInt, ...] = (), + target_shapes: tuple[tuple[SymbolicInt, ...], ...] = (), + selection_bitsizes: tuple[SymbolicInt, ...] = (), num_controls: SymbolicInt = 0, ) -> QROM_T: - data_shape: Tuple[SymbolicInt, ...] = ( + data_shape: tuple[SymbolicInt, ...] = ( (data_len_or_shape,) if isinstance(data_len_or_shape, (int, numbers.Number, sympy.Basic)) else data_len_or_shape @@ -279,11 +279,11 @@ def _build_from_bitsize( ) @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if not self.num_controls else (Register('control', QAny(self.num_controls)),) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: types = [ BQUInt(sb, l) for l, sb in zip(self.data_shape, self.selection_bitsizes) @@ -298,7 +298,7 @@ def _target_reg_side(self) -> Side: return Side.THRU @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return tuple( Register(f'target{i}_', QAny(l), shape=sh, side=self._target_reg_side) for i, (l, sh) in enumerate(zip(self.target_bitsizes, self.target_shapes)) @@ -307,10 +307,10 @@ def target_registers(self) -> Tuple[Register, ...]: def on_classical_vals( self, **vals: Union['sympy.Symbol', 'ClassicalValT'] - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if not self.has_data(): raise NotImplementedError(f'Symbolic {self} does not support classical simulation') - vals = cast(Dict[str, 'ClassicalValT'], vals) + vals = cast(dict[str, 'ClassicalValT'], vals) if self.num_controls > 0: control = vals['control'] if control != 2**self.num_controls - 1: @@ -321,7 +321,7 @@ def on_classical_vals( n_dim = len(self.selection_registers) if n_dim == 0: - idx: Union[int, Tuple[int, ...]] = 0 + idx: Union[int, tuple[int, ...]] = 0 selections = {} elif n_dim == 1: idx = int(vals.pop('selection', 0)) diff --git a/qualtran/bloqs/data_loading/select_swap_qrom.py b/qualtran/bloqs/data_loading/select_swap_qrom.py index 6d1d5407d7..38f8205593 100644 --- a/qualtran/bloqs/data_loading/select_swap_qrom.py +++ b/qualtran/bloqs/data_loading/select_swap_qrom.py @@ -14,7 +14,7 @@ import numbers from collections import defaultdict from functools import cached_property -from typing import cast, Dict, List, Optional, Tuple, Type, TYPE_CHECKING, TypeVar, Union +from typing import cast, Optional, Type, TYPE_CHECKING, TypeVar, Union import attrs import cirq @@ -68,14 +68,14 @@ def find_optimal_log_block_size( if k < 0: return 0 - def value(kk: List[int]): + def value(kk: list[int]): return iteration_length / np.power(2, kk) + target_bitsize * (np.power(2, kk) - 1) k_int = [np.floor(k), np.ceil(k)] # restrict optimal k to integers return int(k_int[np.argmin(value(k_int))]) # obtain optimal k -def _find_optimal_log_block_size_helper(qrom: 'SelectSwapQROM') -> Tuple[SymbolicInt, ...]: +def _find_optimal_log_block_size_helper(qrom: 'SelectSwapQROM') -> tuple[SymbolicInt, ...]: target_bitsize = sum(qrom.target_bitsizes) * sum(prod(shape) for shape in qrom.target_shapes) return tuple( find_optimal_log_block_size(ilen, target_bitsize, qrom.use_dirty_ancilla) @@ -84,7 +84,7 @@ def _find_optimal_log_block_size_helper(qrom: 'SelectSwapQROM') -> Tuple[Symboli def _alloc_anc_for_reg( - bb: 'BloqBuilder', dtype: 'QDType', shape: Tuple[int, ...], dirty: bool + bb: 'BloqBuilder', dtype: 'QDType', shape: tuple[int, ...], dirty: bool ) -> 'SoquetT': if not shape: return bb.allocate(dtype=dtype, dirty=dirty) @@ -139,7 +139,7 @@ class SelectSwapQROM(QROMBase, GateWithRegisters): # type: ignore[misc] Berry et al. 2019. Appendix A. and B. """ - log_block_sizes: Tuple[SymbolicInt, ...] = attrs.field( + log_block_sizes: tuple[SymbolicInt, ...] = attrs.field( converter=lambda x: ( tuple(x.tolist() if isinstance(x, np.ndarray) else x) if x is not None else x ), @@ -170,9 +170,9 @@ def is_symbolic(self) -> bool: def build_from_data( cls: Type['SelectSwapQROM'], *data: ArrayLike, - target_bitsizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + target_bitsizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, num_controls: SymbolicInt = 0, - log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, use_dirty_ancilla: bool = True, ) -> 'SelectSwapQROM': qroam: 'SelectSwapQROM' = cls._build_from_data( @@ -186,12 +186,12 @@ def build_from_data( @classmethod def build_from_bitsize( cls: Type['SelectSwapQROM'], - data_len_or_shape: Union[SymbolicInt, Tuple[SymbolicInt, ...]], - target_bitsizes: Union[SymbolicInt, Tuple[SymbolicInt, ...]], + data_len_or_shape: Union[SymbolicInt, tuple[SymbolicInt, ...]], + target_bitsizes: Union[SymbolicInt, tuple[SymbolicInt, ...]], *, - selection_bitsizes: Tuple[SymbolicInt, ...] = (), + selection_bitsizes: tuple[SymbolicInt, ...] = (), num_controls: SymbolicInt = 0, - log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, use_dirty_ancilla: bool = True, ) -> 'SelectSwapQROM': qroam: 'SelectSwapQROM' = cls._build_from_bitsize( @@ -207,7 +207,7 @@ def build_from_bitsize( def with_log_block_sizes( self: SelSwapQROM_T, - log_block_sizes: Optional[Union[SymbolicInt, Tuple[SymbolicInt, ...]]] = None, + log_block_sizes: Optional[Union[SymbolicInt, tuple[SymbolicInt, ...]]] = None, ) -> 'SelSwapQROM_T': if log_block_sizes is None: return self @@ -218,30 +218,30 @@ def with_log_block_sizes( return attrs.evolve(self, log_block_sizes=log_block_sizes) @cached_property - def block_sizes(self) -> Tuple[SymbolicInt, ...]: + def block_sizes(self) -> tuple[SymbolicInt, ...]: return tuple(2**log_K for log_K in self.log_block_sizes) @cached_property - def batched_qrom_shape(self) -> Tuple[SymbolicInt, ...]: + def batched_qrom_shape(self) -> tuple[SymbolicInt, ...]: return tuple(ceil(N / K) for N, K in zip(self.data_shape, self.block_sizes)) @cached_property - def batched_qrom_selection_bitsizes(self) -> Tuple[SymbolicInt, ...]: + def batched_qrom_selection_bitsizes(self) -> tuple[SymbolicInt, ...]: return tuple(s - log_K for s, log_K in zip(self.selection_bitsizes, self.log_block_sizes)) @cached_property - def padded_data(self) -> List[np.ndarray]: + def padded_data(self) -> list[np.ndarray]: pad_width = tuple( (0, ceil(N / K) * K - N) for N, K in zip(self.data_shape, self.block_sizes) ) return [np.pad(d, pad_width) for d in self.data] @cached_property - def batched_data_shape(self) -> Tuple[int, ...]: - return cast(Tuple[int, ...], self.batched_qrom_shape + self.block_sizes) + def batched_data_shape(self) -> tuple[int, ...]: + return cast(tuple[int, ...], self.batched_qrom_shape + self.block_sizes) @cached_property - def batched_data(self) -> List[np.ndarray]: + def batched_data(self) -> list[np.ndarray]: # In SelectSwapQROM, for N-dimensional data (one or more datasets), you pick block sizes for # each dimension and load a batched N-dimensional output "at-once" using a traditional QROM read # followed by an N-dimensional SwapWithZero swap. @@ -251,7 +251,7 @@ def batched_data(self) -> List[np.ndarray]: batched_data = [np.zeros(self.batched_data_shape, dtype=int) for _ in self.target_bitsizes] block_slices = [slice(0, k) for k in self.block_sizes] for i, data in enumerate(self.padded_data): - for batch_idx in np.ndindex(cast(Tuple[int, ...], self.batched_qrom_shape)): + for batch_idx in np.ndindex(cast(tuple[int, ...], self.batched_qrom_shape)): data_idx = [slice(x * k, (x + 1) * k) for x, k in zip(batch_idx, self.block_sizes)] batched_data[i][(*batch_idx, *block_slices)] = data[tuple(data_idx)] return batched_data @@ -268,7 +268,7 @@ def qrom_bloq(self) -> QROM: return qrom if is_symbolic(self) else qrom.with_data(*self.batched_data) @cached_property - def swap_with_zero_bloqs(self) -> List[SwapWithZero]: + def swap_with_zero_bloqs(self) -> list[SwapWithZero]: return [ SwapWithZero( self.log_block_sizes, @@ -279,7 +279,7 @@ def swap_with_zero_bloqs(self) -> List[SwapWithZero]: ] def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': - ret: Dict[Bloq, SymbolicInt] = defaultdict(lambda: 0) + ret: dict[Bloq, SymbolicInt] = defaultdict(lambda: 0) toggle_overhead = 2 if self.use_dirty_ancilla else 1 ret[self.qrom_bloq] += 1 ret[self.qrom_bloq.adjoint()] += 1 @@ -294,11 +294,11 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': def _add_qrom_bloq( self, bb: 'BloqBuilder', - ctrls: List['SoquetT'], - sel_l: List['SoquetT'], - targets: List['SoquetT'], + ctrls: list['SoquetT'], + sel_l: list['SoquetT'], + targets: list['SoquetT'], uncompute: bool = False, - ) -> Tuple[List['SoquetT'], List['SoquetT'], List['SoquetT']]: + ) -> tuple[list['SoquetT'], list['SoquetT'], list['SoquetT']]: in_soqs = {reg.name: soq for reg, soq in zip(self.qrom_bloq.control_registers, ctrls)} in_soqs |= {reg.name: soq for reg, soq in zip(self.qrom_bloq.selection_registers, sel_l)} in_soqs |= {reg.name: soq for reg, soq in zip(self.qrom_bloq.target_registers, targets)} @@ -311,15 +311,15 @@ def _add_qrom_bloq( def _add_swap_with_zero_bloq( self, bb: 'BloqBuilder', - selection: List['SoquetT'], - targets: List['SoquetT'], + selection: list['SoquetT'], + targets: list['SoquetT'], uncompute: bool = False, - ) -> Tuple[List['SoquetT'], List['SoquetT']]: + ) -> tuple[list['SoquetT'], list['SoquetT']]: # Get soquets for SwapWithZero assert len(targets) == len(self.swap_with_zero_bloqs) sel_names = [reg.name for reg in self.swap_with_zero_bloqs[0].selection_registers] soqs = {sel_name: soq for sel_name, soq in zip(sel_names, selection)} - out_targets: List['SoquetT'] = [] + out_targets: list['SoquetT'] = [] for target, swz in zip(targets, self.swap_with_zero_bloqs): soqs['targets'] = target soqs = bb.add_d(swz.adjoint() if uncompute else swz, **soqs) @@ -327,8 +327,8 @@ def _add_swap_with_zero_bloq( return [soqs[reg_name] for reg_name in sel_names], out_targets def _add_cnot( - self, bb: 'BloqBuilder', qrom_targets: List['SoquetT'], target: List['SoquetT'] - ) -> Tuple[List['SoquetT'], List['SoquetT']]: + self, bb: 'BloqBuilder', qrom_targets: list['SoquetT'], target: list['SoquetT'] + ) -> tuple[list['SoquetT'], list['SoquetT']]: for i, qrom_reg in enumerate(qrom_targets): assert isinstance(qrom_reg, np.ndarray) # Make mypy happy. idx = np.unravel_index(0, qrom_reg.shape) @@ -338,7 +338,7 @@ def _add_cnot( return qrom_targets, target @cached_property - def _partition_selection_reg_bloqs(self) -> List[Partition]: + def _partition_selection_reg_bloqs(self) -> list[Partition]: partition_bloqs = [] for reg, k in zip(self.selection_registers, self.log_block_sizes): preg = ( @@ -349,8 +349,8 @@ def _partition_selection_reg_bloqs(self) -> List[Partition]: return partition_bloqs def _partition_sel_register( - self, bb: 'BloqBuilder', selection: List['SoquetT'] - ) -> Tuple[List['SoquetT'], List['SoquetT']]: + self, bb: 'BloqBuilder', selection: list['SoquetT'] + ) -> tuple[list['SoquetT'], list['SoquetT']]: sel_l, sel_k = [], [] for sel, pbloq in zip(selection, self._partition_selection_reg_bloqs): sl, sk = bb.add(pbloq, x=sel) @@ -359,8 +359,8 @@ def _partition_sel_register( return sel_l, sel_k def _unpartition_sel_register( - self, bb: 'BloqBuilder', sel_l: List['SoquetT'], sel_k: List['SoquetT'] - ) -> List['SoquetT']: + self, bb: 'BloqBuilder', sel_l: list['SoquetT'], sel_k: list['SoquetT'] + ) -> list['SoquetT']: selection = [] for l, k, pbloq in zip(sel_l, sel_k, self._partition_selection_reg_bloqs): selection.append(bb.add(pbloq.adjoint(), l=l, k=k)) @@ -369,11 +369,11 @@ def _unpartition_sel_register( def _build_composite_bloq_with_swz( self, bb: 'BloqBuilder', - ctrl: List['SoquetT'], - selection: List['SoquetT'], - target: List['SoquetT'], - qrom_targets: List['SoquetT'], - ) -> Tuple[List['SoquetT'], List['SoquetT'], List['SoquetT'], List['SoquetT']]: + ctrl: list['SoquetT'], + selection: list['SoquetT'], + target: list['SoquetT'], + qrom_targets: list['SoquetT'], + ) -> tuple[list['SoquetT'], list['SoquetT'], list['SoquetT'], list['SoquetT']]: sel_l, sel_k = self._partition_sel_register(bb, selection) # Partition selection registers into l & k ctrl, sel_l, qrom_targets = self._add_qrom_bloq(bb, ctrl, sel_l, qrom_targets) @@ -396,11 +396,11 @@ def _build_composite_bloq_with_swz( def _build_composite_bloq_without_swz( self, bb: 'BloqBuilder', - ctrl: List['SoquetT'], - selection: List['SoquetT'], - target: List['SoquetT'], - qrom_targets: List['SoquetT'], - ) -> Tuple[List['SoquetT'], List['SoquetT'], List['SoquetT'], List['SoquetT']]: + ctrl: list['SoquetT'], + selection: list['SoquetT'], + target: list['SoquetT'], + qrom_targets: list['SoquetT'], + ) -> tuple[list['SoquetT'], list['SoquetT'], list['SoquetT'], list['SoquetT']]: ctrl, selection, qrom_targets = self._add_qrom_bloq(bb, ctrl, selection, qrom_targets) qrom_targets, target = self._add_cnot(bb, qrom_targets, target) ctrl, selection, qrom_targets = self._add_qrom_bloq( @@ -410,7 +410,7 @@ def _build_composite_bloq_without_swz( qrom_targets, target = self._add_cnot(bb, qrom_targets, target) return ctrl, selection, target, qrom_targets - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: # Get the ctrl and target register for the SelectSwapQROM. ctrl = [soqs.pop(reg.name) for reg in self.control_registers] selection = [soqs.pop(reg.name) for reg in self.selection_registers] @@ -420,7 +420,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str raise DecomposeTypeError( f"Cannot decompose SelectSwapQROM bloq with symbolic block sizes. Found {self.block_sizes=}" ) - block_sizes = cast(Tuple[int, ...], self.block_sizes) + block_sizes = cast(tuple[int, ...], self.block_sizes) qrom_targets = [ _alloc_anc_for_reg(bb, QAny(reg.dtype.num_qubits), block_sizes, self.use_dirty_ancilla) for reg in self.target_registers @@ -469,7 +469,7 @@ def my_static_costs(self, cost_key: "CostKey"): return NotImplemented - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('QROAM') name = reg.name diff --git a/qualtran/bloqs/for_testing/atom.py b/qualtran/bloqs/for_testing/atom.py index 210ede7e84..096a4ec56e 100644 --- a/qualtran/bloqs/for_testing/atom.py +++ b/qualtran/bloqs/for_testing/atom.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, List, Optional, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import attrs import numpy as np @@ -54,8 +54,8 @@ def decompose_bloq(self) -> 'CompositeBloq': raise DecomposeTypeError(f"{self} is atomic") def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ @@ -93,8 +93,8 @@ def decompose_bloq(self) -> 'CompositeBloq': raise DecomposeTypeError(f"{self} is atomic") def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn _I = [[1, 0], [0, 1]] @@ -138,8 +138,8 @@ def decompose_bloq(self) -> 'CompositeBloq': raise DecomposeTypeError(f"{self} is atomic") def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: from qualtran.cirq_interop._cirq_to_bloq import _my_tensors_from_gate return _my_tensors_from_gate(self, self.signature, incoming=incoming, outgoing=outgoing) diff --git a/qualtran/bloqs/for_testing/casting.py b/qualtran/bloqs/for_testing/casting.py index d78863d361..a739220f4a 100644 --- a/qualtran/bloqs/for_testing/casting.py +++ b/qualtran/bloqs/for_testing/casting.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict from attrs import frozen @@ -44,7 +43,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: 'BloqBuilder', *, a: 'Soquet', b: 'Soquet' - ) -> Dict[str, 'Soquet']: + ) -> dict[str, 'Soquet']: cast = Cast(b.reg.dtype, a.reg.dtype) b = bb.add(cast, reg=b) assert isinstance(a.reg.dtype, (QInt, QUInt, QMontgomeryUInt)) diff --git a/qualtran/bloqs/for_testing/costing.py b/qualtran/bloqs/for_testing/costing.py index bef3826962..efacdfad54 100644 --- a/qualtran/bloqs/for_testing/costing.py +++ b/qualtran/bloqs/for_testing/costing.py @@ -11,7 +11,8 @@ # 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 typing import Any, Sequence, Tuple +from collections.abc import Sequence +from typing import Any from attrs import field, frozen @@ -19,14 +20,14 @@ from qualtran.resource_counting import BloqCountDictT, BloqCountT, CostKey, SympySymbolAllocator -def _convert_callees(callees: Sequence[BloqCountT]) -> Tuple[BloqCountT, ...]: +def _convert_callees(callees: Sequence[BloqCountT]) -> tuple[BloqCountT, ...]: # Convert to tuples in a type-checked way. return tuple(callees) def _convert_static_costs( - static_costs: Sequence[Tuple[CostKey, Any]] -) -> Tuple[Tuple[CostKey, Any], ...]: + static_costs: Sequence[tuple[CostKey, Any]] +) -> tuple[tuple[CostKey, Any], ...]: # Convert to tuples in a type-checked way. return tuple(static_costs) @@ -38,7 +39,7 @@ class CostingBloq(Bloq): name: str num_qubits: int callees: Sequence[BloqCountT] = field(converter=_convert_callees, factory=tuple) - static_costs: Sequence[Tuple[CostKey, Any]] = field( + static_costs: Sequence[tuple[CostKey, Any]] = field( converter=_convert_static_costs, factory=tuple ) diff --git a/qualtran/bloqs/for_testing/interior_alloc.py b/qualtran/bloqs/for_testing/interior_alloc.py index 1a25add1c9..5bf45e7397 100644 --- a/qualtran/bloqs/for_testing/interior_alloc.py +++ b/qualtran/bloqs/for_testing/interior_alloc.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Union +from typing import Union import sympy from attrs import frozen @@ -34,7 +34,7 @@ class InteriorAlloc(Bloq): def signature(self) -> 'Signature': return Signature.build(x=self.n, y=self.n) - def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet, y: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet, y: Soquet) -> dict[str, 'SoquetT']: middle = bb.allocate(self.n) x, middle = bb.add(Swap(self.n), x=x, y=middle) middle, y = bb.add(Swap(self.n), x=middle, y=y) diff --git a/qualtran/bloqs/for_testing/large_bloq.py b/qualtran/bloqs/for_testing/large_bloq.py index 810a9d4e35..1d4ee89738 100644 --- a/qualtran/bloqs/for_testing/large_bloq.py +++ b/qualtran/bloqs/for_testing/large_bloq.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, List - import numpy as np from attrs import frozen @@ -31,9 +29,9 @@ class LargeBloq(Bloq): def signature(self) -> 'Signature': return Signature.build(select=self.n_select, target=1) - def build_composite_bloq(self, bb: 'BloqBuilder', select, target) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', select, target) -> dict[str, 'SoquetT']: sel = bb.split(select) - ancs: List[Soquet] = [None] * self.n_select # type: ignore + ancs: list[Soquet] = [None] * self.n_select # type: ignore ancs[0] = sel[0] cvs = QUInt(self.n_select - 1).to_bits_array(np.arange(self.n_ops) % (self.n_select - 1)) diff --git a/qualtran/bloqs/for_testing/many_registers.py b/qualtran/bloqs/for_testing/many_registers.py index 99f89f1589..4f2db2d7af 100644 --- a/qualtran/bloqs/for_testing/many_registers.py +++ b/qualtran/bloqs/for_testing/many_registers.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict import numpy as np from attrs import frozen @@ -54,7 +53,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: 'BloqBuilder', xx: 'SoquetT', yy: NDArray['Soquet'], zz: Soquet # type: ignore[type-var] - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: xx = bb.add(TestAtom(), q=xx) for i in range(2): for j in range(2): @@ -106,7 +105,7 @@ def signature(self) -> Signature: def build_composite_bloq( self, bb: 'BloqBuilder', a: 'SoquetT', b: 'SoquetT', c: 'SoquetT', d: 'Soquet' - ) -> Dict[str, 'Soquet']: + ) -> dict[str, 'Soquet']: a, b = bb.add(TestBoundedQUInt(), xx=a, yy=d) b, c = bb.add(TestQFxp(), xx=b, yy=c) return {'a': a, 'b': b, 'c': c, 'd': d} diff --git a/qualtran/bloqs/for_testing/matrix_gate.py b/qualtran/bloqs/for_testing/matrix_gate.py index 7665416abd..7415508877 100644 --- a/qualtran/bloqs/for_testing/matrix_gate.py +++ b/qualtran/bloqs/for_testing/matrix_gate.py @@ -11,7 +11,7 @@ # 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 typing import Dict, List, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np from attrs import field, frozen @@ -36,7 +36,7 @@ class MatrixGate(GateWithRegisters): """ bitsize: int - matrix: Tuple[Tuple[complex, ...], ...] = field( + matrix: tuple[tuple[complex, ...], ...] = field( converter=lambda mat: tuple(tuple(row) for row in mat) ) atol: float = 1e-10 @@ -64,8 +64,8 @@ def random(cls, bitsize: int, *, random_state=None) -> 'MatrixGate': return cls(bitsize, matrix) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn data = np.array(self.matrix).reshape((2,) * (self.bitsize * 2)) diff --git a/qualtran/bloqs/for_testing/qubitization_walk_test.py b/qualtran/bloqs/for_testing/qubitization_walk_test.py index d1c0fdb5e6..66dbdb4d9e 100644 --- a/qualtran/bloqs/for_testing/qubitization_walk_test.py +++ b/qualtran/bloqs/for_testing/qubitization_walk_test.py @@ -11,8 +11,8 @@ # 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 collections.abc import Iterator from functools import cached_property -from typing import Iterator, Tuple import attrs import cirq @@ -31,17 +31,17 @@ @attrs.frozen class PrepareUniformSuperpositionTest(PrepareOracle): n: int - cvs: Tuple[int, ...] = attrs.field( + cvs: tuple[int, ...] = attrs.field( converter=lambda v: (v,) if isinstance(v, int) else tuple(v), default=() ) qlambda: float = 0.0 @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('selection', BQUInt((self.n - 1).bit_length(), self.n)),) @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return () @cached_property diff --git a/qualtran/bloqs/for_testing/random_select_and_prepare.py b/qualtran/bloqs/for_testing/random_select_and_prepare.py index 6e1a607f5a..81fdd20f86 100644 --- a/qualtran/bloqs/for_testing/random_select_and_prepare.py +++ b/qualtran/bloqs/for_testing/random_select_and_prepare.py @@ -11,8 +11,9 @@ # 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 collections.abc import Iterator from functools import cached_property -from typing import Iterator, Optional, Tuple +from typing import Optional import attrs import cirq @@ -123,15 +124,15 @@ def random( return cls(select_bitsize, target_bitsize, dps) @property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('control', QBit()),) @property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('selection', BQUInt(bitsize=self.select_bitsize)),) @property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register('target', BQUInt(bitsize=self.target_bitsize)),) def decompose_from_registers( @@ -149,7 +150,7 @@ def decompose_from_registers( op = op.controlled_by(*quregs['control'], control_values=[self.control_val]) yield op - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv return get_ctrl_system_1bit_cv( diff --git a/qualtran/bloqs/for_testing/with_decomposition.py b/qualtran/bloqs/for_testing/with_decomposition.py index 9a790ef29c..d581e44017 100644 --- a/qualtran/bloqs/for_testing/with_decomposition.py +++ b/qualtran/bloqs/for_testing/with_decomposition.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING from attrs import frozen @@ -32,7 +32,7 @@ class TestSerialCombo(Bloq): def signature(self) -> Signature: return Signature.build(reg=1) - def build_composite_bloq(self, bb: 'BloqBuilder', reg: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', reg: 'SoquetT') -> dict[str, 'SoquetT']: for i in range(3): reg = bb.add(TestAtom(tag=f'atom{i}'), q=reg) return {'reg': reg} @@ -46,7 +46,7 @@ class TestParallelCombo(Bloq): def signature(self) -> Signature: return Signature.build(reg=3) - def build_composite_bloq(self, bb: 'BloqBuilder', reg: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', reg: 'SoquetT') -> dict[str, 'SoquetT']: assert isinstance(reg, Soquet) reg = bb.split(reg) for i in range(len(reg)): @@ -63,7 +63,7 @@ class TestIndependentParallelCombo(Bloq): def signature(self) -> Signature: return Signature.build() - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: for _ in range(3): reg = bb.allocate(1) reg = bb.add(TestAtom(), q=reg) diff --git a/qualtran/bloqs/gf_arithmetic/gf2_add_k.py b/qualtran/bloqs/gf_arithmetic/gf2_add_k.py index 41e380ea8b..b2c90b515e 100644 --- a/qualtran/bloqs/gf_arithmetic/gf2_add_k.py +++ b/qualtran/bloqs/gf_arithmetic/gf2_add_k.py @@ -11,8 +11,9 @@ # 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 collections.abc import Sequence from functools import cached_property -from typing import Dict, Sequence, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs @@ -66,7 +67,7 @@ def _bits_k(self) -> Sequence[int]: def is_symbolic(self): return is_symbolic(self.k, self.bitsize) - def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> Dict[str, 'Soquet']: + def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> dict[str, 'Soquet']: if self.is_symbolic(): raise DecomposeTypeError(f"Cannot decompose symbolic {self}") xs = bb.split(x) @@ -83,7 +84,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': num_flips = self.bitsize if self.is_symbolic() else sum(self._bits_k) return {XGate(): num_flips} - def on_classical_vals(self, *, x) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, x) -> dict[str, 'ClassicalValT']: assert isinstance(x, self.qgf.gf_type) return {'x': x + self.qgf.gf_type(self.k)} diff --git a/qualtran/bloqs/gf_arithmetic/gf2_addition.py b/qualtran/bloqs/gf_arithmetic/gf2_addition.py index e316e0c582..b42785359b 100644 --- a/qualtran/bloqs/gf_arithmetic/gf2_addition.py +++ b/qualtran/bloqs/gf_arithmetic/gf2_addition.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Set, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import attrs @@ -59,7 +59,7 @@ def qgf(self) -> QGF: def build_composite_bloq( self, bb: 'BloqBuilder', *, x: 'Soquet', y: 'Soquet' - ) -> Dict[str, 'Soquet']: + ) -> dict[str, 'Soquet']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose symbolic {self}") x, y = bb.split(x), bb.split(y) @@ -71,10 +71,10 @@ def build_composite_bloq( def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: return {CNOT(): self.bitsize} - def on_classical_vals(self, *, x, y) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, x, y) -> dict[str, 'ClassicalValT']: assert isinstance(x, self.qgf.gf_type) and isinstance(y, self.qgf.gf_type) return {'x': x, 'y': x + y} diff --git a/qualtran/bloqs/gf_arithmetic/gf2_inverse.py b/qualtran/bloqs/gf_arithmetic/gf2_inverse.py index e792dacbe8..27eaade3f5 100644 --- a/qualtran/bloqs/gf_arithmetic/gf2_inverse.py +++ b/qualtran/bloqs/gf_arithmetic/gf2_inverse.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Set, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import attrs import numpy as np @@ -129,7 +129,7 @@ def my_static_costs(self, cost_key: 'CostKey'): return NotImplemented - def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose symbolic {self}") @@ -172,7 +172,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> Dict[str, ' def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if not is_symbolic(self.bitsize) and self.bitsize == 1: return {GF2Addition(self.bitsize): 1} square_count = self.bitsize + 2 ** ceil(log2(self.bitsize)) - 1 @@ -187,7 +187,7 @@ def build_call_graph( - 1, } - def on_classical_vals(self, *, x) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, x) -> dict[str, 'ClassicalValT']: assert isinstance(x, self.qgf.gf_type) junk = [] bitsize_minus_one = int(self.bitsize - 1) diff --git a/qualtran/bloqs/gf_arithmetic/gf2_multiplication.py b/qualtran/bloqs/gf_arithmetic/gf2_multiplication.py index 80c2f87450..8d32b68b16 100644 --- a/qualtran/bloqs/gf_arithmetic/gf2_multiplication.py +++ b/qualtran/bloqs/gf_arithmetic/gf2_multiplication.py @@ -11,8 +11,9 @@ # 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 collections.abc import Sequence from functools import cached_property -from typing import Dict, Optional, Sequence, Set, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import attrs import galois @@ -72,7 +73,7 @@ def signature(self) -> 'Signature': n, _ = self.matrix.shape return Signature([Register('q', QBit(), shape=(n,))]) - def on_classical_vals(self, *, q: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, q: 'ClassicalValT') -> dict[str, 'ClassicalValT']: if is_symbolic(self.matrix): raise ValueError(f"Cannot do classical simulation on symbolic {self}") matrix = GF(2)(self.matrix.astype(int)) @@ -87,7 +88,7 @@ def on_classical_vals(self, *, q: 'ClassicalValT') -> Dict[str, 'ClassicalValT'] def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: n = self.matrix.shape[0] return {CNOT(): ceil(n**2 / log2(n))} @@ -180,7 +181,7 @@ def synthesize_reduction_matrix_q(self) -> SynthesizeLRCircuit: else SynthesizeLRCircuit(self.reduction_matrix_q) ) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'Soquet') -> Dict[str, 'Soquet']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'Soquet') -> dict[str, 'Soquet']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose symbolic {self}") x, y = soqs['x'], soqs['y'] @@ -219,14 +220,14 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'Soquet') -> Dict[str, def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: m = self.bitsize plus_equal_prod = ( {self.synthesize_reduction_matrix_q.adjoint(): 1} if self.plus_equal_prod else {} ) return {Toffoli(): m**2, self.synthesize_reduction_matrix_q: 1} | plus_equal_prod - def on_classical_vals(self, **vals) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, **vals) -> dict[str, 'ClassicalValT']: assert all(isinstance(val, self.qgf.gf_type) for val in vals.values()) x, y = vals['x'], vals['y'] result = vals['result'] if self.plus_equal_prod else self.qgf.gf_type(0) @@ -327,10 +328,10 @@ def signature(self) -> 'Signature': def _const(self) -> galois.FieldArray: return self.galois_field(self.const) - def on_classical_vals(self, g) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, g) -> dict[str, 'ClassicalValT']: return {'g': g * self._const} - def build_composite_bloq(self, bb: 'BloqBuilder', g: 'Soquet') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', g: 'Soquet') -> dict[str, 'SoquetT']: L, U, P = self.lup if is_symbolic(self.n): raise DecomposeTypeError(f"Symbolic decomposition isn't supported for {self}") @@ -359,7 +360,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', g: 'Soquet') -> Dict[str, 'Soq def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: L, U, _ = self.lup # The number of cnots is the number of non zero off-diagnoal entries in L and U. cnots = np.sum(L) + np.sum(U) - 2 * self.n @@ -446,7 +447,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, f: 'ClassicalValT', g: 'ClassicalValT', h: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if is_symbolic(self.k): raise TypeError(f'classical action is not supported for {self=}') assert isinstance(f, np.ndarray) @@ -464,7 +465,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', f: 'SoquetT', g: 'SoquetT', h: 'SoquetT' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: n = self.n k = self.k l = self.l @@ -499,7 +500,7 @@ def build_composite_bloq( def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if not is_symbolic(self.n) and self.n == 1: return {CNOT(): 2, Toffoli(): 1} return {CNOT(): 2 * (self.l + self.k), BinaryPolynomialMultiplication(self.n): 1} @@ -557,7 +558,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, f: 'ClassicalValT', g: 'ClassicalValT', h: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: assert isinstance(f, np.ndarray) assert isinstance(g, np.ndarray) assert isinstance(h, np.ndarray) @@ -578,7 +579,7 @@ def k(self) -> 'SymbolicInt': def build_composite_bloq( self, bb: 'BloqBuilder', f: 'SoquetT', g: 'SoquetT', h: 'SoquetT' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: k, n = self.k, self.n if is_symbolic(n) or is_symbolic(k): raise DecomposeTypeError(f"symbolic decomposition is not supported for {self}") @@ -628,7 +629,7 @@ def build_composite_bloq( def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if not is_symbolic(self.n) and self.n == 1: return {Toffoli(): 1} if not is_symbolic(self.n) and 2 * self.k == self.n: @@ -712,7 +713,7 @@ def gf(self): def _power_2(self): return self.gf(2) ** self.k - def on_classical_vals(self, f: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, f: 'ClassicalValT') -> dict[str, 'ClassicalValT']: k = self.k if is_symbolic(k): raise TypeError(f'classical action is not supported for {self}') @@ -721,7 +722,7 @@ def on_classical_vals(self, f: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: return {'f': f} return {'f': f * self._power_2} - def build_composite_bloq(self, bb: 'BloqBuilder', f: 'Soquet') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', f: 'Soquet') -> dict[str, 'SoquetT']: if is_symbolic(self.k): raise DecomposeTypeError(f'symbolic decomposition is not supported for {self}') f_arr = bb.split(f)[::-1] @@ -736,7 +737,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', f: 'Soquet') -> Dict[str, 'Soq def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if self.k == 0 or self.n == 1: return {} return {CNOT(): max(len(self.degrees) - 2, 0) * self.k} @@ -785,7 +786,7 @@ def m_x(self): def build_composite_bloq( self, bb: 'BloqBuilder', f: 'Soquet', g: 'Soquet', h: 'Soquet' - ) -> Dict[str, 'Soquet']: + ) -> dict[str, 'Soquet']: if is_symbolic(self.k, self.n): raise DecomposeTypeError(f"Symbolic Decomposition is not supported for {self}") @@ -925,7 +926,7 @@ def _GF2MulViaKaratsubamod_impl(self) -> Bloq: def build_composite_bloq( self, bb: 'BloqBuilder', x: 'Soquet', y: 'Soquet', **soqs: 'SoquetT' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.k, self.n): raise DecomposeTypeError(f"Symbolic Decomposition is not supported for {self}") @@ -944,7 +945,7 @@ def build_composite_bloq( def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if self.n == 1: return {Toffoli(): 1} if not is_symbolic(self.n) and 2 * self.k == self.n: @@ -966,7 +967,7 @@ def build_call_graph( def on_classical_vals( self, x: 'SymbolicInt', y: 'SymbolicInt', result: Optional['SymbolicInt'] = None - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: assert isinstance(x, self.gf) assert isinstance(y, self.gf) if self.uncompute: diff --git a/qualtran/bloqs/gf_arithmetic/gf2_square.py b/qualtran/bloqs/gf_arithmetic/gf2_square.py index 140895e923..fb778d9c8c 100644 --- a/qualtran/bloqs/gf_arithmetic/gf2_square.py +++ b/qualtran/bloqs/gf_arithmetic/gf2_square.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Set, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import attrs import numpy as np @@ -89,7 +89,7 @@ def synthesize_squaring_matrix(self) -> SynthesizeLRCircuit: else SynthesizeLRCircuit(self.squaring_matrix) ) - def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> Dict[str, 'Soquet']: + def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> dict[str, 'Soquet']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose symbolic {self}") x = bb.split(x)[::-1] @@ -99,10 +99,10 @@ def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> Dict[str, ' def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: return {self.synthesize_squaring_matrix: 1} - def on_classical_vals(self, *, x) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, x) -> dict[str, 'ClassicalValT']: assert isinstance(x, self.qgf.gf_type) return {'x': x**2} diff --git a/qualtran/bloqs/gf_poly_arithmetic/gf2_poly_add.py b/qualtran/bloqs/gf_poly_arithmetic/gf2_poly_add.py index 7f8d8a351a..c8c83395eb 100644 --- a/qualtran/bloqs/gf_poly_arithmetic/gf2_poly_add.py +++ b/qualtran/bloqs/gf_poly_arithmetic/gf2_poly_add.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Set, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import attrs @@ -71,7 +71,7 @@ def is_symbolic(self): def build_composite_bloq( self, bb: 'BloqBuilder', *, f_x: 'Soquet', g_x: 'Soquet' - ) -> Dict[str, 'Soquet']: + ) -> dict[str, 'Soquet']: if self.is_symbolic(): raise DecomposeTypeError(f"Cannot decompose symbolic {self}") f_x = bb.add(GFPolySplit(self.qgf_poly), reg=f_x) @@ -85,10 +85,10 @@ def build_composite_bloq( def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: return {GF2Addition(self.qgf_poly.qgf.bitsize): self.qgf_poly.degree + 1} - def on_classical_vals(self, *, f_x, g_x) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, f_x, g_x) -> dict[str, 'ClassicalValT']: return {'f_x': f_x, 'g_x': f_x + g_x} diff --git a/qualtran/bloqs/gf_poly_arithmetic/gf2_poly_add_k.py b/qualtran/bloqs/gf_poly_arithmetic/gf2_poly_add_k.py index b8d6f8c52c..4e239db8ec 100644 --- a/qualtran/bloqs/gf_poly_arithmetic/gf2_poly_add_k.py +++ b/qualtran/bloqs/gf_poly_arithmetic/gf2_poly_add_k.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Set, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import attrs import galois @@ -81,7 +81,7 @@ def _validate_g_x(self, attribute, value): def is_symbolic(self): return is_symbolic(self.qgf_poly.degree) - def build_composite_bloq(self, bb: 'BloqBuilder', *, f_x: 'Soquet') -> Dict[str, 'Soquet']: + def build_composite_bloq(self, bb: 'BloqBuilder', *, f_x: 'Soquet') -> dict[str, 'Soquet']: if self.is_symbolic(): raise DecomposeTypeError(f"Cannot decompose symbolic {self}") f_x = bb.add(GFPolySplit(self.qgf_poly), reg=f_x) @@ -94,13 +94,13 @@ def build_composite_bloq(self, bb: 'BloqBuilder', *, f_x: 'Soquet') -> Dict[str, def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if self.is_symbolic(): k = ssa.new_symbol('g_x') return {GF2AddK(self.qgf_poly.qgf.bitsize, k): self.qgf_poly.degree + 1} return super().build_call_graph(ssa) - def on_classical_vals(self, *, f_x) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, *, f_x) -> dict[str, 'ClassicalValT']: return {'f_x': f_x + self.g_x} diff --git a/qualtran/bloqs/gf_poly_arithmetic/gf_poly_split_and_join.py b/qualtran/bloqs/gf_poly_arithmetic/gf_poly_split_and_join.py index 966e38d607..08f4bd2dc6 100644 --- a/qualtran/bloqs/gf_poly_arithmetic/gf_poly_split_and_join.py +++ b/qualtran/bloqs/gf_poly_arithmetic/gf_poly_split_and_join.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import cast, Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import cast, Optional, TYPE_CHECKING import galois import numpy as np @@ -96,7 +96,7 @@ def decompose_bloq(self) -> 'CompositeBloq': def adjoint(self) -> 'Bloq': return GFPolyJoin(dtype=self.dtype) - def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> Tuple[None, Dict[str, 'CirqQuregT']]: + def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> tuple[None, dict[str, 'CirqQuregT']]: return None, { 'reg': reg.reshape((int(self.dtype.degree) + 1, int(self.dtype.qgf.num_qubits))) } @@ -104,12 +104,12 @@ def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> Tuple[None, Dict[str, def as_pl_op(self, wires: 'Wires') -> 'Operation': return None - def on_classical_vals(self, reg: galois.Poly) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, reg: galois.Poly) -> dict[str, 'ClassicalValT']: return {'reg': self.dtype.to_gf_coefficients(reg)} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn incoming = incoming['reg'] @@ -127,7 +127,7 @@ def my_tensors( for i in range(int(self.dtype.num_qubits)) ] - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.shape: @@ -203,15 +203,15 @@ def decompose_bloq(self) -> 'CompositeBloq': def adjoint(self) -> 'Bloq': return GFPolySplit(dtype=self.dtype) - def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> Tuple[None, Dict[str, 'CirqQuregT']]: + def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> tuple[None, dict[str, 'CirqQuregT']]: return None, {'reg': reg.reshape(int(self.dtype.num_qubits))} def as_pl_op(self, wires: 'Wires') -> 'Operation': return None def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn incoming = cast(NDArray, incoming['reg']) @@ -230,10 +230,10 @@ def my_tensors( for i in range(int(self.dtype.num_qubits)) ] - def on_classical_vals(self, reg: 'galois.Array') -> Dict[str, galois.Poly]: + def on_classical_vals(self, reg: 'galois.Array') -> dict[str, galois.Poly]: return {'reg': self.dtype.from_gf_coefficients(reg)} - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.shape: diff --git a/qualtran/bloqs/hamiltonian_simulation/hamiltonian_simulation_by_gqsp.py b/qualtran/bloqs/hamiltonian_simulation/hamiltonian_simulation_by_gqsp.py index 21c3ee41f1..84821414d8 100644 --- a/qualtran/bloqs/hamiltonian_simulation/hamiltonian_simulation_by_gqsp.py +++ b/qualtran/bloqs/hamiltonian_simulation/hamiltonian_simulation_by_gqsp.py @@ -13,7 +13,7 @@ # limitations under the License. from collections import Counter from functools import cached_property -from typing import cast, Dict, Tuple, TYPE_CHECKING, Union +from typing import cast, TYPE_CHECKING, Union import numpy as np from attrs import field, frozen @@ -145,11 +145,11 @@ def signature(self) -> 'Signature': def __add_prepare( self, bb: 'BloqBuilder', - gqsp_soqs: Dict[str, 'SoquetT'], - state_prep_ancilla_soqs: Dict[str, 'SoquetT'], + gqsp_soqs: dict[str, 'SoquetT'], + state_prep_ancilla_soqs: dict[str, 'SoquetT'], *, adjoint: bool = False, - ) -> Tuple[Dict[str, 'SoquetT'], Dict[str, 'SoquetT']]: + ) -> tuple[dict[str, 'SoquetT'], dict[str, 'SoquetT']]: prepare = self.walk_operator.prepare selection_registers = {reg.name: gqsp_soqs[reg.name] for reg in prepare.selection_registers} @@ -163,8 +163,8 @@ def __add_prepare( } return gqsp_soqs, prepare_out_soqs - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: - state_prep_ancilla: Dict[str, 'SoquetT'] = { + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: + state_prep_ancilla: dict[str, 'SoquetT'] = { reg.name: bb.allocate(reg.total_bits()) for reg in self.walk_operator.prepare.junk_registers } diff --git a/qualtran/bloqs/mcmt/and_bloq.py b/qualtran/bloqs/mcmt/and_bloq.py index 486bb3e49b..0d1fdba2bf 100644 --- a/qualtran/bloqs/mcmt/and_bloq.py +++ b/qualtran/bloqs/mcmt/and_bloq.py @@ -22,8 +22,9 @@ to the and of its control registers. `And` will output the result into a fresh register. """ import itertools +from collections.abc import Iterable, Iterator from functools import cached_property -from typing import cast, Dict, Iterable, Iterator, List, Optional, Tuple, TYPE_CHECKING, Union +from typing import cast, Optional, TYPE_CHECKING, Union import attrs import cirq @@ -97,7 +98,7 @@ def decompose_bloq(self) -> 'CompositeBloq': def on_classical_vals( self, *, ctrl: NDArray[np.uint8], target: Optional[int] = None - ) -> Dict[str, ClassicalValT]: + ) -> dict[str, ClassicalValT]: out = 1 if tuple(ctrl) == (self.cv1, self.cv2) else 0 if not self.uncompute: return {'ctrl': ctrl, 'target': out} @@ -107,8 +108,8 @@ def on_classical_vals( return {'ctrl': ctrl} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn # Fill in our tensor using "and" logic. @@ -138,7 +139,7 @@ def my_tensors( ) ] - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'target': @@ -237,7 +238,7 @@ def _and_bloq() -> And: def _to_tuple_or_has_length( x: Union[HasLength, Iterable[SymbolicInt]] -) -> Union[HasLength, Tuple[SymbolicInt, ...]]: +) -> Union[HasLength, tuple[SymbolicInt, ...]]: if isinstance(x, HasLength): if is_symbolic(x.n): return x @@ -262,7 +263,7 @@ class MultiAnd(Bloq): target [right]: The output bit. """ - cvs: Union[HasLength, Tuple[SymbolicInt, ...]] = field(converter=_to_tuple_or_has_length) + cvs: Union[HasLength, tuple[SymbolicInt, ...]] = field(converter=_to_tuple_or_has_length) @cvs.validator def _validate_cvs(self, field, val): @@ -274,7 +275,7 @@ def n_ctrls(self) -> SymbolicInt: return self.cvs.n if isinstance(self.cvs, HasLength) else len(self.cvs) @property - def concrete_cvs(self) -> Tuple[SymbolicInt, ...]: + def concrete_cvs(self) -> tuple[SymbolicInt, ...]: if isinstance(self.cvs, HasLength): raise ValueError(f"{self.cvs} is symbolic") return self.cvs @@ -289,7 +290,7 @@ def signature(self) -> Signature: ] ) - def on_classical_vals(self, ctrl: NDArray[np.uint8]) -> Dict[str, NDArray[np.uint8]]: + def on_classical_vals(self, ctrl: NDArray[np.uint8]) -> dict[str, NDArray[np.uint8]]: accumulate_and = np.bitwise_and.accumulate( np.equal(ctrl, np.asarray(self.cvs)).astype(np.uint8) ) @@ -306,7 +307,7 @@ def __pow__(self, power: int) -> "Bloq": def _decompose_via_tree( self, controls: NDArray[cirq.Qid], - control_values: Tuple[SymbolicInt, ...], + control_values: tuple[SymbolicInt, ...], ancillas: NDArray[cirq.Qid], target: cirq.Qid, ) -> cirq.ops.op_tree.OpTree: @@ -335,7 +336,7 @@ def decompose_from_registers( def decompose_bloq(self) -> 'CompositeBloq': return decompose_from_cirq_style_method(self) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('') if reg.name == 'ctrl': diff --git a/qualtran/bloqs/mcmt/and_bloq_test.py b/qualtran/bloqs/mcmt/and_bloq_test.py index 70d853579f..1d5e385abc 100644 --- a/qualtran/bloqs/mcmt/and_bloq_test.py +++ b/qualtran/bloqs/mcmt/and_bloq_test.py @@ -14,7 +14,6 @@ import itertools from functools import cached_property -from typing import Dict import cirq import numpy as np @@ -196,7 +195,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', q0: 'SoquetT', q1: 'SoquetT' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: assert isinstance(q0, Soquet) assert isinstance(q1, Soquet) qs, trg = bb.add(And(), ctrl=[q0, q1]) diff --git a/qualtran/bloqs/mcmt/controlled_via_and.py b/qualtran/bloqs/mcmt/controlled_via_and.py index 3947ddf86b..00f0357d05 100644 --- a/qualtran/bloqs/mcmt/controlled_via_and.py +++ b/qualtran/bloqs/mcmt/controlled_via_and.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. from collections import Counter +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Iterable, Sequence, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np from attrs import frozen @@ -66,7 +67,7 @@ def __attrs_post_init__(self): @classmethod def make_ctrl_system( cls, bloq: 'Bloq', ctrl_spec: 'CtrlSpec' - ) -> Tuple['_ControlledBase', 'AddControlledT']: + ) -> tuple['_ControlledBase', 'AddControlledT']: """A factory method for creating both the Controlled and the adder function. See `Bloq.get_ctrl_system`. diff --git a/qualtran/bloqs/mcmt/multi_control_pauli.py b/qualtran/bloqs/mcmt/multi_control_pauli.py index aceff0c99d..89a8865c28 100644 --- a/qualtran/bloqs/mcmt/multi_control_pauli.py +++ b/qualtran/bloqs/mcmt/multi_control_pauli.py @@ -13,7 +13,7 @@ # limitations under the License. import warnings from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import numpy as np import sympy @@ -61,7 +61,7 @@ class MultiControlPauli(GateWithRegisters): [Constructing Large Controlled Nots](https://algassert.com/circuits/2015/06/05/Constructing-Large-Controlled-Nots.html) """ - cvs: Union[HasLength, Tuple[int, ...]] = field(converter=_to_tuple_or_has_length) + cvs: Union[HasLength, tuple[int, ...]] = field(converter=_to_tuple_or_has_length) target_bloq: Bloq def __attrs_post_init__(self): @@ -86,7 +86,7 @@ def n_ctrls(self) -> SymbolicInt: return slen(self.cvs) @property - def concrete_cvs(self) -> Tuple[int, ...]: + def concrete_cvs(self) -> tuple[int, ...]: if isinstance(self.cvs, HasLength): raise ValueError(f"{self.cvs} is symbolic") return self.cvs @@ -99,7 +99,7 @@ def _multi_ctrl_bloq(self) -> ControlledViaAnd: ctrl_spec = CtrlSpec(cvs=(cvs,)) return ControlledViaAnd(self.target_bloq, ctrl_spec) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: if is_symbolic(self.cvs): raise DecomposeTypeError(f"cannot decompose {self} with symbolic {self.cvs=}") @@ -127,7 +127,7 @@ def __str__(self) -> str: ctrl = f'C^{n}' if is_symbolic(n) or n > 2 else ['', 'C', 'CC'][int(n)] return f'{ctrl}{self.target_bloq!s}' - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return TextBox(str(self)) if reg.name == 'target': diff --git a/qualtran/bloqs/mcmt/multi_target_cnot.py b/qualtran/bloqs/mcmt/multi_target_cnot.py index c4df15202f..72e1a9d3a7 100644 --- a/qualtran/bloqs/mcmt/multi_target_cnot.py +++ b/qualtran/bloqs/mcmt/multi_target_cnot.py @@ -11,8 +11,8 @@ # 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 collections.abc import Iterator from functools import cached_property -from typing import Dict, Iterator import cirq import sympy @@ -67,7 +67,7 @@ def _circuit_diagram_info_(self, _) -> cirq.CircuitDiagramInfo: def on_classical_vals( self, control: 'ClassicalValT', targets: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if control: targets = (2**self.bitsize - 1) ^ targets return {'control': control, 'targets': targets} diff --git a/qualtran/bloqs/mcmt/specialized_ctrl.py b/qualtran/bloqs/mcmt/specialized_ctrl.py index 98b6499501..a8f25e3cc9 100644 --- a/qualtran/bloqs/mcmt/specialized_ctrl.py +++ b/qualtran/bloqs/mcmt/specialized_ctrl.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. import enum +from collections.abc import Callable, Iterable, Sequence from functools import cached_property -from typing import Callable, cast, Iterable, Optional, Sequence, TYPE_CHECKING +from typing import cast, Optional, TYPE_CHECKING import attrs import numpy as np diff --git a/qualtran/bloqs/mcmt/specialized_ctrl_test.py b/qualtran/bloqs/mcmt/specialized_ctrl_test.py index 8ed8dd515d..86bfdf885e 100644 --- a/qualtran/bloqs/mcmt/specialized_ctrl_test.py +++ b/qualtran/bloqs/mcmt/specialized_ctrl_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import itertools -from typing import Optional, Sequence, Tuple +from typing import Optional, Sequence from unittest.mock import ANY import attrs @@ -52,7 +52,7 @@ def signature(self) -> 'Signature': reg_name_map = {self.ctrl_reg_name: n_ctrl, self.target_reg_name: 2} return Signature.build(**reg_name_map) - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: return get_ctrl_system_1bit_cv( self, ctrl_spec, @@ -130,7 +130,7 @@ class TestAtom(Bloq): def signature(self) -> 'Signature': return Signature.build(q=2) - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: return get_ctrl_system_1bit_cv_from_bloqs( self, ctrl_spec, @@ -151,7 +151,7 @@ class CTestAtom(Bloq): def signature(self) -> 'Signature': return Signature.build(ctrl=1, q=2) - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: return get_ctrl_system_1bit_cv_from_bloqs( self, ctrl_spec, current_ctrl_bit=1, bloq_with_ctrl=self, ctrl_reg_name='ctrl' ) diff --git a/qualtran/bloqs/mean_estimation/complex_phase_oracle.py b/qualtran/bloqs/mean_estimation/complex_phase_oracle.py index 6abd4c2811..91a325d16d 100644 --- a/qualtran/bloqs/mean_estimation/complex_phase_oracle.py +++ b/qualtran/bloqs/mean_estimation/complex_phase_oracle.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator from functools import cached_property -from typing import Iterator, Tuple import attrs import cirq @@ -40,11 +40,11 @@ class ComplexPhaseOracle(GateWithRegisters): arctan_bitsize: int = 32 @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return self.encoder.control_registers @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.encoder.selection_registers @cached_property diff --git a/qualtran/bloqs/mean_estimation/complex_phase_oracle_test.py b/qualtran/bloqs/mean_estimation/complex_phase_oracle_test.py index ab6dc2af63..00b48776e1 100644 --- a/qualtran/bloqs/mean_estimation/complex_phase_oracle_test.py +++ b/qualtran/bloqs/mean_estimation/complex_phase_oracle_test.py @@ -14,7 +14,7 @@ import math from functools import cached_property -from typing import Optional, Tuple +from typing import Optional import cirq import numpy as np @@ -34,15 +34,15 @@ class ExampleSelect(SelectOracle): control_val: Optional[int] = None @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('control', QBit()),) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('selection', QAny(self.bitsize)),) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register('target', QAny(self.bitsize)),) def decompose_from_registers(self, context, selection, target): diff --git a/qualtran/bloqs/mean_estimation/mean_estimation_operator.py b/qualtran/bloqs/mean_estimation/mean_estimation_operator.py index 1e5b5d7db7..767a03a651 100644 --- a/qualtran/bloqs/mean_estimation/mean_estimation_operator.py +++ b/qualtran/bloqs/mean_estimation/mean_estimation_operator.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator from functools import cached_property -from typing import Iterator, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs from numpy.typing import NDArray @@ -95,7 +96,7 @@ def select(self) -> ComplexPhaseOracle: return ComplexPhaseOracle(self.code.encoder, self.arctan_bitsize) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.code.encoder.selection_registers @cached_property diff --git a/qualtran/bloqs/mean_estimation/mean_estimation_operator_test.py b/qualtran/bloqs/mean_estimation/mean_estimation_operator_test.py index bbc6d9ff32..ec4f06b441 100644 --- a/qualtran/bloqs/mean_estimation/mean_estimation_operator_test.py +++ b/qualtran/bloqs/mean_estimation/mean_estimation_operator_test.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator, Sequence from functools import cached_property -from typing import Iterator, Optional, Sequence, Tuple +from typing import Optional import cirq import numpy as np @@ -39,7 +40,7 @@ class BernoulliSynthesizer(PrepareOracle): nqubits: int @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('q', BQUInt(self.nqubits, 2)),) def decompose_from_registers( # type:ignore[override] @@ -55,21 +56,21 @@ class BernoulliEncoder(SelectOracle): r"""Encodes Bernoulli random variable y0/y1 as $Enc|ii..i>|0> = |ii..i>|y_{i}>$ where i=0/1.""" p: float - y: Tuple[int, int] + y: tuple[int, int] selection_bitsize: int target_bitsize: int control_val: Optional[int] = None @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('q', BQUInt(self.selection_bitsize, 2)),) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register('t', QAny(self.target_bitsize)),) def decompose_from_registers( # type:ignore[override] @@ -179,7 +180,7 @@ class GroverSynthesizer(PrepareOracle): n: int @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('selection', QAny(self.n)),) def decompose_from_registers( # type:ignore[override] @@ -202,15 +203,15 @@ class GroverEncoder(SelectOracle): marked_val: int @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('selection', QAny(self.n)),) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register('target', QAny(self.marked_val.bit_length())),) def decompose_from_registers( # type:ignore[override] diff --git a/qualtran/bloqs/mod_arithmetic/mod_addition.py b/qualtran/bloqs/mod_arithmetic/mod_addition.py index 0a167e84fe..2b6e166285 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_addition.py +++ b/qualtran/bloqs/mod_arithmetic/mod_addition.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import numpy as np import sympy @@ -86,7 +86,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: # The construction still works when at most one of inputs equals `mod`. special_case = (x == self.mod) ^ (y == self.mod) if not (0 <= x < self.mod or special_case): @@ -101,7 +101,7 @@ def on_classical_vals( y = (x + y) % self.mod return {'x': x, 'y': y} - def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet, y: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet, y: Soquet) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") # Allocate ancilla bits for use in addition. @@ -197,7 +197,7 @@ class ModAddK(GateWithRegisters): bitsize: int mod: int = field() add_val: int = 1 - cvs: Tuple[int, ...] = field( + cvs: tuple[int, ...] = field( converter=lambda v: (v,) if isinstance(v, int) else tuple(v), default=() ) @@ -226,7 +226,7 @@ def _classical_unctrled(self, target_val: int): def on_classical_vals( self, *, x: int, ctrl: Optional[int] = None - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: out = self._classical_unctrled(x) if self.cvs: assert ctrl is not None @@ -306,7 +306,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: 'Soquet', x: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: k = bb.add(IntState(bitsize=self.bitsize, val=self.k)) ctrl, k, x = bb.add(CModAdd(QUInt(self.bitsize), mod=self.mod), ctrl=ctrl, x=k, y=x) bb.add(IntEffect(bitsize=self.bitsize, val=self.k), val=k) @@ -314,7 +314,7 @@ def build_composite_bloq( def on_classical_vals( self, ctrl: 'ClassicalValT', x: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == 0: return {'ctrl': 0, 'x': x} @@ -332,7 +332,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {CModAdd(QUInt(self.bitsize), mod=self.mod): 1} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(f"mod {self.mod}") @@ -396,7 +396,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: 'Soquet', x: 'Soquet', y: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") x_split = bb.split(x) @@ -429,7 +429,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': def on_classical_vals( self, ctrl: 'ClassicalValT', x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == 0: return {'ctrl': 0, 'x': x, 'y': y} @@ -438,7 +438,7 @@ def on_classical_vals( return {'ctrl': ctrl, 'x': x, 'y': y_out} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(f"mod {self.mod}") @@ -506,7 +506,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, ctrl: 'ClassicalValT', x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl != self.cv: return {'ctrl': ctrl, 'x': x, 'y': y} @@ -526,7 +526,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', ctrl, x: Soquet, y: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.dtype.bitsize): raise DecomposeTypeError(f'symbolic decomposition is not supported for {self}') y_arr = bb.split(y) diff --git a/qualtran/bloqs/mod_arithmetic/mod_division.py b/qualtran/bloqs/mod_arithmetic/mod_division.py index 947f40eb5d..96ea3f4dce 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_division.py +++ b/qualtran/bloqs/mod_arithmetic/mod_division.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import cast, Dict, List, Optional, Tuple, TYPE_CHECKING, Union +from typing import cast, Optional, TYPE_CHECKING, Union import numpy as np import sympy @@ -68,7 +68,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, v: int, m: int, f: int, is_terminal: int - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: m ^= f & (v == 0) assert is_terminal == 0 is_terminal ^= m @@ -77,7 +77,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', v: Soquet, m: Soquet, f: Soquet, is_terminal: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f'symbolic decomposition is not supported for {self}') v_arr = bb.split(v) @@ -96,7 +96,7 @@ def build_composite_bloq( def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': if is_symbolic(self.bitsize): - cvs: Union[HasLength, List[int]] = HasLength(self.bitsize + 1) + cvs: Union[HasLength, list[int]] = HasLength(self.bitsize + 1) else: cvs = [0] * int(self.bitsize) + [1] return {MultiAnd(cvs=cvs): 1, MultiAnd(cvs=cvs).adjoint(): 1, CNOT(): 3} @@ -123,7 +123,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, u: int, v: int, b: int, a: int, m: int, f: int - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: a ^= ((u & 1) == 0) & f m ^= ((v & 1) == 0) & (a == 0) & f b ^= a @@ -132,7 +132,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', u: Soquet, v: Soquet, b: Soquet, a: Soquet, m: Soquet, f: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") @@ -186,7 +186,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, u: int, v: int, b: int, a: int, m: int, f: int - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: c = (u > v) & (b == 0) & f a ^= c m ^= c @@ -194,7 +194,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', u: Soquet, v: Soquet, b: Soquet, a: Soquet, m: Soquet, f: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: u, v, junk_c, greater_than = bb.add( LinearDepthHalfGreaterThan(QMontgomeryUInt(self.bitsize)), a=u, b=v ) @@ -248,7 +248,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, u: int, v: int, r: int, s: int, a: int - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if a: u, v = v, u r, s = s, r @@ -256,7 +256,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', u: Soquet, v: Soquet, r: Soquet, s: Soquet, a: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: a, u, v = bb.add(CSwap(self.bitsize), ctrl=a, x=u, y=v) a, r, s = bb.add(CSwap(self.bitsize), ctrl=a, x=r, y=s) return {'u': u, 'v': v, 'r': r, 's': s, 'a': a} @@ -286,7 +286,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, u: int, v: int, r: int, s: int, b: int, f: int - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if f and b == 0: v -= u s += r @@ -294,7 +294,7 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', u: Soquet, v: Soquet, r: Soquet, s: Soquet, b: Soquet, f: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: (f, b), c = bb.add(And(1, 0), ctrl=(f, b)) v = bb.add(BitwiseNot(QMontgomeryUInt(self.bitsize)), x=v) c, u, v = bb.add(CAdd(QMontgomeryUInt(self.bitsize)), ctrl=c, a=u, b=v) @@ -336,7 +336,7 @@ def signature(self) -> 'Signature': def on_classical_vals( self, u: int, v: int, r: int, s: int, b: int, a: int, m: int, f: int - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: b ^= m b ^= a if f: @@ -360,7 +360,7 @@ def build_composite_bloq( a: Soquet, m: Soquet, f: Soquet, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize, self.mod): raise DecomposeTypeError(f'symbolic decomposition is not supported for {self}') m, b = bb.add(CNOT(), ctrl=m, target=b) @@ -426,7 +426,7 @@ def build_composite_bloq( m: Soquet, f: Soquet, is_terminal: Soquet, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: a = bb.allocate(1) b = bb.allocate(1) @@ -463,7 +463,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': def on_classical_vals( self, u: int, v: int, r: int, s: int, m: int, f: int, is_terminal: int - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: """This is the Kaliski algorithm as described in Fig7 of https://arxiv.org/pdf/2001.09580. The following implementation merges together the pseudocode from Fig7 of https://arxiv.org/pdf/2001.09580 @@ -539,7 +539,7 @@ def build_composite_bloq( m: Soquet, f: Soquet, terminal_condition: Soquet, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") @@ -664,7 +664,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', x: Soquet, junk: Optional[Soquet] = None - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.bitsize): raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") @@ -679,7 +679,7 @@ def build_composite_bloq( m = bb.join(junk_arr[: 2 * self.bitsize]) terminal_condition = bb.join(junk_arr[2 * self.bitsize :]) u, x, r, s, m, f, terminal_condition = cast( - Tuple[Soquet, Soquet, Soquet, Soquet, Soquet, Soquet, Soquet], + tuple[Soquet, Soquet, Soquet, Soquet, Soquet, Soquet, Soquet], bb.add_from( _KaliskiModInverseImpl(self.bitsize, self.mod).adjoint(), u=u, @@ -702,7 +702,7 @@ def build_composite_bloq( m = bb.allocate(2 * self.bitsize) terminal_condition = bb.allocate(2 * self.bitsize) u, v, x, s, m, f, terminal_condition = cast( - Tuple[Soquet, Soquet, Soquet, Soquet, Soquet, Soquet, Soquet], + tuple[Soquet, Soquet, Soquet, Soquet, Soquet, Soquet, Soquet], bb.add_from( _KaliskiModInverseImpl(self.bitsize, self.mod), u=u, @@ -728,7 +728,7 @@ def adjoint(self) -> 'KaliskiModInverse': def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return _KaliskiModInverseImpl(self.bitsize, self.mod).build_call_graph(ssa) - def on_classical_vals(self, x: int, junk: int = 0) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, x: int, junk: int = 0) -> dict[str, 'ClassicalValT']: mod = int(self.mod) u, v, r, s, f = mod, x, 0, 1, 1 terminal_condition = m = 0 diff --git a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py index c0242f9735..7dadba1ed5 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py +++ b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py @@ -14,8 +14,9 @@ import math import numbers +from collections.abc import Sequence from functools import cached_property -from typing import cast, Dict, Optional, Sequence, Set, Tuple, TYPE_CHECKING, Union +from typing import cast, Optional, TYPE_CHECKING, Union import attrs import numpy as np @@ -86,12 +87,12 @@ def _validate_mod(self, attribute, value): def signature(self) -> 'Signature': return Signature([Register('x', self.dtype)]) - def on_classical_vals(self, x: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, x: 'ClassicalValT') -> dict[str, 'ClassicalValT']: if x < self.mod: x = (x + x) % self.mod return {'x': x} - def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> dict[str, 'SoquetT']: if is_symbolic(self.dtype.bitsize): raise DecomposeTypeError(f'symbolic decomposition is not supported for {self}') @@ -140,7 +141,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> Dict[str, 'Soque return {'x': x} def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text(f'x = 2 * x mod {self.mod}') @@ -207,7 +208,7 @@ def _Add(self, k: Union[int, sympy.Expr]): def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: 'SoquetT', x: 'SoquetT' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: k = self.k if isinstance(self.mod, sympy.Expr) or isinstance(k, sympy.Expr): neg_k_inv = sympy.Mod(sympy.Pow(k, -1), self.mod) @@ -235,12 +236,12 @@ def build_call_graph(self, ssa: SympySymbolAllocator) -> BloqCountDictT: k = ssa.new_symbol('k') return {self._Add(k=k): 2, CSwap(self.dtype.bitsize): 1} - def on_classical_vals(self, ctrl, x) -> Dict[str, ClassicalValT]: + def on_classical_vals(self, ctrl, x) -> dict[str, ClassicalValT]: if ctrl and x < self.mod: return {'ctrl': ctrl, 'x': (x * self.k) % self.mod} return {'ctrl': ctrl, 'x': x} - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text(f'x *= {self.k} % {self.mod}') if reg.name == 'ctrl': @@ -494,7 +495,7 @@ def build_composite_bloq( target: Soquet, qrom_indices: Soquet, reduced: Soquet, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if is_symbolic(self.window_size) or is_symbolic(self.bitsize) or is_symbolic(self.mod): raise DecomposeNotImplementedError(f'symbolic decomposition not supported for {self}') x_arr = bb.split(x) @@ -650,7 +651,7 @@ def on_classical_vals( target: Optional['ClassicalValT'] = None, qrom_indices: Optional['ClassicalValT'] = None, reduced: Optional['ClassicalValT'] = None, - ) -> Dict[str, ClassicalValT]: + ) -> dict[str, ClassicalValT]: if is_symbolic(self.bitsize) or is_symbolic(self.window_size) or is_symbolic(self.mod): raise ValueError(f'classical action is not supported for {self}') if self.uncompute: @@ -697,7 +698,7 @@ def build_composite_bloq( target: Optional[Soquet] = None, qrom_indices: Optional[Soquet] = None, reduced: Optional[Soquet] = None, - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if self.uncompute: assert target is not None assert qrom_indices is not None @@ -731,7 +732,7 @@ def build_composite_bloq( def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union[Set['BloqCountT'], BloqCountDictT]: + ) -> Union[set['BloqCountT'], BloqCountDictT]: return self._mod_mul_impl.build_call_graph(ssa) diff --git a/qualtran/bloqs/mod_arithmetic/mod_subtraction.py b/qualtran/bloqs/mod_arithmetic/mod_subtraction.py index e0d0fbf81a..7a3fae6100 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_subtraction.py +++ b/qualtran/bloqs/mod_arithmetic/mod_subtraction.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import sympy from attrs import frozen @@ -73,7 +73,7 @@ class ModNeg(Bloq): def signature(self) -> 'Signature': return Signature([Register('x', self.dtype)]) - def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet) -> dict[str, 'SoquetT']: if not isinstance(self.dtype.bitsize, int): raise DecomposeTypeError(f'symbolic decomposition is not supported for {self}') @@ -106,7 +106,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': } def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text("") @@ -114,7 +114,7 @@ def wire_symbol( return TextBox('$-x$') raise ValueError(f'Unrecognized register name {reg.name}') - def on_classical_vals(self, x: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, x: 'ClassicalValT') -> dict[str, 'ClassicalValT']: if 0 < x < self.mod: x = self.mod - x return {'x': x} @@ -153,7 +153,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: Soquet, x: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if not isinstance(self.dtype.bitsize, int): raise DecomposeTypeError(f'symbolic decomposition is not supported for {self}') @@ -199,7 +199,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': } def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text("") @@ -211,7 +211,7 @@ def wire_symbol( def on_classical_vals( self, ctrl: 'ClassicalValT', x: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == self.cv and 0 < x < self.mod: x = self.mod - x return {'ctrl': ctrl, 'x': x} @@ -265,7 +265,7 @@ class ModSub(Bloq): def signature(self) -> 'Signature': return Signature([Register('x', self.dtype), Register('y', self.dtype)]) - def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet, y: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: Soquet, y: Soquet) -> dict[str, 'SoquetT']: x = bb.add(BitwiseNot(self.dtype), x=x) x = bb.add(AddK(self.dtype, self.mod + 1), x=x) x, y = bb.add(ModAdd(self.dtype.bitsize, self.mod), x=x, y=y) @@ -282,7 +282,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': } def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text("") @@ -294,7 +294,7 @@ def wire_symbol( def on_classical_vals( self, x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if 0 <= x < self.mod and 0 <= y < self.mod: y -= x if y < 0: @@ -345,7 +345,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', ctrl: Soquet, x: Soquet, y: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: x = bb.add(BitwiseNot(self.dtype), x=x) x = bb.add(AddK(self.dtype, self.mod + 1), x=x) ctrl, x, y = bb.add(CModAdd(self.dtype, self.mod, self.cv), ctrl=ctrl, x=x, y=y) @@ -362,7 +362,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': } def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text("") @@ -376,7 +376,7 @@ def wire_symbol( def on_classical_vals( self, ctrl: 'ClassicalValT', x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == self.cv and 0 <= x < self.mod and 0 <= y < self.mod: y -= x if y < 0: diff --git a/qualtran/bloqs/multiplexers/apply_gate_to_lth_target.ipynb b/qualtran/bloqs/multiplexers/apply_gate_to_lth_target.ipynb index 7b733722e6..215fca97bc 100644 --- a/qualtran/bloqs/multiplexers/apply_gate_to_lth_target.ipynb +++ b/qualtran/bloqs/multiplexers/apply_gate_to_lth_target.ipynb @@ -70,7 +70,7 @@ "`selection`-th qubit of `target` all controlled by the `control` register.\n", "\n", "#### Parameters\n", - " - `selection_regs`: Indexing `select` signature of type Tuple[`Register`, ...]. It also contains information about the iteration length of each selection register.\n", + " - `selection_regs`: Indexing `select` signature of type tuple[`Register`, ...]. It also contains information about the iteration length of each selection register.\n", " - `nth_gate`: A function mapping the composite selection index to a single-qubit gate.\n", " - `control_regs`: Control signature for constructing a controlled version of the gate. \n", "\n", diff --git a/qualtran/bloqs/multiplexers/apply_gate_to_lth_target.py b/qualtran/bloqs/multiplexers/apply_gate_to_lth_target.py index 77f70157ce..d9476f1420 100644 --- a/qualtran/bloqs/multiplexers/apply_gate_to_lth_target.py +++ b/qualtran/bloqs/multiplexers/apply_gate_to_lth_target.py @@ -13,8 +13,8 @@ # limitations under the License. import itertools +from collections.abc import Callable, Sequence from functools import cached_property -from typing import Callable, Sequence, Tuple import attrs import cirq @@ -40,7 +40,7 @@ class ApplyGateToLthQubit(UnaryIterationGate): `selection`-th qubit of `target` all controlled by the `control` register. Args: - selection_regs: Indexing `select` signature of type Tuple[`Register`, ...]. + selection_regs: Indexing `select` signature of type tuple[`Register`, ...]. It also contains information about the iteration length of each selection register. nth_gate: A function mapping the composite selection index to a single-qubit gate. control_regs: Control signature for constructing a controlled version of the gate. @@ -50,11 +50,11 @@ class ApplyGateToLthQubit(UnaryIterationGate): Babbush et al. (2018). Section III.A. and Figure 7. """ - selection_regs: Tuple[Register, ...] = attrs.field( + selection_regs: tuple[Register, ...] = attrs.field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v) ) nth_gate: Callable[..., cirq.Gate] - control_regs: Tuple[Register, ...] = attrs.field( + control_regs: tuple[Register, ...] = attrs.field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v), default=(Register('control', QBit()),), ) @@ -71,15 +71,15 @@ def make_on( ).on_registers(**quregs) @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return self.control_regs @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.selection_regs @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: if any( isinstance(reg.dtype.iteration_length_or_zero(), sympy.Expr) for reg in self.selection_registers diff --git a/qualtran/bloqs/multiplexers/apply_lth_bloq.py b/qualtran/bloqs/multiplexers/apply_lth_bloq.py index 57ea79336c..5cf51dbd57 100644 --- a/qualtran/bloqs/multiplexers/apply_lth_bloq.py +++ b/qualtran/bloqs/multiplexers/apply_lth_bloq.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import cast, Iterable, Optional, Sequence, Set, Tuple, Union +from typing import cast, Optional, Union import cirq import numpy as np @@ -69,7 +70,7 @@ class ApplyLthBloq(UnaryIterationGate, SelectOracle): # type: ignore[misc] converter=lambda x: np.array(x) if isinstance(x, Iterable) else x, eq=lambda d: tuple(d.flat), ) - selection_regs: Optional[Tuple[Register, ...]] = None + selection_regs: Optional[tuple[Register, ...]] = None control_val: Optional[int] = None def __attrs_post_init__(self): @@ -81,11 +82,11 @@ def __attrs_post_init__(self): raise ValueError("All ops must have only THRU registers.") @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('control', QBit()),) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: if self.selection_regs is None: return tuple( Register( @@ -97,10 +98,10 @@ def selection_registers(self) -> Tuple[Register, ...]: return self.selection_regs @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return tuple(self.ops.flat[0].signature) # type: ignore - def nth_operation_callgraph(self, **kwargs: int) -> Set[BloqCountT]: + def nth_operation_callgraph(self, **kwargs: int) -> set[BloqCountT]: return {(self.ops[tuple(kwargs.values())].controlled(), 1)} def nth_operation( @@ -117,7 +118,7 @@ def nth_operation( target_qubits = merge_qubits(bloq.signature, **targets) return bloq.controlled().on(control, *target_qubits) - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv return get_ctrl_system_1bit_cv( diff --git a/qualtran/bloqs/multiplexers/black_box_select.py b/qualtran/bloqs/multiplexers/black_box_select.py index 8cb8d402b1..cb68d9af6e 100644 --- a/qualtran/bloqs/multiplexers/black_box_select.py +++ b/qualtran/bloqs/multiplexers/black_box_select.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Tuple from attr import frozen @@ -60,15 +59,15 @@ def __str__(self) -> str: return 'SELECT' @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register(name='selection', dtype=QAny(self.selection_bitsize)),) @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return self.select.control_registers @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register(name='system', dtype=QAny(self.system_bitsize)),) @cached_property @@ -83,7 +82,7 @@ def selection_bitsize(self) -> SymbolicInt: def system_bitsize(self) -> SymbolicInt: return ssum(r.total_bits() for r in self.select.target_registers) - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: partitions = ( (self.selection_registers[0], [r.name for r in self.select.selection_registers]), (self.target_registers[0], [r.name for r in self.select.target_registers]), diff --git a/qualtran/bloqs/multiplexers/black_box_select_test.py b/qualtran/bloqs/multiplexers/black_box_select_test.py index 6bd3dd68d3..97a90c0eea 100644 --- a/qualtran/bloqs/multiplexers/black_box_select_test.py +++ b/qualtran/bloqs/multiplexers/black_box_select_test.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Tuple - from attr import frozen from qualtran import QAny, QBit, Register @@ -28,15 +26,15 @@ def test_black_box_select(bloq_autotester): @frozen class TestSelectOracle(SelectOracle): @property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () @property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('z', QBit()),) @property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register('a', QAny(5)),) diff --git a/qualtran/bloqs/multiplexers/select_base.py b/qualtran/bloqs/multiplexers/select_base.py index dc72bbc1a4..fd621eca37 100644 --- a/qualtran/bloqs/multiplexers/select_base.py +++ b/qualtran/bloqs/multiplexers/select_base.py @@ -14,7 +14,6 @@ import abc from functools import cached_property -from typing import Tuple from qualtran import BloqDocSpec, GateWithRegisters, Register, Signature @@ -39,15 +38,15 @@ class SelectOracle(GateWithRegisters): @property @abc.abstractmethod - def control_registers(self) -> Tuple[Register, ...]: ... + def control_registers(self) -> tuple[Register, ...]: ... @property @abc.abstractmethod - def selection_registers(self) -> Tuple[Register, ...]: ... + def selection_registers(self) -> tuple[Register, ...]: ... @property @abc.abstractmethod - def target_registers(self) -> Tuple[Register, ...]: ... + def target_registers(self) -> tuple[Register, ...]: ... @cached_property def signature(self) -> Signature: diff --git a/qualtran/bloqs/multiplexers/select_pauli_lcu.py b/qualtran/bloqs/multiplexers/select_pauli_lcu.py index 41e2f8ddb3..be65d0a261 100644 --- a/qualtran/bloqs/multiplexers/select_pauli_lcu.py +++ b/qualtran/bloqs/multiplexers/select_pauli_lcu.py @@ -14,8 +14,9 @@ """Bloqs for applying SELECT unitary for LCU of Pauli Strings.""" +from collections.abc import Iterable, Iterator, Sequence from functools import cached_property -from typing import Iterable, Iterator, Optional, Sequence, Tuple +from typing import Optional import attrs import cirq @@ -71,7 +72,7 @@ class SelectPauliLCU(SelectOracle, UnaryIterationGate): # type: ignore[misc] selection_bitsize: int target_bitsize: int - select_unitaries: Tuple[cirq.DensePauliString, ...] = attrs.field(converter=_to_tuple) + select_unitaries: tuple[cirq.DensePauliString, ...] = attrs.field(converter=_to_tuple) control_val: Optional[int] = None def __attrs_post_init__(self): @@ -87,15 +88,15 @@ def __attrs_post_init__(self): ) @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('control', QBit()),) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('selection', BQUInt(self.selection_bitsize, len(self.select_unitaries))),) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register('target', QAny(self.target_bitsize)),) def decompose_from_registers( @@ -126,7 +127,7 @@ def nth_operation( # type: ignore[override] ps = self.select_unitaries[selection].on(*target) return ps.with_coefficient(np.sign(complex(ps.coefficient).real)).controlled_by(control) - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv return get_ctrl_system_1bit_cv( diff --git a/qualtran/bloqs/multiplexers/select_pauli_lcu_test.py b/qualtran/bloqs/multiplexers/select_pauli_lcu_test.py index c075593269..a50692086a 100644 --- a/qualtran/bloqs/multiplexers/select_pauli_lcu_test.py +++ b/qualtran/bloqs/multiplexers/select_pauli_lcu_test.py @@ -11,7 +11,7 @@ # 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 typing import Sequence +from collections.abc import Sequence import cirq import numpy as np diff --git a/qualtran/bloqs/multiplexers/selected_majorana_fermion.py b/qualtran/bloqs/multiplexers/selected_majorana_fermion.py index fd5a94952e..317c06a5a7 100644 --- a/qualtran/bloqs/multiplexers/selected_majorana_fermion.py +++ b/qualtran/bloqs/multiplexers/selected_majorana_fermion.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator, Sequence from functools import cached_property -from typing import Iterator, Sequence, Tuple, Union +from typing import Union import attrs import cirq @@ -47,10 +48,10 @@ class SelectedMajoranaFermion(UnaryIterationGate): Fig 9. """ - selection_regs: Tuple[Register, ...] = attrs.field( + selection_regs: tuple[Register, ...] = attrs.field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v) ) - control_regs: Tuple[Register, ...] = attrs.field( + control_regs: tuple[Register, ...] = attrs.field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v), default=(Register('control', QBit()),), ) @@ -72,15 +73,15 @@ def make_on( ).on_registers(**quregs) @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return self.control_regs @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.selection_regs @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: if any( isinstance(reg.dtype.iteration_length_or_zero(), sympy.Expr) for reg in self.selection_registers @@ -93,7 +94,7 @@ def target_registers(self) -> Tuple[Register, ...]: return (Register('target', QAny(int(total_iteration_size))),) @cached_property - def extra_registers(self) -> Tuple[Register, ...]: + def extra_registers(self) -> tuple[Register, ...]: return (Register('accumulator', QBit()),) def decompose_from_registers( diff --git a/qualtran/bloqs/multiplexers/unary_iteration_bloq.py b/qualtran/bloqs/multiplexers/unary_iteration_bloq.py index 1c75868a0f..787737a858 100644 --- a/qualtran/bloqs/multiplexers/unary_iteration_bloq.py +++ b/qualtran/bloqs/multiplexers/unary_iteration_bloq.py @@ -14,8 +14,9 @@ import abc from collections import defaultdict +from collections.abc import Callable, Iterator, Sequence from functools import cached_property -from typing import Callable, Dict, Iterator, List, Sequence, Set, Tuple, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import cirq import numpy as np @@ -35,7 +36,7 @@ def _unary_iteration_segtree( - ops: List[cirq.Operation], + ops: list[cirq.Operation], control: cirq.Qid, selection: Sequence[cirq.Qid], ancilla: Sequence[cirq.Qid], @@ -45,7 +46,7 @@ def _unary_iteration_segtree( l_iter: int, r_iter: int, break_early: Callable[[int, int], bool], -) -> Iterator[Tuple[cirq.OP_TREE, cirq.Qid, int]]: +) -> Iterator[tuple[cirq.OP_TREE, cirq.Qid, int]]: """Constructs a unary iteration circuit by iterating over nodes of an implicit Segment Tree. Args: @@ -71,7 +72,7 @@ def _unary_iteration_segtree( `(OP_TREE, control_qubit, l)` for all integers in the range `[l, r)`. Yields: - One `Tuple[cirq.OP_TREE, cirq.Qid, int]` for each leaf node in the segment tree. The i'th + One `tuple[cirq.OP_TREE, cirq.Qid, int]` for each leaf node in the segment tree. The i'th yielded element corresponds to the i'th leaf node which represents the `l_iter + i`'th integer. The tuple corresponds to: - cirq.OP_TREE: Operations to be inserted in the circuit in between the last leaf node @@ -116,13 +117,13 @@ def _unary_iteration_segtree( def _unary_iteration_zero_control( - ops: List[cirq.Operation], + ops: list[cirq.Operation], selection: Sequence[cirq.Qid], ancilla: Sequence[cirq.Qid], l_iter: int, r_iter: int, break_early: Callable[[int, int], bool], -) -> Iterator[Tuple[cirq.OP_TREE, cirq.Qid, int]]: +) -> Iterator[tuple[cirq.OP_TREE, cirq.Qid, int]]: sl, l, r = 0, 0, 2 ** len(selection) m = (l + r) >> 1 if r_iter <= m: @@ -141,14 +142,14 @@ def _unary_iteration_zero_control( def _unary_iteration_single_control( - ops: List[cirq.Operation], + ops: list[cirq.Operation], control: cirq.Qid, selection: Sequence[cirq.Qid], ancilla: Sequence[cirq.Qid], l_iter: int, r_iter: int, break_early: Callable[[int, int], bool], -) -> Iterator[Tuple[cirq.OP_TREE, cirq.Qid, int]]: +) -> Iterator[tuple[cirq.OP_TREE, cirq.Qid, int]]: sl, l, r = 0, 0, 2 ** len(selection) yield from _unary_iteration_segtree( ops, control, selection, ancilla, sl, l, r, l_iter, r_iter, break_early @@ -156,14 +157,14 @@ def _unary_iteration_single_control( def _unary_iteration_multi_controls( - ops: List[cirq.Operation], + ops: list[cirq.Operation], controls: Sequence[cirq.Qid], selection: Sequence[cirq.Qid], ancilla: Sequence[cirq.Qid], l_iter: int, r_iter: int, break_early: Callable[[int, int], bool], -) -> Iterator[Tuple[cirq.OP_TREE, cirq.Qid, int]]: +) -> Iterator[tuple[cirq.OP_TREE, cirq.Qid, int]]: num_controls = len(controls) and_ancilla = ancilla[: num_controls - 2] and_target = ancilla[num_controls - 2] @@ -188,12 +189,12 @@ def _unary_iteration_multi_controls( def unary_iteration( l_iter: int, r_iter: int, - flanking_ops: List[cirq.Operation], + flanking_ops: list[cirq.Operation], controls: Sequence[cirq.Qid], selection: Sequence[cirq.Qid], qubit_manager: cirq.QubitManager, break_early: Callable[[int, int], bool] = lambda l, r: False, -) -> Iterator[Tuple[cirq.OP_TREE, cirq.Qid, int]]: +) -> Iterator[tuple[cirq.OP_TREE, cirq.Qid, int]]: """The method performs unary iteration on `selection` integer in `range(l_iter, r_iter)`. Unary iteration is a coherent for loop that can be used to conditionally perform a different @@ -244,7 +245,7 @@ def unary_iteration( (r_iter - l_iter) different tuples, each corresponding to an integer in range [l_iter, r_iter). Each returned tuple also corresponds to a unique leaf in the unary iteration tree. - The values of yielded `Tuple[cirq.OP_TREE, cirq.Qid, int]` correspond to: + The values of yielded `tuple[cirq.OP_TREE, cirq.Qid, int]` correspond to: - cirq.OP_TREE: The op-tree to be inserted in the circuit to get to the current leaf. - cirq.Qid: Control qubit used to conditionally apply operations on the target conditioned on the returned integer. @@ -274,8 +275,8 @@ def _unary_iteration_callgraph_segtree( l_range: int, r_range: int, break_early: Callable[[int, int], bool], - bloq_counts: Dict['Bloq', Union[int, 'sympy.Expr']], -) -> List[int]: + bloq_counts: dict['Bloq', Union[int, 'sympy.Expr']], +) -> list[int]: """Iterative segment tree used to construct call graph for Unary iteration. See https://codeforces.com/blog/entry/18051 for an explanation of how iterative @@ -310,7 +311,7 @@ def _unary_iteration_callgraph_segtree( n_levels = n.bit_length() marked = np.zeros(2 * n, dtype=bool) num_ands = 0 - ret: List[int] = [] + ret: list[int] = [] step_size = n for lvl in range(1, n_levels + 1): r = l_range @@ -350,7 +351,7 @@ def _unary_iteration_callgraph( selection_bitsize: int, control_bitsize: int, break_early: Callable[[int, int], bool], - bloq_counts: Dict['Bloq', Union[int, 'sympy.Expr']], + bloq_counts: dict['Bloq', Union[int, 'sympy.Expr']], ) -> Sequence[int]: """Helper to compute the call graph for unary iteration. @@ -409,17 +410,17 @@ class UnaryIterationGate(GateWithRegisters): @cached_property @abc.abstractmethod - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: pass @cached_property @abc.abstractmethod - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: pass @cached_property @abc.abstractmethod - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: pass @cached_property @@ -429,7 +430,7 @@ def signature(self) -> Signature: ) @cached_property - def extra_registers(self) -> Tuple[Register, ...]: + def extra_registers(self) -> tuple[Register, ...]: return () @abc.abstractmethod @@ -479,7 +480,7 @@ def decompose_zero_selection( raise NotImplementedError("Selection register must not be empty.") def _break_early( - self, selection_index_prefix: Tuple[int, ...], l: 'SymbolicInt', r: 'SymbolicInt' + self, selection_index_prefix: tuple[int, ...], l: 'SymbolicInt', r: 'SymbolicInt' ) -> bool: """Derived classes should override this method to specify an early termination condition. @@ -520,7 +521,7 @@ def decompose_from_registers( def unary_iteration_loops( nested_depth: int, - selection_reg_name_to_val: Dict[str, int], + selection_reg_name_to_val: dict[str, int], controls: Sequence[cirq.Qid], ) -> Iterator[cirq.OP_TREE]: """Recursively write any number of nested coherent for-loops using unary iteration. @@ -553,7 +554,7 @@ def unary_iteration_loops( ) return # Use recursion to write `num_loops` nested loops using unary_iteration(). - ops: List[cirq.Operation] = [] + ops: list[cirq.Operation] = [] selection_index_prefix = tuple(selection_reg_name_to_val.values()) ith_for_loop = unary_iteration( l_iter=0, @@ -586,23 +587,23 @@ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.Circ wire_symbols += [self.__class__.__name__] * total_bits(self.target_registers) return cirq.CircuitDiagramInfo(wire_symbols=wire_symbols) - def nth_operation_callgraph(self, **selection_regs_name_to_val) -> Set['BloqCountT']: + def nth_operation_callgraph(self, **selection_regs_name_to_val) -> set['BloqCountT']: raise NotImplementedError( f"Derived class {type(self)} does not implement `nth_operation_callgraph`." ) def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if total_bits(self.selection_registers) == 0 or self._break_early( (), 0, self.selection_registers[0].dtype.iteration_length_or_zero() ): return self.decompose_bloq().build_call_graph(ssa) num_loops = len(self.selection_registers) - bloq_counts: Dict['Bloq', Union[int, 'sympy.Expr']] = defaultdict(lambda: 0) + bloq_counts: dict['Bloq', Union[int, 'sympy.Expr']] = defaultdict(lambda: 0) def unary_iteration_loops( - nested_depth: int, selection_reg_name_to_val: Dict[str, int], num_controls: int + nested_depth: int, selection_reg_name_to_val: dict[str, int], num_controls: int ) -> None: if nested_depth == num_loops: for bloq, count in self.nth_operation_callgraph(**selection_reg_name_to_val): diff --git a/qualtran/bloqs/multiplexers/unary_iteration_bloq_test.py b/qualtran/bloqs/multiplexers/unary_iteration_bloq_test.py index 529640770d..9c4b2ea524 100644 --- a/qualtran/bloqs/multiplexers/unary_iteration_bloq_test.py +++ b/qualtran/bloqs/multiplexers/unary_iteration_bloq_test.py @@ -13,8 +13,9 @@ # limitations under the License. import itertools +from collections.abc import Iterator, Sequence from functools import cached_property -from typing import Iterator, List, Sequence, Set, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import cirq import pytest @@ -40,17 +41,17 @@ def __init__(self, selection_bitsize: int, target_bitsize: int, control_bitsize: self._control_bitsize = control_bitsize @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return ( (Register('control', QAny(self._control_bitsize)),) if self._control_bitsize > 0 else () ) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('selection', BQUInt(self._selection_bitsize, self._target_bitsize)),) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return (Register('target', QAny(self._target_bitsize)),) def nth_operation( # type: ignore[override] @@ -62,7 +63,7 @@ def nth_operation( # type: ignore[override] ) -> cirq.OP_TREE: return cirq.CNOT(control, target[-(selection + 1)]) - def nth_operation_callgraph(self, **selection_regs_name_to_val) -> Set['BloqCountT']: + def nth_operation_callgraph(self, **selection_regs_name_to_val) -> set['BloqCountT']: return {(CNOT(), 1)} @@ -91,15 +92,15 @@ def test_unary_iteration_gate(selection_bitsize, target_bitsize, control_bitsize class ApplyXToIJKthQubit(UnaryIterationGate): - def __init__(self, target_shape: Tuple[int, int, int]): + def __init__(self, target_shape: tuple[int, int, int]): self._target_shape = target_shape @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return tuple( Register( 'ijk'[i], BQUInt((self._target_shape[i] - 1).bit_length(), self._target_shape[i]) @@ -108,7 +109,7 @@ def selection_registers(self) -> Tuple[Register, ...]: ) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return tuple( Signature.build( t1=self._target_shape[0], t2=self._target_shape[1], t3=self._target_shape[2] @@ -128,13 +129,13 @@ def nth_operation( # type: ignore[override] ) -> Iterator[cirq.OP_TREE]: yield [cirq.CNOT(control, t1[i]), cirq.CNOT(control, t2[j]), cirq.CNOT(control, t3[k])] - def nth_operation_callgraph(self, **selection_regs_name_to_val) -> Set['BloqCountT']: + def nth_operation_callgraph(self, **selection_regs_name_to_val) -> set['BloqCountT']: return {(CNOT(), 3)} @pytest.mark.slow @pytest.mark.parametrize("target_shape", [(2, 3, 2), (2, 2, 2)]) -def test_multi_dimensional_unary_iteration_gate(target_shape: Tuple[int, int, int]): +def test_multi_dimensional_unary_iteration_gate(target_shape: tuple[int, int, int]): greedy_mm = cirq.GreedyQubitManager(prefix="_a", maximize_reuse=True) gate = ApplyXToIJKthQubit(target_shape) g = GateHelper(gate, context=cirq.DecompositionContext(greedy_mm)) @@ -166,13 +167,13 @@ def test_unary_iteration_loop(): target = {(n, m): cirq.q(f't({n}, {m})') for n in range(*n_range) for m in range(*m_range)} qm = cirq.GreedyQubitManager("ancilla", maximize_reuse=True) circuit = cirq.Circuit() - i_ops: List[cirq.Operation] = [] + i_ops: list[cirq.Operation] = [] # Build the unary iteration circuit for i_optree, i_ctrl, i in unary_iteration( n_range[0], n_range[1], i_ops, [], list(selection['n']), qm ): circuit.append(i_optree) - j_ops: List[cirq.Operation] = [] + j_ops: list[cirq.Operation] = [] for j_optree, j_ctrl, j in unary_iteration( m_range[0], m_range[1], j_ops, [i_ctrl], list(selection['m']), qm ): @@ -225,7 +226,7 @@ def test_bloq_has_consistent_decomposition(selection_bitsize, target_bitsize, co @pytest.mark.parametrize("target_shape", [(2, 3, 2), (2, 2, 2)]) -def test_multi_dimensional_bloq_has_consistent_decomposition(target_shape: Tuple[int, int, int]): +def test_multi_dimensional_bloq_has_consistent_decomposition(target_shape: tuple[int, int, int]): bloq = ApplyXToIJKthQubit(target_shape) assert_valid_bloq_decomposition(bloq) verify_bloq_has_consistent_build_callgraph(bloq) diff --git a/qualtran/bloqs/optimization/k_xor_sat/kxor_instance.py b/qualtran/bloqs/optimization/k_xor_sat/kxor_instance.py index 913ae06ae0..4ce0e90bc7 100644 --- a/qualtran/bloqs/optimization/k_xor_sat/kxor_instance.py +++ b/qualtran/bloqs/optimization/k_xor_sat/kxor_instance.py @@ -25,8 +25,9 @@ # limitations under the License. import itertools from collections import defaultdict +from collections.abc import Sequence from functools import cached_property -from typing import cast, Sequence, TypeAlias, Union +from typing import cast, TypeAlias, Union import numpy as np import sympy diff --git a/qualtran/bloqs/phase_estimation/kaiser_window_state.py b/qualtran/bloqs/phase_estimation/kaiser_window_state.py index 38e851f815..ad9ae6de94 100644 --- a/qualtran/bloqs/phase_estimation/kaiser_window_state.py +++ b/qualtran/bloqs/phase_estimation/kaiser_window_state.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, List, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import numpy as np @@ -106,8 +106,8 @@ def from_precision_and_delta( return KaiserWindowState(bitsize=m_bits, alpha=alpha) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn return [ diff --git a/qualtran/bloqs/phase_estimation/lp_resource_state.py b/qualtran/bloqs/phase_estimation/lp_resource_state.py index 55466291ab..5462c16521 100644 --- a/qualtran/bloqs/phase_estimation/lp_resource_state.py +++ b/qualtran/bloqs/phase_estimation/lp_resource_state.py @@ -15,7 +15,7 @@ """Resource states proposed by A. Luis and J. Peřina (1996) for optimal phase measurements""" from collections import Counter from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import attrs import numpy as np @@ -56,14 +56,14 @@ class LPRSInterimPrep(GateWithRegisters): def signature(self) -> 'Signature': return Signature.build(m=self.bitsize, anc=1) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('LPRS') return super().wire_symbol(reg, idx) def build_composite_bloq( self, bb: 'BloqBuilder', *, m: 'SoquetT', anc: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: if isinstance(self.bitsize, sympy.Expr): raise ValueError(f'Symbolic bitsize {self.bitsize} not supported') m = bb.add(OnEach(self.bitsize, Hadamard()), q=m) @@ -140,7 +140,7 @@ def from_standard_deviation_eps(cls, eps: SymbolicFloat) -> 'LPResourceState': def m_bits(self) -> SymbolicInt: return self.bitsize - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: qpe_reg = bb.allocate(dtype=self.m_qdtype) anc, flag = bb.allocate(dtype=QBit()), bb.allocate(dtype=QBit()) diff --git a/qualtran/bloqs/phase_estimation/qpe_window_state.py b/qualtran/bloqs/phase_estimation/qpe_window_state.py index 075147c04e..fe548ca5e7 100644 --- a/qualtran/bloqs/phase_estimation/qpe_window_state.py +++ b/qualtran/bloqs/phase_estimation/qpe_window_state.py @@ -13,7 +13,7 @@ # limitations under the License. import abc from functools import cached_property -from typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs @@ -99,7 +99,7 @@ def from_standard_deviation_eps(cls, eps: SymbolicFloat): """ return cls(ceil(2 * log2(pi(eps) / eps))) - def build_composite_bloq(self, bb: 'BloqBuilder') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder') -> dict[str, 'SoquetT']: qpe_reg = bb.allocate(dtype=self.m_qdtype) qpe_reg = bb.add(OnEach(self.m_bits, Hadamard()), q=qpe_reg) return {'qpe_reg': qpe_reg} diff --git a/qualtran/bloqs/phase_estimation/qubitization_qpe.py b/qualtran/bloqs/phase_estimation/qubitization_qpe.py index 39b608ea57..0d86e887da 100644 --- a/qualtran/bloqs/phase_estimation/qubitization_qpe.py +++ b/qualtran/bloqs/phase_estimation/qubitization_qpe.py @@ -11,8 +11,9 @@ # 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 collections.abc import Iterator from functools import cached_property -from typing import Iterator, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import cirq @@ -95,11 +96,11 @@ def m_bits(self) -> SymbolicInt: return self.ctrl_state_prep.m_bits @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return tuple(self.walk.signature) @cached_property - def phase_registers(self) -> Tuple[Register, ...]: + def phase_registers(self) -> tuple[Register, ...]: return tuple(self.ctrl_state_prep.signature) @cached_property diff --git a/qualtran/bloqs/phase_estimation/text_book_qpe.py b/qualtran/bloqs/phase_estimation/text_book_qpe.py index 9349ca3290..aed8f17486 100644 --- a/qualtran/bloqs/phase_estimation/text_book_qpe.py +++ b/qualtran/bloqs/phase_estimation/text_book_qpe.py @@ -11,8 +11,9 @@ # 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 collections.abc import Iterator from functools import cached_property -from typing import Iterator, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import cirq @@ -157,11 +158,11 @@ def m_bits(self) -> SymbolicInt: return self.ctrl_state_prep.m_bits @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return tuple(self.unitary.signature) @cached_property - def phase_registers(self) -> Tuple[Register, ...]: + def phase_registers(self) -> tuple[Register, ...]: return tuple(self.ctrl_state_prep.signature) @cached_property diff --git a/qualtran/bloqs/qft/approximate_qft.py b/qualtran/bloqs/qft/approximate_qft.py index e6dfcee861..4837fe2e4e 100644 --- a/qualtran/bloqs/qft/approximate_qft.py +++ b/qualtran/bloqs/qft/approximate_qft.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. from collections import defaultdict +from collections.abc import Iterator from functools import cached_property -from typing import Iterator, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import cirq diff --git a/qualtran/bloqs/qft/approximate_qft_test.py b/qualtran/bloqs/qft/approximate_qft_test.py index 7dd0b10f8d..b4b02adb42 100644 --- a/qualtran/bloqs/qft/approximate_qft_test.py +++ b/qualtran/bloqs/qft/approximate_qft_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import math -from typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import cirq @@ -43,7 +43,7 @@ class TestApproximateQFT(GateWithRegisters): def signature(self) -> 'Signature': return Signature.build(q=self.bitsize) - def build_composite_bloq(self, bb: 'BloqBuilder', *, q: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', *, q: 'SoquetT') -> dict[str, 'SoquetT']: phase_grad = bb.add(PhaseGradientState(self.phase_bitsize, exponent=-1)) q, phase_grad = bb.add( diff --git a/qualtran/bloqs/qft/qft_phase_gradient.py b/qualtran/bloqs/qft/qft_phase_gradient.py index 6597eba42b..efa7d7ac53 100644 --- a/qualtran/bloqs/qft/qft_phase_gradient.py +++ b/qualtran/bloqs/qft/qft_phase_gradient.py @@ -11,8 +11,8 @@ # 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 collections.abc import Iterator from functools import cached_property -from typing import Iterator import attrs import cirq diff --git a/qualtran/bloqs/qft/qft_phase_gradient_test.py b/qualtran/bloqs/qft/qft_phase_gradient_test.py index d6fee8c159..680e62ddab 100644 --- a/qualtran/bloqs/qft/qft_phase_gradient_test.py +++ b/qualtran/bloqs/qft/qft_phase_gradient_test.py @@ -11,7 +11,7 @@ # 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 typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import cirq @@ -38,7 +38,7 @@ class TestQFTWithPhaseGradient(GateWithRegisters): def signature(self) -> 'Signature': return Signature.build(q=self.bitsize) - def build_composite_bloq(self, bb: 'BloqBuilder', *, q: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', *, q: 'SoquetT') -> dict[str, 'SoquetT']: phase_grad = bb.add(PhaseGradientState(self.bitsize)) q, phase_grad = bb.add( QFTPhaseGradient(self.bitsize, self.with_reverse), q=q, phase_grad=phase_grad diff --git a/qualtran/bloqs/qft/qft_text_book.py b/qualtran/bloqs/qft/qft_text_book.py index c560deab20..cd1bb2bcbc 100644 --- a/qualtran/bloqs/qft/qft_text_book.py +++ b/qualtran/bloqs/qft/qft_text_book.py @@ -11,8 +11,8 @@ # 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 collections.abc import Iterator from functools import cached_property -from typing import Iterator import attrs import cirq diff --git a/qualtran/bloqs/qft/two_bit_ffft.py b/qualtran/bloqs/qft/two_bit_ffft.py index a707f9c802..a4a395a5b5 100644 --- a/qualtran/bloqs/qft/two_bit_ffft.py +++ b/qualtran/bloqs/qft/two_bit_ffft.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, List, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import numpy as np from attrs import frozen @@ -87,14 +87,14 @@ def __attrs_post_init__(self): def signature(self) -> Signature: return Signature([Register('x', QBit()), Register('y', QBit())]) - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('F(k, n)') return super().wire_symbol(reg, idx) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn # TODO: https://github.com/quantumlib/Qualtran/issues/873. This tensor definition @@ -119,7 +119,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': def build_composite_bloq( self, bb: 'BloqBuilder', x: 'Soquet', y: 'Soquet' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: x = bb.add(Rz(2 * np.pi * self.k / self.n, eps=self.eps), q=x) y = bb.add(SGate(), q=y) x = bb.add(Hadamard(), q=x) diff --git a/qualtran/bloqs/qsp/fast_qsp.py b/qualtran/bloqs/qsp/fast_qsp.py index eada77ac61..62ea067cd6 100644 --- a/qualtran/bloqs/qsp/fast_qsp.py +++ b/qualtran/bloqs/qsp/fast_qsp.py @@ -11,7 +11,8 @@ # 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 typing import Sequence, Union +from collections.abc import Sequence +from typing import Union import numpy as np from numpy.typing import NDArray diff --git a/qualtran/bloqs/qsp/fft_qsp.py b/qualtran/bloqs/qsp/fft_qsp.py index 855d7a61b3..0265e5fe93 100644 --- a/qualtran/bloqs/qsp/fft_qsp.py +++ b/qualtran/bloqs/qsp/fft_qsp.py @@ -11,7 +11,8 @@ # 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 typing import Sequence, Union +from collections.abc import Sequence +from typing import Union import numpy as np diff --git a/qualtran/bloqs/qsp/generalized_qsp.py b/qualtran/bloqs/qsp/generalized_qsp.py index 04cc75184d..9612529df9 100644 --- a/qualtran/bloqs/qsp/generalized_qsp.py +++ b/qualtran/bloqs/qsp/generalized_qsp.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. from collections import Counter +from collections.abc import Iterable, Iterator, Sequence from functools import cached_property -from typing import Iterable, Iterator, Sequence, Tuple, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import numpy as np from attrs import field, frozen @@ -165,7 +166,7 @@ def assert_is_permutation(A, B): def qsp_phase_factors( P: Union[NDArray[np.number], Sequence[complex]], Q: Union[NDArray[np.number], Sequence[complex]] -) -> Tuple[NDArray[np.floating], NDArray[np.floating], int]: +) -> tuple[NDArray[np.floating], NDArray[np.floating], int]: """Computes the QSP signal rotations for a given pair of polynomials. The QSP transformation is described in Theorem 3, and the algorithm for computing @@ -216,7 +217,7 @@ def safe_angle(x): return theta, phi, lambd -def _to_tuple(x: Union[Iterable[complex], Shaped]) -> Union[Tuple[complex, ...], Shaped]: +def _to_tuple(x: Union[Iterable[complex], Shaped]) -> Union[tuple[complex, ...], Shaped]: """mypy-compatible attrs converter for GeneralizedQSP.P and Q""" if isinstance(x, Shaped): return x @@ -283,8 +284,8 @@ class GeneralizedQSP(GateWithRegisters): """ U: 'Bloq' - P: Union[Tuple[complex, ...], Shaped] = field(converter=_to_tuple) - Q: Union[Tuple[complex, ...], Shaped] = field(converter=_to_tuple) + P: Union[tuple[complex, ...], Shaped] = field(converter=_to_tuple) + Q: Union[tuple[complex, ...], Shaped] = field(converter=_to_tuple) negative_power: SymbolicInt = field(default=0, kw_only=True) precision: SymbolicFloat = field(default=1e-11, kw_only=True) @@ -319,7 +320,7 @@ def from_qsp_polynomial( return GeneralizedQSP(U, P, Q, negative_power=negative_power, precision=precision) @cached_property - def _qsp_phases(self) -> Tuple[NDArray[np.floating], NDArray[np.floating], float]: + def _qsp_phases(self) -> tuple[NDArray[np.floating], NDArray[np.floating], float]: if isinstance(self.P, Shaped) or isinstance(self.Q, Shaped): raise ValueError( 'Cannot compute phases for symbolic GQSP polynomials {self.P=}, {self.Q=}' diff --git a/qualtran/bloqs/qsp/generalized_qsp_test.py b/qualtran/bloqs/qsp/generalized_qsp_test.py index c925da2a85..ea9ee1ae7c 100644 --- a/qualtran/bloqs/qsp/generalized_qsp_test.py +++ b/qualtran/bloqs/qsp/generalized_qsp_test.py @@ -11,8 +11,9 @@ # 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 collections.abc import Sequence from functools import cached_property -from typing import Dict, Optional, Sequence +from typing import Optional import cirq import numpy as np @@ -160,7 +161,7 @@ def catch_rotations(bloq: Bloq) -> Bloq: g, sigma = gsqp_U.call_graph(max_depth=1, generalizer=catch_rotations) - expected_counts: Dict[Bloq, int] = {arbitrary_rotation: 3} + expected_counts: dict[Bloq, int] = {arbitrary_rotation: 3} if negative_power < 2: expected_counts[U.controlled(control_values=[0])] = 2 - negative_power if negative_power > 0: diff --git a/qualtran/bloqs/qubitization/qubitization_walk_operator.py b/qualtran/bloqs/qubitization/qubitization_walk_operator.py index 9e270d8ec3..ae1c9fd8dd 100644 --- a/qualtran/bloqs/qubitization/qubitization_walk_operator.py +++ b/qualtran/bloqs/qubitization/qubitization_walk_operator.py @@ -27,7 +27,7 @@ """ from functools import cached_property -from typing import Tuple, Union +from typing import Union import attrs import cirq @@ -93,7 +93,7 @@ class QubitizationWalkOperator(GateWithRegisters): block_encoding: Union[SelectBlockEncoding, LCUBlockEncoding] @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: regs = tuple( set(self.block_encoding.selection_registers + self.reflect.selection_registers) ) @@ -107,11 +107,11 @@ def selection_registers(self) -> Tuple[Register, ...]: return regs @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return self.block_encoding.target_registers @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return self.block_encoding.junk_registers @cached_property diff --git a/qualtran/bloqs/reflections/prepare_identity.py b/qualtran/bloqs/reflections/prepare_identity.py index cbd8eb35d8..3279641771 100644 --- a/qualtran/bloqs/reflections/prepare_identity.py +++ b/qualtran/bloqs/reflections/prepare_identity.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Sequence from functools import cached_property -from typing import Dict, Sequence, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING from attrs import field, frozen @@ -41,7 +42,7 @@ class PrepareIdentity(PrepareOracle): selection_registers: The selection registers. """ - selection_regs: Tuple[Register, ...] = field( + selection_regs: tuple[Register, ...] = field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v) ) @@ -55,14 +56,14 @@ def from_bitsizes(cls, bitsizes: Sequence[SymbolicInt]) -> 'PrepareIdentity': return cls(tuple(Register(f'reg{i}_', QAny(b)) for i, b in enumerate(bitsizes))) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.selection_regs @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return () - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: Soquet) -> Dict[str, Soquet]: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: Soquet) -> dict[str, Soquet]: for label, soq in soqs.items(): soqs[label] = bb.add(Identity(soq.reg.bitsize), q=soq) return soqs diff --git a/qualtran/bloqs/reflections/reflection_using_prepare.py b/qualtran/bloqs/reflections/reflection_using_prepare.py index 4a8467fde1..473f447ea4 100644 --- a/qualtran/bloqs/reflections/reflection_using_prepare.py +++ b/qualtran/bloqs/reflections/reflection_using_prepare.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator, Sequence from functools import cached_property -from typing import Iterator, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import attrs import cirq @@ -93,11 +94,11 @@ class ReflectionUsingPrepare(GateWithRegisters): eps: float = 1e-11 @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return () if self.control_val is None else (Register('control', QBit()),) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.prepare_gate.selection_registers @cached_property @@ -196,7 +197,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': def adjoint(self) -> 'ReflectionUsingPrepare': return self - def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']: + def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> tuple['Bloq', 'AddControlledT']: from qualtran.bloqs.mcmt.specialized_ctrl import get_ctrl_system_1bit_cv return get_ctrl_system_1bit_cv( diff --git a/qualtran/bloqs/rotations/hamming_weight_phasing.py b/qualtran/bloqs/rotations/hamming_weight_phasing.py index 2c55d84b5b..3df6a6ce87 100644 --- a/qualtran/bloqs/rotations/hamming_weight_phasing.py +++ b/qualtran/bloqs/rotations/hamming_weight_phasing.py @@ -13,7 +13,7 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import attrs import numpy as np @@ -80,7 +80,7 @@ class HammingWeightPhasing(GateWithRegisters): def signature(self) -> 'Signature': return Signature.build_from_dtypes(x=QUInt(self.bitsize)) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: soqs['x'], junk, out = bb.add(HammingWeightCompute(self.bitsize), x=soqs['x']) out = bb.split(out) for i in range(len(out)): @@ -93,7 +93,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str ) return soqs - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text(f'HWP_{self.bitsize}(Z^{self.exponent})') return super().wire_symbol(reg, idx) @@ -186,13 +186,13 @@ def gamma_dtype(self) -> QFxp: def build_composite_bloq( self, bb: 'BloqBuilder', *, x: 'SoquetT', phase_grad: 'SoquetT' - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: x, junk, out = bb.add(HammingWeightCompute(self.bitsize), x=x) out, phase_grad = bb.add(self.phase_oracle, out=out, phase_grad=phase_grad) x = bb.add(HammingWeightCompute(self.bitsize).adjoint(), x=x, junk=junk, out=out) return {'x': x, 'phase_grad': phase_grad} - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text(f'HWPG_{self.bitsize}(Z^{self.exponent})') return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/rotations/hamming_weight_phasing_test.py b/qualtran/bloqs/rotations/hamming_weight_phasing_test.py index 33dc216268..2a0527c49a 100644 --- a/qualtran/bloqs/rotations/hamming_weight_phasing_test.py +++ b/qualtran/bloqs/rotations/hamming_weight_phasing_test.py @@ -11,7 +11,7 @@ # 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 typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs import cirq @@ -85,7 +85,7 @@ def signature(self) -> 'Signature': def b_grad(self) -> SymbolicInt: return HammingWeightPhasingViaPhaseGradient(self.bitsize, self.exponent, self.eps).b_grad - def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'SoquetT') -> dict[str, 'SoquetT']: b_grad = self.b_grad phase_grad = bb.add(PhaseGradientState(b_grad)) x, phase_grad = bb.add( diff --git a/qualtran/bloqs/rotations/phase_gradient.py b/qualtran/bloqs/rotations/phase_gradient.py index 0a6dded656..1a5e7d2e27 100644 --- a/qualtran/bloqs/rotations/phase_gradient.py +++ b/qualtran/bloqs/rotations/phase_gradient.py @@ -11,8 +11,9 @@ # 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 collections.abc import Iterator, Sequence from functools import cached_property -from typing import Dict, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union import attrs import cirq @@ -261,7 +262,7 @@ class AddIntoPhaseGrad(GateWithRegisters, cirq.ArithmeticGate): # type: ignore[ sign: int = +1 controlled_by: Optional[int] = None - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': sign = '+' if self.sign > 0 else '-' if reg is None: return Text(f'pg{sign}=x>>{self.right_shift}' if self.right_shift else f'pg{sign}=x') @@ -302,7 +303,7 @@ def scaled_val(self, x: int) -> int: x_fxp = _fxp(x / 2**x_width, x_width).like(_fxp(0, self.phase_bitsize)).astype(float) return int(x_fxp.astype(float) * 2**self.phase_bitsize) - def apply(self, *args) -> Tuple[Union[int, np.integer, NDArray[np.integer]], ...]: + def apply(self, *args) -> tuple[Union[int, np.integer, NDArray[np.integer]], ...]: if self.controlled_by is not None: ctrl, x, phase_grad = args out = self.on_classical_vals(ctrl=ctrl, x=x, phase_grad=phase_grad) @@ -312,7 +313,7 @@ def apply(self, *args) -> Tuple[Union[int, np.integer, NDArray[np.integer]], ... out = self.on_classical_vals(x=x, phase_grad=phase_grad) return out['x'], out['phase_grad'] - def on_classical_vals(self, **kwargs) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, **kwargs) -> dict[str, 'ClassicalValT']: x, phase_grad = kwargs['x'], kwargs['phase_grad'] if self.controlled_by is not None: ctrl = kwargs['ctrl'] @@ -338,8 +339,8 @@ def adjoint(self) -> 'AddIntoPhaseGrad': return attrs.evolve(self, sign=-self.sign) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: from qualtran.cirq_interop._cirq_to_bloq import _my_tensors_from_gate return _my_tensors_from_gate(self, self.signature, incoming=incoming, outgoing=outgoing) @@ -507,13 +508,13 @@ def decompose_from_registers( def apply( self, x: int, phase_grad: int - ) -> Tuple[ + ) -> tuple[ Union[int, np.integer, NDArray[np.integer]], Union[int, np.integer, NDArray[np.integer]] ]: out = self.on_classical_vals(x=x, phase_grad=phase_grad) return out['x'], out['phase_grad'] - def on_classical_vals(self, x: int, phase_grad: int) -> Dict[str, 'ClassicalValT']: + def on_classical_vals(self, x: int, phase_grad: int) -> dict[str, 'ClassicalValT']: phase_grad_out = (phase_grad + self.scaled_val(x)) % 2**self.phase_bitsize return {'x': x, 'phase_grad': phase_grad_out} diff --git a/qualtran/bloqs/rotations/phasing_via_cost_function.py b/qualtran/bloqs/rotations/phasing_via_cost_function.py index 7e4204a0dc..59790e957a 100644 --- a/qualtran/bloqs/rotations/phasing_via_cost_function.py +++ b/qualtran/bloqs/rotations/phasing_via_cost_function.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING import attrs @@ -85,8 +85,8 @@ def signature(self) -> 'Signature': registers = [*self.cost_eval_oracle.signature.lefts(), *self.phase_oracle.extra_registers] return Signature(registers) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: - def _extract_soqs(bloq: Bloq) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: + def _extract_soqs(bloq: Bloq) -> dict[str, 'SoquetT']: return {reg.name: soqs.pop(reg.name) for reg in bloq.signature.lefts()} soqs |= bb.add_d(self.cost_eval_oracle, **_extract_soqs(self.cost_eval_oracle)) diff --git a/qualtran/bloqs/rotations/phasing_via_cost_function_test.py b/qualtran/bloqs/rotations/phasing_via_cost_function_test.py index a554f98fa0..0218894b96 100644 --- a/qualtran/bloqs/rotations/phasing_via_cost_function_test.py +++ b/qualtran/bloqs/rotations/phasing_via_cost_function_test.py @@ -11,8 +11,6 @@ # 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 typing import Dict - import attrs import cirq import numpy as np @@ -80,7 +78,7 @@ def phase_oracle(self) -> QvrInterface: def cost_eval_oracle(self) -> Bloq: return HammingWeightCompute(self.bitsize) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: if self.use_phase_gradient: soqs['phase_grad'] = bb.add(PhaseGradientState(int(self.phase_gradient_oracle.b_grad))) soqs = bb.add_d(PhasingViaCostFunction(self.cost_eval_oracle, self.phase_oracle), **soqs) @@ -157,7 +155,7 @@ def phase_oracle(self) -> QvrInterface: def cost_eval_oracle(self) -> Bloq: return Square(self.bitsize) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: if self.use_phase_gradient: soqs['phase_grad'] = bb.add(PhaseGradientState(int(self.phase_gradient_oracle.b_grad))) soqs = bb.add_d(PhasingViaCostFunction(self.cost_eval_oracle, self.phase_oracle), **soqs) diff --git a/qualtran/bloqs/rotations/programmable_rotation_gate_array.py b/qualtran/bloqs/rotations/programmable_rotation_gate_array.py index c7c8967938..5d86efbe5c 100644 --- a/qualtran/bloqs/rotations/programmable_rotation_gate_array.py +++ b/qualtran/bloqs/rotations/programmable_rotation_gate_array.py @@ -13,8 +13,8 @@ # limitations under the License. import abc +from collections.abc import Iterator, Sequence from functools import cached_property -from typing import Iterator, Sequence, Tuple import cirq import numpy as np @@ -95,7 +95,7 @@ def kappa(self) -> int: return self._kappa @property - def angles(self) -> Tuple[Tuple[int, ...], ...]: + def angles(self) -> tuple[tuple[int, ...], ...]: return self._angles @cached_method @@ -111,20 +111,20 @@ def interleaved_unitary( pass @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('selection', BQUInt(self._selection_bitsize, len(self.angles[0]))),) @cached_property - def kappa_load_target(self) -> Tuple[Register, ...]: + def kappa_load_target(self) -> tuple[Register, ...]: return (Register('kappa_load_target', QAny(self.kappa)),) @cached_property - def rotations_target(self) -> Tuple[Register, ...]: + def rotations_target(self) -> tuple[Register, ...]: return (Register('rotations_target', QAny(self._target_bitsize)),) @property @abc.abstractmethod - def interleaved_unitary_target(self) -> Tuple[Register, ...]: + def interleaved_unitary_target(self) -> tuple[Register, ...]: pass @cached_property @@ -212,7 +212,7 @@ def interleaved_unitary(self, index: int, **qubit_regs: NDArray[cirq.Qid]) -> ci return self._interleaved_unitaries[index].on(*qubit_regs['rotations_target']) @cached_property - def interleaved_unitary_target(self) -> Tuple[Register, ...]: + def interleaved_unitary_target(self) -> tuple[Register, ...]: return () diff --git a/qualtran/bloqs/rotations/programmable_rotation_gate_array_test.py b/qualtran/bloqs/rotations/programmable_rotation_gate_array_test.py index f3486cab51..1063112cf6 100644 --- a/qualtran/bloqs/rotations/programmable_rotation_gate_array_test.py +++ b/qualtran/bloqs/rotations/programmable_rotation_gate_array_test.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator from functools import cached_property -from typing import Iterator, Tuple import cirq import numpy as np @@ -41,7 +41,7 @@ def interleaved_unitary( return two_qubit_ops_factory[index % 2] @cached_property - def interleaved_unitary_target(self) -> Tuple[Register, ...]: + def interleaved_unitary_target(self) -> tuple[Register, ...]: return tuple(Signature.build(unrelated_target=1)) diff --git a/qualtran/bloqs/rotations/quantum_variable_rotation.py b/qualtran/bloqs/rotations/quantum_variable_rotation.py index 8177ea80e8..26630f7f09 100644 --- a/qualtran/bloqs/rotations/quantum_variable_rotation.py +++ b/qualtran/bloqs/rotations/quantum_variable_rotation.py @@ -55,8 +55,9 @@ """ import abc +from collections.abc import Sequence from functools import cached_property -from typing import cast, Dict, Sequence, TYPE_CHECKING +from typing import cast, TYPE_CHECKING import attrs import numpy as np @@ -177,7 +178,7 @@ def num_frac_rotations(self) -> SymbolicInt: def num_rotations(self) -> SymbolicInt: return self.cost_dtype.num_int + self.num_frac_rotations + int(self.cost_dtype.signed) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: if isinstance(self.cost_dtype.bitsize, sympy.Expr): raise ValueError(f'Unsupported symbolic {self.cost_dtype.bitsize} bitsize') out = cast(Soquet, soqs[self.cost_reg.name]) @@ -470,7 +471,7 @@ def gamma_dtype(self) -> QFxp: n_frac = self.cost_dtype.num_int + self.b_phase return QFxp(bitsize=n_int + n_frac, num_frac=n_frac, signed=False) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: add_scaled_val = AddScaledValIntoPhaseReg( self.cost_dtype, self.b_grad, self.gamma, self.gamma_dtype ) diff --git a/qualtran/bloqs/rotations/quantum_variable_rotation_test.py b/qualtran/bloqs/rotations/quantum_variable_rotation_test.py index 864b904866..81c4137cf4 100644 --- a/qualtran/bloqs/rotations/quantum_variable_rotation_test.py +++ b/qualtran/bloqs/rotations/quantum_variable_rotation_test.py @@ -11,7 +11,7 @@ # 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 typing import Iterator +from collections.abc import Iterator import attrs import cirq diff --git a/qualtran/bloqs/state_preparation/black_box_prepare.py b/qualtran/bloqs/state_preparation/black_box_prepare.py index 42aacba78e..91f24d1439 100644 --- a/qualtran/bloqs/state_preparation/black_box_prepare.py +++ b/qualtran/bloqs/state_preparation/black_box_prepare.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Tuple from attr import frozen @@ -51,11 +50,11 @@ class BlackBoxPrepare(Bloq): prepare: PrepareOracle @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register(name='selection', dtype=QAny(self.selection_bitsize)),) @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return (Register(name='junk', dtype=QAny(self.junk_bitsize)),) @cached_property @@ -74,7 +73,7 @@ def l1_norm_of_coeffs(self) -> SymbolicFloat: def signature(self) -> Signature: return Signature.build(selection=self.selection_bitsize, junk=self.junk_bitsize) - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: if self.selection_bitsize == 0: return soqs partitions = [ diff --git a/qualtran/bloqs/state_preparation/black_box_prepare_test.py b/qualtran/bloqs/state_preparation/black_box_prepare_test.py index 8dc0acab59..30a7fafbc6 100644 --- a/qualtran/bloqs/state_preparation/black_box_prepare_test.py +++ b/qualtran/bloqs/state_preparation/black_box_prepare_test.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Tuple - from attr import frozen from qualtran import QAny, QBit, Register @@ -28,11 +26,11 @@ def test_black_box_prepare(bloq_autotester): @frozen class TestPrepareOracle(PrepareOracle): @property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return (Register('z', QBit()),) @property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return (Register('a', QAny(5)),) diff --git a/qualtran/bloqs/state_preparation/prepare_base.py b/qualtran/bloqs/state_preparation/prepare_base.py index 6870d7752a..df60aa562d 100644 --- a/qualtran/bloqs/state_preparation/prepare_base.py +++ b/qualtran/bloqs/state_preparation/prepare_base.py @@ -14,7 +14,6 @@ import abc from functools import cached_property -from typing import Tuple from qualtran import BloqDocSpec, GateWithRegisters, Register, Signature from qualtran.symbolics import SymbolicFloat @@ -38,10 +37,10 @@ class PrepareOracle(GateWithRegisters): @property @abc.abstractmethod - def selection_registers(self) -> Tuple[Register, ...]: ... + def selection_registers(self) -> tuple[Register, ...]: ... @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return () @cached_property diff --git a/qualtran/bloqs/state_preparation/prepare_uniform_superposition.py b/qualtran/bloqs/state_preparation/prepare_uniform_superposition.py index c3a7002bc7..16988eaa59 100644 --- a/qualtran/bloqs/state_preparation/prepare_uniform_superposition.py +++ b/qualtran/bloqs/state_preparation/prepare_uniform_superposition.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator from functools import cached_property -from typing import cast, Iterator, Optional, Set, Tuple, TYPE_CHECKING, Union +from typing import cast, Optional, TYPE_CHECKING, Union import attrs import cirq @@ -64,7 +65,7 @@ class PrepareUniformSuperposition(GateWithRegisters): """ n: SymbolicInt - cvs: Union[HasLength, Tuple[SymbolicInt, ...]] = attrs.field( + cvs: Union[HasLength, tuple[SymbolicInt, ...]] = attrs.field( converter=_to_tuple_or_has_length, default=() ) @@ -73,17 +74,17 @@ def signature(self) -> Signature: return Signature.build(ctrl=slen(self.cvs), target=bit_length(self.n - 1)) def wire_symbol( - self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + self, reg: Optional['Register'], idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': if reg is None: return Text('Σ |l>') return super().wire_symbol(reg, idx) @property - def concrete_cvs(self) -> Tuple[int, ...]: + def concrete_cvs(self) -> tuple[int, ...]: if isinstance(self.cvs, HasLength): raise ValueError(f"{self.cvs} is symbolic") - return cast(Tuple[int, ...], self.cvs) + return cast(tuple[int, ...], self.cvs) def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo: control_symbols = ["@" if cv else "@(0)" for cv in self.concrete_cvs] @@ -91,7 +92,7 @@ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.Circ target_symbols[0] = f"UNIFORM({self.n})" return cirq.CircuitDiagramInfo(wire_symbols=control_symbols + target_symbols) - def k_l_logL(self) -> Tuple[SymbolicInt, SymbolicInt, SymbolicInt]: + def k_l_logL(self) -> tuple[SymbolicInt, SymbolicInt, SymbolicInt]: # Find K and L as per https://arxiv.org/abs/1805.03662 Fig 12. k, n, logL = 0, self.n, bit_length(self.n - 1) if is_symbolic(n): @@ -150,7 +151,7 @@ def decompose_from_registers( def build_call_graph( self, ssa: 'SympySymbolAllocator' - ) -> Union['BloqCountDictT', Set['BloqCountT']]: + ) -> Union['BloqCountDictT', set['BloqCountT']]: if not is_symbolic(self.n, self.cvs): # build from decomposition return super().build_call_graph(ssa) diff --git a/qualtran/bloqs/state_preparation/sparse_state_preparation_via_rotations.py b/qualtran/bloqs/state_preparation/sparse_state_preparation_via_rotations.py index e5d631263c..2cfa0d52bd 100644 --- a/qualtran/bloqs/state_preparation/sparse_state_preparation_via_rotations.py +++ b/qualtran/bloqs/state_preparation/sparse_state_preparation_via_rotations.py @@ -11,7 +11,8 @@ # 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 typing import Sequence, TYPE_CHECKING, Union +from collections.abc import Sequence +from typing import TYPE_CHECKING, Union import attrs import numpy as np diff --git a/qualtran/bloqs/state_preparation/state_preparation_alias_sampling.py b/qualtran/bloqs/state_preparation/state_preparation_alias_sampling.py index 4850ef95d9..39bc98353f 100644 --- a/qualtran/bloqs/state_preparation/state_preparation_alias_sampling.py +++ b/qualtran/bloqs/state_preparation/state_preparation_alias_sampling.py @@ -19,8 +19,9 @@ database) with a number of T gates scaling as 4L + O(log(1/eps)) where eps is the largest absolute error that one can tolerate in the prepared amplitudes. """ +from collections.abc import Sequence from functools import cached_property -from typing import Sequence, Tuple, TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Union import attrs import numpy as np @@ -51,7 +52,7 @@ from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator -def _data_or_shape_to_tuple(data_or_shape: Union[NDArray, Shaped]) -> Tuple: +def _data_or_shape_to_tuple(data_or_shape: Union[NDArray, Shaped]) -> tuple: return ( tuple(data_or_shape.flatten()) if isinstance(data_or_shape, np.ndarray) @@ -113,7 +114,7 @@ class StatePreparationAliasSampling(PrepareOracle): Babbush et al. (2018). Section III.D. and Figure 11. """ - selection_registers: Tuple[Register, ...] = attrs.field( + selection_registers: tuple[Register, ...] = attrs.field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v) ) alt: Union[Shaped, NDArray[np.int_]] = attrs.field(eq=_data_or_shape_to_tuple) @@ -223,7 +224,7 @@ def selection_bitsize(self) -> SymbolicInt: return total_bits(self.selection_registers) @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return tuple( Signature.build( sigma_mu=self.sigma_mu_bitsize, @@ -355,7 +356,7 @@ class SparseStatePreparationAliasSampling(PrepareOracle): Babbush et al. (2018). Section III.D. and Figure 11. """ - selection_registers: Tuple[Register, ...] = attrs.field( + selection_registers: tuple[Register, ...] = attrs.field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v) ) index: Union[Shaped, NDArray[np.int_]] = attrs.field(eq=_data_or_shape_to_tuple) @@ -369,7 +370,7 @@ def __attrs_post_init__(self): raise ValueError(f"{self.mu=} must be at least 1") @cached_property - def junk_registers(self) -> Tuple[Register, ...]: + def junk_registers(self) -> tuple[Register, ...]: return tuple( Signature.build( sigma_mu=self.mu, diff --git a/qualtran/bloqs/state_preparation/state_preparation_via_rotation.py b/qualtran/bloqs/state_preparation/state_preparation_via_rotation.py index 2466a11c33..f27cd68b0f 100644 --- a/qualtran/bloqs/state_preparation/state_preparation_via_rotation.py +++ b/qualtran/bloqs/state_preparation/state_preparation_via_rotation.py @@ -74,7 +74,8 @@ """ from collections import Counter -from typing import cast, Dict, Iterable, List, Tuple, TYPE_CHECKING, Union +from collections.abc import Iterable +from typing import cast, TYPE_CHECKING, Union import attrs import numpy as np @@ -104,7 +105,7 @@ def _to_tuple_or_has_length( x: Union[HasLength, Iterable[complex]] -) -> Union[HasLength, Tuple[complex, ...]]: +) -> Union[HasLength, tuple[complex, ...]]: if isinstance(x, HasLength): return x return tuple(x) @@ -134,7 +135,7 @@ class StatePreparationViaRotations(GateWithRegisters): Low, Kliuchnikov, Schaeffer. 2018. """ - state_coefficients: Union[HasLength, Tuple[complex, ...]] = attrs.field( + state_coefficients: Union[HasLength, tuple[complex, ...]] = attrs.field( converter=_to_tuple_or_has_length ) phase_bitsize: SymbolicInt @@ -176,7 +177,7 @@ def rotation_tree(self) -> 'RotationTree': return RotationTree(np.asarray(self.state_coefficients), self.phase_bitsize, self.uncompute) @property - def prga_prepare_amplitude(self) -> List['PRGAViaPhaseGradient']: + def prga_prepare_amplitude(self) -> list['PRGAViaPhaseGradient']: if is_symbolic(self.state_coefficients, self.phase_bitsize): return [ PRGAViaPhaseGradient( @@ -200,7 +201,7 @@ def prga_prepare_amplitude(self) -> List['PRGAViaPhaseGradient']: @property def prga_prepare_phases(self) -> 'PRGAViaPhaseGradient': - data_or_shape: Union[Shaped, Tuple[int, ...]] = ( + data_or_shape: Union[Shaped, tuple[int, ...]] = ( Shaped((slen(self.state_coefficients),)) if is_symbolic(self.state_coefficients) or is_symbolic(self.phase_bitsize) else tuple(self.rotation_tree.get_rom_vals()[1]) @@ -212,7 +213,7 @@ def prga_prepare_phases(self) -> 'PRGAViaPhaseGradient': control_bitsize=self.control_bitsize + 1, ) - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: r"""Parameters: * prepare_control: only if control_bitsize != 0 * target_state: register where the state is written @@ -239,7 +240,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': ret[bloq] += 1 return ret - def _prepare_amplitudes(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def _prepare_amplitudes(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: r"""Parameters into soqs: * prepare_control: only if control_bitsize != 0 * target_state: register where the state is written @@ -279,7 +280,7 @@ def _prepare_amplitudes(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, Soq soqs["target_state"] = bb.join(state_qubits) return soqs - def _prepare_phases(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def _prepare_phases(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: """Encodes the phase of each coefficient. Takes into account both the phase of the original coefficient and offsets caused by the @@ -410,7 +411,7 @@ class PRGAViaPhaseGradient(Bloq): selection_bitsize: SymbolicInt phase_bitsize: SymbolicInt - rom_values: Union[Shaped, Tuple[int, ...]] + rom_values: Union[Shaped, tuple[int, ...]] control_bitsize: SymbolicInt @property @@ -434,7 +435,7 @@ def qrom_bloq(self) -> QROM: def add_into_phase_grad(self) -> AddIntoPhaseGrad: return AddIntoPhaseGrad(self.phase_bitsize, self.phase_bitsize) - def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> Dict[str, SoquetT]: + def build_composite_bloq(self, bb: BloqBuilder, **soqs: SoquetT) -> dict[str, SoquetT]: """Parameters: * control * selection (not necessary if selection_bitsize == 0) @@ -490,7 +491,7 @@ def __init__(self, state: NDArray, phase_bitsize: int, uncompute: bool = False): self._calc_amplitude_angles_and_rv(state, phase_bitsize, uncompute) self._calc_phase_rom_values(state, phase_bitsize, uncompute) - def get_rom_vals(self) -> Tuple[List[List[int]], List[int]]: + def get_rom_vals(self) -> tuple[list[list[int]], list[int]]: return self.amplitude_rom_values, self.phase_rom_values def _calc_amplitude_angles_and_rv( @@ -507,9 +508,9 @@ def _calc_amplitude_angles_and_rv( self.sum_total[i + slen] = abs(state[i]) ** 2 for i in range(slen - 1, 0, -1): self.sum_total[i] = self.sum_total[i << 1] + self.sum_total[(i << 1) | 1] - self.amplitude_rom_values: List[List[int]] = [] + self.amplitude_rom_values: list[list[int]] = [] for i in range(self.state_bitsize): - rom_vals_this_layer: List[int] = [] + rom_vals_this_layer: list[int] = [] for node in range(1 << i, 1 << (i + 1)): angle = self._angle_0(node) if uncompute: @@ -536,7 +537,7 @@ def _calc_phase_rom_values(self, state: NDArray, phase_bitsize: int, uncompute: angles = np.array([np.angle(c) for c in state]) # flip angle if uncompute angles = [(1 - 2 * uncompute) * (a - o) for a, o in zip(angles, offsets)] - self.phase_rom_values: List[int] = [ + self.phase_rom_values: list[int] = [ RotationTree._angle_to_rom_value(a, phase_bitsize) for a in angles ] diff --git a/qualtran/bloqs/state_preparation/state_preparation_via_rotation_test.py b/qualtran/bloqs/state_preparation/state_preparation_via_rotation_test.py index 6b7a770579..fe8147f6e9 100644 --- a/qualtran/bloqs/state_preparation/state_preparation_via_rotation_test.py +++ b/qualtran/bloqs/state_preparation/state_preparation_via_rotation_test.py @@ -11,8 +11,6 @@ # 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 typing import Tuple - import cirq import numpy as np import pytest @@ -119,7 +117,7 @@ def test_state_prep_via_rotation_symb(): ], ], ) -def test_exact_state_prep_via_rotation_(phase_bitsize: int, state_coefs: Tuple[complex, ...]): +def test_exact_state_prep_via_rotation_(phase_bitsize: int, state_coefs: tuple[complex, ...]): # https://github.com/python/mypy/issues/5313 qsp = StatePreparationViaRotations( phase_bitsize=phase_bitsize, state_coefficients=state_coefs # type: ignore[arg-type] @@ -157,7 +155,7 @@ def test_exact_state_prep_via_rotation_(phase_bitsize: int, state_coefs: Tuple[c ], ) def test_state_prep_via_rotation_adjoint( - phase_bitsize: int, state_coefs: Tuple[complex, ...] + phase_bitsize: int, state_coefs: tuple[complex, ...] ) -> None: # https://github.com/python/mypy/issues/5313 qsp = StatePreparationViaRotations( @@ -201,7 +199,7 @@ def test_state_prep_via_rotation_adjoint( ], ], ) -def test_approximate_state_prep_via_rotation(phase_bitsize: int, state_coefs: Tuple[complex, ...]): +def test_approximate_state_prep_via_rotation(phase_bitsize: int, state_coefs: tuple[complex, ...]): qsp = StatePreparationViaRotations( phase_bitsize=phase_bitsize, state_coefficients=state_coefs # type: ignore[arg-type] ) @@ -231,7 +229,7 @@ def test_approximate_state_prep_via_rotation(phase_bitsize: int, state_coefs: Tu ], ) def test_controlled_state_preparation_via_rotation_do_not_prepare( - phase_bitsize: int, state_coefs: Tuple[complex, ...] + phase_bitsize: int, state_coefs: tuple[complex, ...] ): qsp = StatePreparationViaRotations( phase_bitsize=phase_bitsize, state_coefficients=state_coefs, control_bitsize=1 # type: ignore[arg-type] @@ -255,7 +253,7 @@ def test_controlled_state_preparation_via_rotation_do_not_prepare( @pytest.mark.parametrize("phase_bitsize, state_coefs", [[2, ((-0.5 - 0.5j), 0, 0.5, -0.5)]]) def test_state_preparation_via_rotation_superposition_ctrl( - phase_bitsize: int, state_coefs: Tuple[complex, ...] + phase_bitsize: int, state_coefs: tuple[complex, ...] ): qsp = StatePreparationViaRotations( phase_bitsize=phase_bitsize, state_coefficients=state_coefs, control_bitsize=1 # type: ignore[arg-type] @@ -282,7 +280,7 @@ def test_state_preparation_via_rotation_superposition_ctrl( @pytest.mark.parametrize("phase_bitsize, state_coefs", [[2, ((-0.5 - 0.5j), 0, 0.5, -0.5)]]) def test_state_preparation_via_rotation_multi_qubit_ctrl( - phase_bitsize: int, state_coefs: Tuple[complex, ...] + phase_bitsize: int, state_coefs: tuple[complex, ...] ): qsp = StatePreparationViaRotations( phase_bitsize=phase_bitsize, state_coefficients=state_coefs, control_bitsize=2 # type: ignore[arg-type] diff --git a/qualtran/bloqs/swap_network/cswap_approx.py b/qualtran/bloqs/swap_network/cswap_approx.py index 0629511b30..70899de751 100644 --- a/qualtran/bloqs/swap_network/cswap_approx.py +++ b/qualtran/bloqs/swap_network/cswap_approx.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterator from functools import cached_property -from typing import Dict, Iterator, Optional, Tuple, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING import cirq import sympy @@ -88,14 +89,14 @@ def g(q: cirq.Qid, adjoint=False) -> cirq.ops.op_tree.OpTree: def on_classical_vals( self, ctrl: 'ClassicalValT', x: 'ClassicalValT', y: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: if ctrl == 0: return {'ctrl': 0, 'x': x, 'y': y} if ctrl == 1: return {'ctrl': 1, 'x': y, 'y': x} raise ValueError("Bad control value for CSwap classical simulation.") - def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Optional[Register], idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return Text('~swap') return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/swap_network/cswap_approx_test.py b/qualtran/bloqs/swap_network/cswap_approx_test.py index 665e1cb122..e70ddfe811 100644 --- a/qualtran/bloqs/swap_network/cswap_approx_test.py +++ b/qualtran/bloqs/swap_network/cswap_approx_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import random -from typing import Dict, Tuple, Union +from typing import Union import cirq import numpy as np @@ -59,8 +59,8 @@ def test_approx_cswap_t_count(n): def get_t_count_and_clifford( - bc: Dict[Bloq, Union[int, sympy.Expr]] -) -> Tuple[Union[int, sympy.Expr], Union[int, sympy.Expr]]: + bc: dict[Bloq, Union[int, sympy.Expr]] +) -> tuple[Union[int, sympy.Expr], Union[int, sympy.Expr]]: """Get the t count and clifford cost from bloq count.""" cliff_cost = sum([v for k, v in bc.items() if isinstance(k, ArbitraryClifford)]) t_cost = sum([v for k, v in bc.items() if isinstance(k, TGate)]) diff --git a/qualtran/bloqs/swap_network/multiplexed_cswap.py b/qualtran/bloqs/swap_network/multiplexed_cswap.py index d41e2bb20c..c927e89275 100644 --- a/qualtran/bloqs/swap_network/multiplexed_cswap.py +++ b/qualtran/bloqs/swap_network/multiplexed_cswap.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Tuple import cirq from attrs import field, frozen @@ -41,14 +40,14 @@ class MultiplexedCSwap(UnaryIterationGate): the registers to swap, and $n_c$ is the number of controls. Args: - selection_regs: Indexing `select` signature of type Tuple[`Register`, ...]. + selection_regs: Indexing `select` signature of type tuple[`Register`, ...]. It also contains information about the iteration length of each selection register. target_bitsize: The size of the registers we want to swap. control_regs: Control registers for constructing a controlled version of the gate. Registers: control_registers: Control registers - selection_regs: Indexing `select` signature of type Tuple[`Register`, ...]. + selection_regs: Indexing `select` signature of type tuple[`Register`, ...]. It also contains information about the iteration length of each selection register. target_registers: Target registers to swap. We swap FROM registers labelled x`i`, where i is an integer and TO a single register called y @@ -58,24 +57,24 @@ class MultiplexedCSwap(UnaryIterationGate): page 20 paragraph 2. """ - selection_regs: Tuple[Register, ...] = field( + selection_regs: tuple[Register, ...] = field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v) ) target_bitsize: int - control_regs: Tuple[Register, ...] = field( + control_regs: tuple[Register, ...] = field( converter=lambda v: (v,) if isinstance(v, Register) else tuple(v), default=() ) @cached_property - def control_registers(self) -> Tuple[Register, ...]: + def control_registers(self) -> tuple[Register, ...]: return self.control_regs @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: return self.selection_regs @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: target_shape = tuple( sreg.dtype.iteration_length_or_zero() for sreg in self.selection_registers ) diff --git a/qualtran/bloqs/swap_network/swap_network.ipynb b/qualtran/bloqs/swap_network/swap_network.ipynb index 13d0a58fb5..f8a9e86028 100644 --- a/qualtran/bloqs/swap_network/swap_network.ipynb +++ b/qualtran/bloqs/swap_network/swap_network.ipynb @@ -323,13 +323,13 @@ "the registers to swap, and $n_c$ is the number of controls.\n", "\n", "#### Parameters\n", - " - `selection_regs`: Indexing `select` signature of type Tuple[`Register`, ...]. It also contains information about the iteration length of each selection register.\n", + " - `selection_regs`: Indexing `select` signature of type tuple[`Register`, ...]. It also contains information about the iteration length of each selection register.\n", " - `target_bitsize`: The size of the registers we want to swap.\n", " - `control_regs`: Control registers for constructing a controlled version of the gate. \n", "\n", "#### Registers\n", " - `control_registers`: Control registers\n", - " - `selection_regs`: Indexing `select` signature of type Tuple[`Register`, ...]. It also contains information about the iteration length of each selection register.\n", + " - `selection_regs`: Indexing `select` signature of type tuple[`Register`, ...]. It also contains information about the iteration length of each selection register.\n", " - `target_registers`: Target registers to swap. We swap FROM registers labelled x`i`, where i is an integer and TO a single register called y \n", "\n", "#### References\n", diff --git a/qualtran/bloqs/swap_network/swap_with_zero.py b/qualtran/bloqs/swap_network/swap_with_zero.py index 756704c796..4d066c1aa6 100644 --- a/qualtran/bloqs/swap_network/swap_with_zero.py +++ b/qualtran/bloqs/swap_network/swap_with_zero.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable, Iterator from functools import cached_property -from typing import cast, Dict, Iterable, Iterator, Tuple, TYPE_CHECKING, Union +from typing import cast, TYPE_CHECKING, Union import attrs import cirq @@ -42,7 +43,7 @@ from qualtran.simulation.classical_sim import ClassicalValT -def _to_tuple(x: Union[SymbolicInt, Iterable[SymbolicInt]]) -> Tuple[SymbolicInt, ...]: +def _to_tuple(x: Union[SymbolicInt, Iterable[SymbolicInt]]) -> tuple[SymbolicInt, ...]: if isinstance(x, np.ndarray): return _to_tuple(x.tolist()) if isinstance(x, Iterable): @@ -51,8 +52,8 @@ def _to_tuple(x: Union[SymbolicInt, Iterable[SymbolicInt]]) -> Tuple[SymbolicInt def _swap_with_zero_swap_sequence( - selection_bitsizes: Tuple[int, ...], target_shape: Tuple[int, ...], idx: Tuple[int, ...] = () -) -> Iterator[Tuple[int, int, Tuple[int, ...], Tuple[int, ...]]]: + selection_bitsizes: tuple[int, ...], target_shape: tuple[int, ...], idx: tuple[int, ...] = () +) -> Iterator[tuple[int, int, tuple[int, ...], tuple[int, ...]]]: """Yields tuples of indices that should be swapped in that order to realize a swap with zero. The method recursively iterates over all combinations of `S = np.prod(selection_bitsizes)` @@ -124,16 +125,16 @@ class SwapWithZero(GateWithRegisters): Low, Kliuchnikov, Schaeffer. 2018. """ - selection_bitsizes: Tuple[SymbolicInt, ...] = attrs.field(converter=_to_tuple) + selection_bitsizes: tuple[SymbolicInt, ...] = attrs.field(converter=_to_tuple) target_bitsize: SymbolicInt - n_target_registers: Tuple[SymbolicInt, ...] = attrs.field(converter=_to_tuple) + n_target_registers: tuple[SymbolicInt, ...] = attrs.field(converter=_to_tuple) uncompute: bool = False def __attrs_post_init__(self): assert len(self.n_target_registers) == len(self.selection_bitsizes) @cached_property - def selection_registers(self) -> Tuple[Register, ...]: + def selection_registers(self) -> tuple[Register, ...]: types = [ BQUInt(sb, l) for sb, l in zip(self.selection_bitsizes, self.n_target_registers) @@ -144,7 +145,7 @@ def selection_registers(self) -> Tuple[Register, ...]: return tuple(Register(f'selection{i}_', qdtype) for i, qdtype in enumerate(types)) @cached_property - def target_registers(self) -> Tuple[Register, ...]: + def target_registers(self) -> tuple[Register, ...]: return ( Register('targets', QAny(bitsize=self.target_bitsize), shape=self.n_target_registers), ) @@ -158,17 +159,17 @@ def cswap_n(self) -> 'CSwapApprox': return CSwapApprox(self.target_bitsize) @cached_property - def _swap_sequence(self) -> Tuple[Tuple[int, int, Tuple[int, ...], Tuple[int, ...]], ...]: + def _swap_sequence(self) -> tuple[tuple[int, int, tuple[int, ...], tuple[int, ...]], ...]: if is_symbolic(*self.selection_bitsizes) or is_symbolic(*self.n_target_registers): raise ValueError(f"Cannot produce swap sequence for symbolic {self=}") - selection_bitsizes = cast(Tuple[int, ...], self.selection_bitsizes) - n_target_registers = cast(Tuple[int, ...], self.n_target_registers) + selection_bitsizes = cast(tuple[int, ...], self.selection_bitsizes) + n_target_registers = cast(tuple[int, ...], self.n_target_registers) ret = [*_swap_with_zero_swap_sequence(selection_bitsizes, n_target_registers)] return tuple(ret[::-1] if self.uncompute else ret) def build_composite_bloq( self, bb: 'BloqBuilder', targets: NDArray['Soquet'], **sel: 'Soquet' # type: ignore[type-var] - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: sel_soqs = [bb.split(sel[reg.name]) for reg in self.selection_registers] for i, sel_idx_small, idx_one, idx_two in self._swap_sequence: sel_idx_big = self.selection_bitsizes[i] - sel_idx_small - 1 @@ -189,7 +190,7 @@ def _circuit_diagram_info_(self, args) -> cirq.CircuitDiagramInfo: return _wire_symbol_to_cirq_diagram_info(self, args) - def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + def wire_symbol(self, reg: Register, idx: tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return super().wire_symbol(reg, idx) name = reg.name @@ -202,7 +203,7 @@ def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSym def on_classical_vals( self, *, targets: 'ClassicalValT', **selection: 'ClassicalValT' - ) -> Dict[str, 'ClassicalValT']: + ) -> dict[str, 'ClassicalValT']: assert isinstance(targets, np.ndarray) selection_idx = tuple(selection.values()) for i, sel_idx_small, idx_one, idx_two in self._swap_sequence: diff --git a/qualtran/cirq_interop/_bloq_to_cirq.py b/qualtran/cirq_interop/_bloq_to_cirq.py index 3a03f65639..cf08268e9c 100644 --- a/qualtran/cirq_interop/_bloq_to_cirq.py +++ b/qualtran/cirq_interop/_bloq_to_cirq.py @@ -14,7 +14,8 @@ """Qualtran Bloqs to Cirq gates/circuits conversion.""" -from typing import Dict, Iterable, List, Optional, Sequence, Tuple +from collections.abc import Iterable, Sequence +from typing import Optional import cirq import networkx as nx @@ -95,8 +96,8 @@ def bloq(self) -> Bloq: @classmethod def bloq_on( - cls, bloq: Bloq, cirq_quregs: Dict[str, 'CirqQuregT'], qubit_manager: cirq.QubitManager # type: ignore[type-var] - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: # type: ignore[type-var] + cls, bloq: Bloq, cirq_quregs: dict[str, 'CirqQuregT'], qubit_manager: cirq.QubitManager # type: ignore[type-var] + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: # type: ignore[type-var] """Shim `bloq` into a cirq gate and call it on `cirq_quregs`. This is used as a default implementation for `Bloq.as_cirq_op` if a native @@ -191,7 +192,7 @@ def __repr__(self) -> str: return f'BloqAsCirqGate({self.bloq})' -def _track_soq_name_changes(cxns: Iterable[Connection], qvar_to_qreg: Dict[Soquet, _QReg]): +def _track_soq_name_changes(cxns: Iterable[Connection], qvar_to_qreg: dict[Soquet, _QReg]): """Track inter-Bloq name changes across the two ends of a connection.""" for cxn in cxns: qvar_to_qreg[cxn.right] = qvar_to_qreg[cxn.left] @@ -202,11 +203,11 @@ def _bloq_to_cirq_op( bloq: Bloq, pred_cxns: Iterable[Connection], succ_cxns: Iterable[Connection], - qvar_to_qreg: Dict[Soquet, _QReg], + qvar_to_qreg: dict[Soquet, _QReg], qubit_manager: cirq.QubitManager, ) -> Optional[cirq.Operation]: _track_soq_name_changes(pred_cxns, qvar_to_qreg) - in_quregs: Dict[str, CirqQuregT] = { + in_quregs: dict[str, CirqQuregT] = { reg.name: np.empty((*reg.shape, reg.bitsize), dtype=object) for reg in bloq.signature.lefts() } @@ -234,10 +235,10 @@ def _bloq_to_cirq_op( def _cbloq_to_cirq_circuit( signature: Signature, - cirq_quregs: Dict[str, 'CirqQuregInT'], + cirq_quregs: dict[str, 'CirqQuregInT'], binst_graph: nx.DiGraph, qubit_manager: cirq.QubitManager, -) -> Tuple[cirq.FrozenCircuit, Dict[str, 'CirqQuregT']]: +) -> tuple[cirq.FrozenCircuit, dict[str, 'CirqQuregT']]: """Propagate `as_cirq_op` calls through a composite bloq's contents to export a `cirq.Circuit`. Args: @@ -250,16 +251,16 @@ def _cbloq_to_cirq_circuit( circuit: The cirq.FrozenCircuit version of this composite bloq. cirq_quregs: The output mapping from right register names to Cirq qubit arrays. """ - cirq_quregs: Dict[str, 'CirqQuregInT'] = { + cirq_quregs: dict[str, 'CirqQuregInT'] = { k: np.apply_along_axis(_QReg, -1, *(v, signature.get_left(k).dtype)) # type: ignore for k, v in cirq_quregs.items() } - qvar_to_qreg: Dict[Soquet, _QReg] = { + qvar_to_qreg: dict[Soquet, _QReg] = { Soquet(LeftDangle, idx=idx, reg=reg): np.asarray(cirq_quregs[reg.name])[idx] for reg in signature.lefts() for idx in reg.all_idxs() } - ops: List[cirq.Operation] = [] + ops: list[cirq.Operation] = [] for binst in greedy_topological_sort(binst_graph): if binst is LeftDangle: continue diff --git a/qualtran/cirq_interop/_bloq_to_cirq_test.py b/qualtran/cirq_interop/_bloq_to_cirq_test.py index eb2d9e6204..91dc6cc3d3 100644 --- a/qualtran/cirq_interop/_bloq_to_cirq_test.py +++ b/qualtran/cirq_interop/_bloq_to_cirq_test.py @@ -11,7 +11,7 @@ # 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 typing import Dict, List, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING import cirq import numpy as np @@ -39,14 +39,14 @@ def signature(self): def as_cirq_op( self, qubit_manager: cirq.QubitManager, x: CirqQuregT, y: CirqQuregT - ) -> Tuple[cirq.Operation, Dict[str, CirqQuregT]]: + ) -> tuple[cirq.Operation, dict[str, CirqQuregT]]: (x,) = x (y,) = y return cirq.SWAP(x, y), {'x': np.array([x]), 'y': np.array([y])} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: from qualtran.bloqs.basic_gates import TwoBitSwap return TwoBitSwap().my_tensors(incoming=incoming, outgoing=outgoing) @@ -73,7 +73,7 @@ def signature(self): def build_composite_bloq( self, bb: 'BloqBuilder', x: Soquet, y: Soquet, **kwargs - ) -> Dict[str, SoquetT]: + ) -> dict[str, SoquetT]: xs = bb.split(x) ys = bb.split(y) for i in range(self.n): @@ -90,8 +90,8 @@ def signature(self): return Signature.build(x=self.n, y=self.n) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: import quimb.tensor as qtn from qualtran.simulation.tensor._dense import _order_incoming_outgoing_indices diff --git a/qualtran/cirq_interop/_cirq_to_bloq.py b/qualtran/cirq_interop/_cirq_to_bloq.py index d2977e4339..8cf4282d21 100644 --- a/qualtran/cirq_interop/_cirq_to_bloq.py +++ b/qualtran/cirq_interop/_cirq_to_bloq.py @@ -17,8 +17,9 @@ import itertools import numbers import warnings +from collections.abc import Sequence from functools import cached_property -from typing import Any, Dict, List, Optional, Sequence, Tuple, TYPE_CHECKING, TypeVar, Union +from typing import Any, Optional, TYPE_CHECKING, TypeVar, Union import cirq import numpy as np @@ -114,15 +115,15 @@ def decompose_from_registers( raise DecomposeNotImplementedError(f"{self} does not declare a decomposition.") from e def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: return _my_tensors_from_gate( self.cirq_gate, self.signature, incoming=incoming, outgoing=outgoing ) def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', **in_quregs: 'CirqQuregT' - ) -> Tuple[Union['cirq.Operation', None], Dict[str, 'CirqQuregT']]: + ) -> tuple[Union['cirq.Operation', None], dict[str, 'CirqQuregT']]: qubits = in_quregs.get('q', np.array([])).flatten() return self.cirq_gate.on(*qubits), in_quregs @@ -188,7 +189,7 @@ def _cirq_wire_symbol_to_qualtran_wire_symbol(symbol: str, side: Side) -> 'WireS def _wire_symbol_from_gate( - gate: cirq.Gate, signature: Signature, wire_reg: Register, idx: Tuple[int, ...] = tuple() + gate: cirq.Gate, signature: Signature, wire_reg: Register, idx: tuple[int, ...] = tuple() ) -> 'WireSymbol': wire_symbols = cirq.circuit_diagram_info(gate).wire_symbols begin = 0 @@ -220,9 +221,9 @@ def _my_tensors_from_gate( gate: cirq.Gate, signature: Signature, *, - incoming: Dict[str, 'ConnectionT'], - outgoing: Dict[str, 'ConnectionT'], -) -> List['qtn.Tensor']: + incoming: dict[str, 'ConnectionT'], + outgoing: dict[str, 'ConnectionT'], +) -> list['qtn.Tensor']: import quimb.tensor as qtn from qualtran.simulation.tensor._dense import _order_incoming_outgoing_indices @@ -247,7 +248,7 @@ class _QReg: of qubits that together form a quantum register. """ - qubits: Tuple[cirq.Qid, ...] = field( + qubits: tuple[cirq.Qid, ...] = field( converter=lambda v: (v,) if isinstance(v, cirq.Qid) else tuple(v) ) dtype: QDType @@ -268,13 +269,13 @@ def __hash__(self): def _ensure_in_reg_exists( - bb: BloqBuilder, in_reg: _QReg, qreg_to_qvar: Dict[_QReg, Soquet] + bb: BloqBuilder, in_reg: _QReg, qreg_to_qvar: dict[_QReg, Soquet] ) -> None: """Takes care of qubit allocations, split and joins to ensure `qreg_to_qvar[in_reg]` exists.""" from qualtran.bloqs.bookkeeping import Cast all_mapped_qubits = {q for qreg in qreg_to_qvar for q in qreg.qubits} - qubits_to_allocate: List[cirq.Qid] = [q for q in in_reg.qubits if q not in all_mapped_qubits] + qubits_to_allocate: list[cirq.Qid] = [q for q in in_reg.qubits if q not in all_mapped_qubits] if qubits_to_allocate: n_alloc = len(qubits_to_allocate) qreg_to_qvar[_QReg(qubits_to_allocate, dtype=QBit() if n_alloc == 1 else QAny(n_alloc))] = ( @@ -288,7 +289,7 @@ def _ensure_in_reg_exists( # a. Split all registers containing at-least one qubit corresponding to `in_reg`. in_reg_qubits = set(in_reg.qubits) - new_qreg_to_qvar: Dict[_QReg, Soquet] = {} + new_qreg_to_qvar: dict[_QReg, Soquet] = {} for qreg, soq in qreg_to_qvar.items(): if len(qreg.qubits) > 1 and any(q in qreg.qubits for q in in_reg_qubits): new_qreg_to_qvar |= { @@ -299,7 +300,7 @@ def _ensure_in_reg_exists( qreg_to_qvar.clear() # b. Join all 1-bit registers, corresponding to individual qubits, that make up `in_reg`. - soqs_to_join: Dict[cirq.Qid, Soquet] = {} + soqs_to_join: dict[cirq.Qid, Soquet] = {} for qreg, soq in new_qreg_to_qvar.items(): if len(in_reg_qubits) > 1 and qreg.qubits and qreg.qubits[0] in in_reg_qubits: assert len(qreg.qubits) == 1, "Individual qubits should have been split by now." @@ -330,11 +331,11 @@ def _ensure_in_reg_exists( def _gather_input_soqs( - bb: BloqBuilder, op_quregs: Dict[str, NDArray[_QReg]], qreg_to_qvar: Dict[_QReg, Soquet] # type: ignore[type-var] -) -> Dict[str, NDArray[Soquet]]: # type: ignore[type-var] - qvars_in: Dict[str, NDArray[Soquet]] = {} # type: ignore[type-var] + bb: BloqBuilder, op_quregs: dict[str, NDArray[_QReg]], qreg_to_qvar: dict[_QReg, Soquet] # type: ignore[type-var] +) -> dict[str, NDArray[Soquet]]: # type: ignore[type-var] + qvars_in: dict[str, NDArray[Soquet]] = {} # type: ignore[type-var] for reg_name, quregs in op_quregs.items(): - flat_soqs: List[Soquet] = [] + flat_soqs: list[Soquet] = [] for qureg in quregs.flatten(): _ensure_in_reg_exists(bb, qureg, qreg_to_qvar) flat_soqs.append(qreg_to_qvar[qureg]) @@ -457,8 +458,8 @@ def cirq_optree_to_cbloq( optree: cirq.OP_TREE, *, signature: Optional[Signature] = None, - in_quregs: Optional[Dict[str, 'CirqQuregT']] = None, - out_quregs: Optional[Dict[str, 'CirqQuregT']] = None, + in_quregs: Optional[dict[str, 'CirqQuregT']] = None, + out_quregs: Optional[dict[str, 'CirqQuregT']] = None, ) -> CompositeBloq: """Convert a Cirq OP-TREE into a `CompositeBloq` with signature `signature`. @@ -500,11 +501,11 @@ def cirq_optree_to_cbloq( elif in_quregs is None or out_quregs is None: raise ValueError("`signature` requires specifying both `in_quregs` and `out_quregs`.") - in_quregs: Dict[str, NDArray] = { + in_quregs: dict[str, NDArray] = { k: np.apply_along_axis(_QReg, -1, *(v, signature.get_left(k).dtype)) # type: ignore for k, v in in_quregs.items() } - out_quregs: Dict[str, NDArray] = { + out_quregs: dict[str, NDArray] = { k: np.apply_along_axis(_QReg, -1, *(v, signature.get_right(k).dtype)) # type: ignore for k, v in out_quregs.items() } @@ -512,7 +513,7 @@ def cirq_optree_to_cbloq( bb, initial_soqs = BloqBuilder.from_signature(signature, add_registers_allowed=False) # 1. Compute qreg_to_qvar for input qubits in the LEFT signature. - qreg_to_qvar: Dict[_QReg, Soquet] = {} + qreg_to_qvar: dict[_QReg, Soquet] = {} for reg in signature.lefts(): if reg.name not in in_quregs: raise ValueError(f"Register {reg.name} from signature must be present in in_quregs.") @@ -535,12 +536,12 @@ def cirq_optree_to_cbloq( reg_dtypes = [r.dtype for r in bloq.signature] # 3.1 Find input / output registers. - all_op_quregs: Dict[str, NDArray[_QReg]] = { + all_op_quregs: dict[str, NDArray[_QReg]] = { k: np.apply_along_axis(_QReg, -1, *(v, reg_dtypes[i])) # type: ignore for i, (k, v) in enumerate(split_qubits(bloq.signature, op.qubits).items()) } - in_op_quregs: Dict[str, NDArray[_QReg]] = { + in_op_quregs: dict[str, NDArray[_QReg]] = { reg.name: all_op_quregs[reg.name] for reg in bloq.signature.lefts() } # 3.2 Find input Soquets, by potentially allocating new Bloq registers corresponding to diff --git a/qualtran/cirq_interop/_cirq_to_bloq_test.py b/qualtran/cirq_interop/_cirq_to_bloq_test.py index 7df2f0a8ec..042b86ab21 100644 --- a/qualtran/cirq_interop/_cirq_to_bloq_test.py +++ b/qualtran/cirq_interop/_cirq_to_bloq_test.py @@ -11,7 +11,7 @@ # 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 typing import Dict, Iterator, List, Tuple +from collections.abc import Iterator import attr import cirq @@ -50,7 +50,7 @@ class TestCNOT(Bloq): def signature(self) -> Signature: return Signature.build(control=1, target=1) - def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> dict[str, 'SoquetT']: ctrl, target = soqs['control'], soqs['target'] assert isinstance(ctrl, Soquet) assert isinstance(target, Soquet) @@ -59,7 +59,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str def as_cirq_op( self, qubit_manager: cirq.QubitManager, **cirq_quregs: 'CirqQuregT' - ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: + ) -> tuple['cirq.Operation', dict[str, 'CirqQuregT']]: (control,) = cirq_quregs['control'] (target,) = cirq_quregs['target'] return cirq.CNOT(control, target), cirq_quregs @@ -256,7 +256,7 @@ def decompose_from_registers(self, *, context, junk) -> Iterator[cirq.OP_TREE]: # Using InteropQubitManager enables support for LeftOnlyGate's in CirqGateAsBloq. cbloq = qlt_testing.assert_valid_bloq_decomposition(LeftOnlyGate()) - bloqs_list: List[Bloq] = [binst.bloq for binst in cbloq.bloq_instances] + bloqs_list: list[Bloq] = [binst.bloq for binst in cbloq.bloq_instances] assert bloqs_list.count(Split(QAny(2))) == 1 assert bloqs_list.count(Free(QBit())) == 2 assert bloqs_list.count(CNOT()) == 1 diff --git a/qualtran/cirq_interop/_interop_qubit_manager.py b/qualtran/cirq_interop/_interop_qubit_manager.py index da3e8d2ee9..152da604dd 100644 --- a/qualtran/cirq_interop/_interop_qubit_manager.py +++ b/qualtran/cirq_interop/_interop_qubit_manager.py @@ -13,7 +13,8 @@ # limitations under the License. """Qubit Manager to use when converting Cirq gates to/from Bloqs.""" -from typing import Iterable, List, Optional, Set +from collections.abc import Iterable +from typing import Optional import cirq @@ -25,11 +26,11 @@ def __init__(self, qm: Optional[cirq.QubitManager] = None): if qm is None: qm = cirq.SimpleQubitManager() self._qm = qm - self._managed_qubits: Set[cirq.Qid] = set() + self._managed_qubits: set[cirq.Qid] = set() - def qalloc(self, n: int, dim: int = 2) -> List['cirq.Qid']: - ret: List['cirq.Qid'] = [] - qubits_to_free: List['cirq.Qid'] = [] + def qalloc(self, n: int, dim: int = 2) -> list['cirq.Qid']: + ret: list['cirq.Qid'] = [] + qubits_to_free: list['cirq.Qid'] = [] while len(ret) < n: new_alloc = self._qm.qalloc(n - len(ret), dim) for q in new_alloc: @@ -40,9 +41,9 @@ def qalloc(self, n: int, dim: int = 2) -> List['cirq.Qid']: self._qm.qfree(qubits_to_free) return ret - def qborrow(self, n: int, dim: int = 2) -> List['cirq.Qid']: - ret: List['cirq.Qid'] = [] - qubits_to_free: List['cirq.Qid'] = [] + def qborrow(self, n: int, dim: int = 2) -> list['cirq.Qid']: + ret: list['cirq.Qid'] = [] + qubits_to_free: list['cirq.Qid'] = [] while len(ret) < n: new_alloc = self._qm.qborrow(n - len(ret), dim) for q in new_alloc: diff --git a/qualtran/cirq_interop/jupyter_tools.py b/qualtran/cirq_interop/jupyter_tools.py index fab86169ce..d5db181831 100644 --- a/qualtran/cirq_interop/jupyter_tools.py +++ b/qualtran/cirq_interop/jupyter_tools.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable from pathlib import Path -from typing import Iterable import cirq import cirq.contrib.svg.svg as ccsvg diff --git a/qualtran/cirq_interop/t_complexity_protocol.py b/qualtran/cirq_interop/t_complexity_protocol.py index 64e3da56f3..e0ebe954d1 100644 --- a/qualtran/cirq_interop/t_complexity_protocol.py +++ b/qualtran/cirq_interop/t_complexity_protocol.py @@ -11,7 +11,8 @@ # 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 typing import Any, Callable, Iterable, Optional, Union +from collections.abc import Callable, Iterable +from typing import Any, Optional, Union import attrs import cachetools diff --git a/qualtran/cirq_interop/testing.py b/qualtran/cirq_interop/testing.py index 203207f759..00ab8e714f 100644 --- a/qualtran/cirq_interop/testing.py +++ b/qualtran/cirq_interop/testing.py @@ -12,9 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Sequence from dataclasses import dataclass from functools import cached_property -from typing import Any, Dict, List, Sequence, Tuple +from typing import Any import cirq import numpy as np @@ -46,12 +47,12 @@ def r(self) -> Signature: return self.gate.signature @cached_property - def quregs(self) -> Dict[str, NDArray[cirq.Qid]]: # type: ignore[type-var] + def quregs(self) -> dict[str, NDArray[cirq.Qid]]: # type: ignore[type-var] """A dictionary of named qubits appropriate for the signature for the gate.""" return get_named_qubits(self.r) @cached_property - def all_qubits(self) -> List[cirq.Qid]: + def all_qubits(self) -> list[cirq.Qid]: """All qubits in Register order.""" merged_qubits = merge_qubits(self.r, **self.quregs) decomposed_qubits = self.decomposed_circuit.all_qubits() @@ -101,7 +102,7 @@ def get_circuit_inp_out_cirqsim( inputs: Sequence[int], outputs: Sequence[int], decimals: int = 2, -) -> Tuple[str, str]: +) -> tuple[str, str]: """Use a Cirq simulator to get a outputs of a `circuit`. Args: diff --git a/qualtran/cirq_interop/testing_test.py b/qualtran/cirq_interop/testing_test.py index cc35f145ea..b12fe081fe 100644 --- a/qualtran/cirq_interop/testing_test.py +++ b/qualtran/cirq_interop/testing_test.py @@ -11,7 +11,7 @@ # 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 typing import Iterator +from collections.abc import Iterator import cirq import numpy as np diff --git a/qualtran/drawing/_show_funcs.py b/qualtran/drawing/_show_funcs.py index 932a78ad69..23e3dda336 100644 --- a/qualtran/drawing/_show_funcs.py +++ b/qualtran/drawing/_show_funcs.py @@ -15,7 +15,8 @@ """Convenience functions for showing rich displays in Jupyter notebook.""" import os -from typing import Dict, Optional, overload, Sequence, TYPE_CHECKING, Union +from collections.abc import Sequence +from typing import Optional, overload, TYPE_CHECKING, Union import IPython.display import ipywidgets @@ -123,7 +124,7 @@ def show_call_graph( IPython.display.display(GraphvizCallGraph(item).get_svg()) -def show_counts_sigma(sigma: Dict['Bloq', Union[int, 'sympy.Expr']]): +def show_counts_sigma(sigma: dict['Bloq', Union[int, 'sympy.Expr']]): """Display nicely formatted bloq counts sums `sigma`.""" IPython.display.display(IPython.display.Markdown(format_counts_sigma(sigma))) diff --git a/qualtran/drawing/bloq_counts_graph.py b/qualtran/drawing/bloq_counts_graph.py index bfbeea4cab..78de6ba734 100644 --- a/qualtran/drawing/bloq_counts_graph.py +++ b/qualtran/drawing/bloq_counts_graph.py @@ -16,7 +16,8 @@ import abc import html import warnings -from typing import Any, cast, Dict, Mapping, Optional, TYPE_CHECKING, Union +from collections.abc import Mapping +from typing import Any, cast, Optional, TYPE_CHECKING, Union import IPython.display import networkx as nx @@ -33,7 +34,7 @@ class _CallGraphDrawerBase(metaclass=abc.ABCMeta): def __init__(self, g: nx.DiGraph): self.g = g - self._ids: Dict[Bloq, str] = {} + self._ids: dict[Bloq, str] = {} self._i = 0 def get_id(self, b: Bloq) -> str: @@ -126,7 +127,7 @@ class GraphvizCallGraph(_CallGraphDrawerBase): in each node. The keys and values must support `str()`. """ - def __init__(self, g: nx.DiGraph, bloq_data: Optional[Dict['Bloq', Dict[Any, Any]]] = None): + def __init__(self, g: nx.DiGraph, bloq_data: Optional[dict['Bloq', dict[Any, Any]]] = None): super().__init__(g) if bloq_data is None: @@ -135,7 +136,7 @@ def __init__(self, g: nx.DiGraph, bloq_data: Optional[Dict['Bloq', Dict[Any, Any self.bloq_data = bloq_data @classmethod - def format_qubit_count(cls, val: SymbolicInt) -> Dict[str, str]: + def format_qubit_count(cls, val: SymbolicInt) -> dict[str, str]: """Format `QubitCount` cost values as a string. Args: @@ -147,7 +148,7 @@ def format_qubit_count(cls, val: SymbolicInt) -> Dict[str, str]: return {'Qubits': f'{val}'} @classmethod - def format_qec_gates_cost(cls, val: 'GateCounts', agg: Optional[str] = None) -> Dict[str, str]: + def format_qec_gates_cost(cls, val: 'GateCounts', agg: Optional[str] = None) -> dict[str, str]: """Format `QECGatesCost` cost values as a string. Args: @@ -191,9 +192,9 @@ def format_qec_gates_cost(cls, val: 'GateCounts', agg: Optional[str] = None) -> @classmethod def format_cost_data( cls, - cost_data: Dict['Bloq', Dict['CostKey', 'CostValT']], + cost_data: dict['Bloq', dict['CostKey', 'CostValT']], agg_gate_counts: Optional[str] = None, - ) -> Dict['Bloq', Dict[str, str]]: + ) -> dict['Bloq', dict[str, str]]: """Format `cost_data` as human-readable strings. Args: @@ -211,9 +212,9 @@ class method will delegate to `format_qubit_count` and `format_qec_gates_cost` """ from qualtran.resource_counting import GateCounts, QECGatesCost, QubitCount - disp_data: Dict['Bloq', Dict[str, str]] = {} + disp_data: dict['Bloq', dict[str, str]] = {} for bloq in cost_data.keys(): - bloq_disp: Dict[str, str] = {} + bloq_disp: dict[str, str] = {} for cost_key, cost_val in cost_data[bloq].items(): if isinstance(cost_key, QubitCount): bloq_disp |= cls.format_qubit_count(cast(SymbolicInt, cost_val)) @@ -258,7 +259,7 @@ def from_bloq( from qualtran.resource_counting import QECGatesCost, QubitCount, query_costs call_graph, _ = bloq.call_graph(max_depth=max_depth) - cost_data: Dict['Bloq', Dict[CostKey, Any]] = query_costs( + cost_data: dict['Bloq', dict[CostKey, Any]] = query_costs( bloq, [QubitCount(), QECGatesCost()] ) formatted_cost_data = cls.format_cost_data(cost_data, agg_gate_counts=agg_gate_counts) @@ -314,7 +315,7 @@ def format_counts_graph_markdown(graph: nx.DiGraph) -> str: return m -def format_counts_sigma(sigma: Dict[Bloq, Union[int, sympy.Expr]]) -> str: +def format_counts_sigma(sigma: dict[Bloq, Union[int, sympy.Expr]]) -> str: """Format `sigma` as markdown.""" lines = [f' - {_format_bloq_expr_markdown(bloq, expr)}' for bloq, expr in sigma.items()] lines.sort() diff --git a/qualtran/drawing/bloq_counts_graph_test.py b/qualtran/drawing/bloq_counts_graph_test.py index e95e9f194f..2d3b6fa8e8 100644 --- a/qualtran/drawing/bloq_counts_graph_test.py +++ b/qualtran/drawing/bloq_counts_graph_test.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. import random -from typing import List import networkx as nx @@ -46,7 +45,7 @@ def test_format_counts_graph_markdown(): ) -def _get_node_labels_from_pydot_graph(drawer: _CallGraphDrawerBase) -> List[str]: +def _get_node_labels_from_pydot_graph(drawer: _CallGraphDrawerBase) -> list[str]: graph = drawer.get_graph() node_labels = [node.get_label() for node in graph.get_node_list()] # type: ignore[attr-defined] random.shuffle(node_labels) # don't rely on order of graphviz nodes diff --git a/qualtran/drawing/classical_sim_graph.py b/qualtran/drawing/classical_sim_graph.py index a816c62cee..f465369250 100644 --- a/qualtran/drawing/classical_sim_graph.py +++ b/qualtran/drawing/classical_sim_graph.py @@ -14,7 +14,7 @@ """Classes for drawing classical data flows with Graphviz.""" -from typing import Dict, TYPE_CHECKING +from typing import TYPE_CHECKING import pydot @@ -36,7 +36,7 @@ class ClassicalSimGraphDrawer(PrettyGraphDrawer): vals: Input classical values to propogate through the composite bloq. """ - def __init__(self, bloq: Bloq, vals: Dict[str, 'ClassicalValT']): + def __init__(self, bloq: Bloq, vals: dict[str, 'ClassicalValT']): super().__init__(bloq=bloq) from qualtran.simulation.classical_sim import call_cbloq_classically diff --git a/qualtran/drawing/flame_graph.py b/qualtran/drawing/flame_graph.py index 7546f69912..a583491b05 100644 --- a/qualtran/drawing/flame_graph.py +++ b/qualtran/drawing/flame_graph.py @@ -17,7 +17,8 @@ import pathlib import subprocess import tempfile -from typing import Any, Callable, List, Optional, Union +from collections.abc import Callable +from typing import Any, Optional, Union import networkx as nx import numpy as np @@ -71,7 +72,7 @@ def _keep_if_small(bloq: Bloq) -> bool: return False -def _is_leaf_node(callees: List[Bloq]) -> bool: +def _is_leaf_node(callees: list[Bloq]) -> bool: from qualtran.bloqs.basic_gates import TGate return len(callees) == 0 or ( @@ -80,8 +81,8 @@ def _is_leaf_node(callees: List[Bloq]) -> bool: def _populate_flame_graph_data( - bloq: Bloq, graph: nx.DiGraph, graph_t: nx.DiGraph, prefix: List[str] -) -> List[str]: + bloq: Bloq, graph: nx.DiGraph, graph_t: nx.DiGraph, prefix: list[str] +) -> list[str]: """Populates data for the flame graph. Args: @@ -128,7 +129,7 @@ def get_flame_graph_data( file_path: Union[None, pathlib.Path, str] = None, keep: Optional[Callable[['Bloq'], bool]] = _keep_if_small, **kwargs, -) -> List[str]: +) -> list[str]: """Get the flame graph data for visualizing T-costs distribution of a sequence of bloqs. For each bloq in the input, this will do a DFS ordering over all edges in the DAG and diff --git a/qualtran/drawing/graphviz.py b/qualtran/drawing/graphviz.py index 64f4faee09..faeba6bc85 100644 --- a/qualtran/drawing/graphviz.py +++ b/qualtran/drawing/graphviz.py @@ -15,7 +15,8 @@ """Classes for drawing bloqs with Graphviz.""" import html import itertools -from typing import Any, Dict, Iterable, List, Optional, Set, Tuple +from collections.abc import Iterable +from typing import Any, Optional import IPython.display import pydot @@ -38,7 +39,7 @@ def _assign_ids_to_bloqs_and_soqs( bloq_instances: Iterable[BloqInstance], all_soquets: Iterable[Soquet] -) -> Dict[Any, str]: +) -> dict[Any, str]: """Assign unique identifiers to bloq instances, soquets, and register groups. Graphviz is very forgiving in its input format. If you accidentally introduce a new id (e.g. @@ -53,8 +54,8 @@ def _assign_ids_to_bloqs_and_soqs( shared names (but differing `side` attributes) are implicitly grouped. 3) Each Soquet in `all_soquets`. """ - to_id: Dict[Any, str] = {} - ids: Set[str] = set() + to_id: dict[Any, str] = {} + ids: set[str] = set() disambiguator = 0 def add(item: Any, desired_id: str): @@ -85,7 +86,7 @@ def add(item: Any, desired_id: str): def _parition_registers_in_a_group( regs: Iterable[Register], binst: BloqInstance -) -> Tuple[List[Soquet], List[Soquet], List[Soquet]]: +) -> tuple[list[Soquet], list[Soquet], list[Soquet]]: """Construct and sort the expected Soquets for a given register group. Since we expect the input registers to be in a group, we assert that diff --git a/qualtran/drawing/musical_score.py b/qualtran/drawing/musical_score.py index 065f2312c4..042e6f3a94 100644 --- a/qualtran/drawing/musical_score.py +++ b/qualtran/drawing/musical_score.py @@ -21,8 +21,9 @@ import abc import heapq import json +from collections.abc import Callable, Iterable from enum import Enum -from typing import Any, Callable, cast, Dict, Iterable, List, Optional, Set, Tuple, Union +from typing import Any, cast, Optional, Union import attrs import networkx as nx @@ -102,7 +103,7 @@ class HLine: seq_x_end: Optional[int] = None flavor: HLineFlavor = HLineFlavor.QUANTUM - def json_dict(self) -> Dict[str, Any]: + def json_dict(self) -> dict[str, Any]: d = attrs.asdict(self) d['flavor'] = str(d['flavor']) return d @@ -114,8 +115,8 @@ class LineManager: def __init__(self, max_n_lines: int = 100): self.available = list(range(max_n_lines)) heapq.heapify(self.available) - self.hlines: Set[HLine] = set() - self._reserved: List[Tuple[List[int], Callable]] = [] + self.hlines: set[HLine] = set() + self._reserved: list[tuple[list[int], Callable]] = [] def new_y(self, binst: BloqInstance, reg: Register, idx=None): """Allocate a new y position (i.e. a new qubit or register).""" @@ -145,7 +146,7 @@ def unreserve(self, binst: BloqInstance, reg: Register): self._reserved = kept def maybe_reserve( - self, binst: Union[DanglingT, BloqInstance], reg: Register, idx: Tuple[int, ...] + self, binst: Union[DanglingT, BloqInstance], reg: Register, idx: tuple[int, ...] ): """Override this method to provide custom control over line allocation. @@ -218,7 +219,7 @@ def free( def _get_in_vals( - binst: Union[DanglingT, BloqInstance], reg: Register, soq_assign: Dict[Soquet, RegPosition] + binst: Union[DanglingT, BloqInstance], reg: Register, soq_assign: dict[Soquet, RegPosition] ) -> Union[RegPosition, NDArray[RegPosition]]: """Pluck out the correct values from `soq_assign` for `reg` on `binst`.""" if not reg.shape: @@ -235,8 +236,8 @@ def _get_in_vals( def _update_assign_from_vals( regs: Iterable[Register], binst: Union[DanglingT, BloqInstance], - vals: Dict[str, RegPosition], - soq_assign: Dict[Soquet, RegPosition], + vals: dict[str, RegPosition], + soq_assign: dict[Soquet, RegPosition], seq_x: int, topo_gen: int, manager: LineManager, @@ -274,7 +275,7 @@ def _update_assign_from_vals( def _binst_assign_line( binst: BloqInstance, pred_cxns: Iterable[Connection], - soq_assign: Dict[Soquet, RegPosition], + soq_assign: dict[Soquet, RegPosition], seq_x: int, topo_gen: int, manager: LineManager, @@ -324,7 +325,7 @@ def _in_vals(reg: Register): def _cbloq_musical_score( signature: Signature, binst_graph: nx.DiGraph, manager: Optional[LineManager] = None -) -> Tuple[Dict[str, RegPosition], Dict[Soquet, RegPosition], LineManager]: +) -> tuple[dict[str, RegPosition], dict[Soquet, RegPosition], LineManager]: """Assign musical score positions through a composite bloq's contents. Args: @@ -341,7 +342,7 @@ def _cbloq_musical_score( # Keep track of each soquet's position. Initialize by implicitly allocating new positions. # We introduce the convention that `LeftDangle`s are a seq_x=-1 and topo_gen=0 - soq_assign: Dict[Soquet, RegPosition] = {} + soq_assign: dict[Soquet, RegPosition] = {} topo_gen = 0 _update_assign_from_vals( signature.lefts(), LeftDangle, {}, soq_assign, seq_x=-1, topo_gen=topo_gen, manager=manager @@ -392,7 +393,7 @@ def adjoint(self) -> 'WireSymbol': """Return a symbol that is the adjoint of this.""" return self - def json_dict(self) -> Dict[str, Any]: + def json_dict(self) -> dict[str, Any]: return {'symb_cls': self.__class__.__name__, 'symb_attributes': attrs.asdict(self)} @@ -572,9 +573,9 @@ class MusicalScoreData: max_x: int max_y: int - soqs: List[SoqData] - hlines: List[HLine] - vlines: List[VLine] + soqs: list[SoqData] + hlines: list[HLine] + vlines: list[VLine] def json_dict(self): return attrs.asdict(self, recurse=False) diff --git a/qualtran/drawing/qpic_diagram.py b/qualtran/drawing/qpic_diagram.py index 389876fa3f..263af3579c 100644 --- a/qualtran/drawing/qpic_diagram.py +++ b/qualtran/drawing/qpic_diagram.py @@ -24,7 +24,7 @@ import subprocess import tempfile from collections import defaultdict -from typing import Dict, List, Optional, Set, Tuple, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union from qualtran import DanglingT, LeftDangle, QBit, RightDangle, Side, Soquet from qualtran.drawing.musical_score import ( @@ -99,16 +99,16 @@ class QpicWireManager: """ def __init__(self): - self._soq_to_wire_name_tuple: Dict[Soquet, Tuple[str, int]] = {} - self._alloc_wires_with_prefix: Dict[str, Set[int]] = defaultdict(set) + self._soq_to_wire_name_tuple: dict[Soquet, tuple[str, int]] = {} + self._alloc_wires_with_prefix: dict[str, set[int]] = defaultdict(set) - def _wire_name_tuple_for_soq(self, soq: Soquet) -> Tuple[str, int]: + def _wire_name_tuple_for_soq(self, soq: Soquet) -> tuple[str, int]: prefix = _wire_name_prefix_for_soq(soq) allocated_suffixes = self._alloc_wires_with_prefix[prefix] next_i = next(i for i in range(len(allocated_suffixes) + 1) if i not in allocated_suffixes) return prefix, next_i - def _wire_name_tuple_to_str(self, wire_name: Tuple[str, int]) -> str: + def _wire_name_tuple_to_str(self, wire_name: tuple[str, int]) -> str: prefix, i = wire_name return prefix + '_' + str(i) if i else prefix @@ -169,10 +169,10 @@ def add_right_wires_for_signature(self, signature: 'Signature') -> None: self.gates += ['LABEL length=10'] @property - def data(self) -> List[str]: + def data(self) -> list[str]: return self.wires + self.gates - def _add_soq(self, soq: Soquet) -> Tuple[str, Optional[str]]: + def _add_soq(self, soq: Soquet) -> tuple[str, Optional[str]]: symbol = _soq_to_symb(soq) suffix = '' wire = self.wire_manager.soq_to_wirename(self.soq_map[soq]) @@ -200,7 +200,7 @@ def _dealloc_wire_for_soq(self, soq: Soquet) -> None: self.soq_map.pop(soq) @classmethod - def _dtype_label_for_wire(cls, wire_name: str, dtype: 'QCDType') -> List[str]: + def _dtype_label_for_wire(cls, wire_name: str, dtype: 'QCDType') -> list[str]: if dtype != QBit(): dtype_str = _format_label_text(str(dtype), scale=0.5) return [f'{wire_name} / {dtype_str}'] @@ -241,7 +241,7 @@ def _add_bloq_with_no_wire(self, bloq: 'Bloq'): width = _gate_width_for_text(gate_text) self.gates += [f'{self.empty_wire} G:width={width}:shape=8 {gate_text}'] - def add_bloq(self, bloq: 'Bloq', pred: List['Connection'], succ: List['Connection']) -> None: + def add_bloq(self, bloq: 'Bloq', pred: list['Connection'], succ: list['Connection']) -> None: controls, targets, wire_dtype_labels = [], [], [] if not (pred or succ): @@ -270,7 +270,7 @@ def add_soq(soq: Soquet): self.gates += wire_dtype_labels -def get_qpic_data(bloq: 'Bloq', file_path: Union[None, pathlib.Path, str] = None) -> List[str]: +def get_qpic_data(bloq: 'Bloq', file_path: Union[None, pathlib.Path, str] = None) -> list[str]: """Get the input data that can be used to draw a latex diagram for `bloq` using `qpic`. Args: diff --git a/qualtran/linalg/lcu_util.py b/qualtran/linalg/lcu_util.py index fea17c03d3..b21fe05df4 100644 --- a/qualtran/linalg/lcu_util.py +++ b/qualtran/linalg/lcu_util.py @@ -15,7 +15,8 @@ """Utility methods for LCU circuits as implemented in https://github.com/quantumlib/OpenFermion""" import math -from typing import Optional, overload, Sequence +from collections.abc import Sequence +from typing import Optional, overload from qualtran.symbolics import ceil, is_symbolic, log2, SymbolicFloat, SymbolicInt diff --git a/qualtran/linalg/permutation.py b/qualtran/linalg/permutation.py index 2655f6e612..fee5e60fdc 100644 --- a/qualtran/linalg/permutation.py +++ b/qualtran/linalg/permutation.py @@ -11,7 +11,8 @@ # 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 typing import Iterator, Sequence, TypeAlias +from collections.abc import Iterator, Sequence +from typing import TypeAlias CycleT: TypeAlias = tuple[int, ...] diff --git a/qualtran/linalg/polynomial/basic.py b/qualtran/linalg/polynomial/basic.py index 2251b9c733..17013cf9af 100644 --- a/qualtran/linalg/polynomial/basic.py +++ b/qualtran/linalg/polynomial/basic.py @@ -11,7 +11,7 @@ # 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 typing import Sequence +from collections.abc import Sequence import numpy as np from numpy.typing import NDArray diff --git a/qualtran/linalg/polynomial/qsp_testing.py b/qualtran/linalg/polynomial/qsp_testing.py index 496822c4e2..a4a0c52641 100644 --- a/qualtran/linalg/polynomial/qsp_testing.py +++ b/qualtran/linalg/polynomial/qsp_testing.py @@ -11,7 +11,8 @@ # 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 typing import Sequence, Union +from collections.abc import Sequence +from typing import Union import numpy as np from numpy.polynomial import Polynomial diff --git a/qualtran/protos/bloq_pb2.pyi b/qualtran/protos/bloq_pb2.pyi index b3481a7aab..6b06b48a9e 100644 --- a/qualtran/protos/bloq_pb2.pyi +++ b/qualtran/protos/bloq_pb2.pyi @@ -18,6 +18,7 @@ limitations under the License. """ import builtins import collections.abc +import typing import google.protobuf.descriptor import google.protobuf.internal.containers import google.protobuf.message @@ -28,16 +29,10 @@ import qualtran.protos.data_types_pb2 import qualtran.protos.ec_point_pb2 import qualtran.protos.registers_pb2 import qualtran.protos.sympy_pb2 -import sys - -if sys.version_info >= (3, 8): - import typing as typing_extensions -else: - import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor -@typing_extensions.final +@typing.final class BloqArg(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor @@ -104,13 +99,13 @@ class BloqArg(google.protobuf.message.Message): complex_val: qualtran.protos.args_pb2.Complex | None = ..., ec_point: qualtran.protos.ec_point_pb2.ECPoint | None = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["cirq_json_gzip", b"cirq_json_gzip", "complex_val", b"complex_val", "ctrl_spec", b"ctrl_spec", "ec_point", b"ec_point", "float_val", b"float_val", "int_val", b"int_val", "ndarray", b"ndarray", "qdata_type", b"qdata_type", "register", b"register", "registers", b"registers", "string_val", b"string_val", "subbloq", b"subbloq", "sympy_expr", b"sympy_expr", "val", b"val"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["cirq_json_gzip", b"cirq_json_gzip", "complex_val", b"complex_val", "ctrl_spec", b"ctrl_spec", "ec_point", b"ec_point", "float_val", b"float_val", "int_val", b"int_val", "name", b"name", "ndarray", b"ndarray", "qdata_type", b"qdata_type", "register", b"register", "registers", b"registers", "string_val", b"string_val", "subbloq", b"subbloq", "sympy_expr", b"sympy_expr", "val", b"val"]) -> None: ... - def WhichOneof(self, oneof_group: typing_extensions.Literal["val", b"val"]) -> typing_extensions.Literal["int_val", "float_val", "string_val", "sympy_expr", "ndarray", "subbloq", "cirq_json_gzip", "qdata_type", "register", "registers", "ctrl_spec", "complex_val", "ec_point"] | None: ... + def HasField(self, field_name: typing.Literal["cirq_json_gzip", b"cirq_json_gzip", "complex_val", b"complex_val", "ctrl_spec", b"ctrl_spec", "ec_point", b"ec_point", "float_val", b"float_val", "int_val", b"int_val", "ndarray", b"ndarray", "qdata_type", b"qdata_type", "register", b"register", "registers", b"registers", "string_val", b"string_val", "subbloq", b"subbloq", "sympy_expr", b"sympy_expr", "val", b"val"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["cirq_json_gzip", b"cirq_json_gzip", "complex_val", b"complex_val", "ctrl_spec", b"ctrl_spec", "ec_point", b"ec_point", "float_val", b"float_val", "int_val", b"int_val", "name", b"name", "ndarray", b"ndarray", "qdata_type", b"qdata_type", "register", b"register", "registers", b"registers", "string_val", b"string_val", "subbloq", b"subbloq", "sympy_expr", b"sympy_expr", "val", b"val"]) -> None: ... + def WhichOneof(self, oneof_group: typing.Literal["val", b"val"]) -> typing.Literal["int_val", "float_val", "string_val", "sympy_expr", "ndarray", "subbloq", "cirq_json_gzip", "qdata_type", "register", "registers", "ctrl_spec", "complex_val", "ec_point"] | None: ... global___BloqArg = BloqArg -@typing_extensions.final +@typing.final class BloqLibrary(google.protobuf.message.Message): """A library of Bloqs. BloqLibrary should be used to represent both primitive Bloqs and composite Bloqs; i.e. Bloqs consisting of other subbloqs, like `CompositeBloq`, @@ -119,13 +114,13 @@ class BloqLibrary(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor - @typing_extensions.final + @typing.final class BloqWithDecomposition(google.protobuf.message.Message): """Decompositions are specified using integer IDs referencing other Bloqs within this library.""" DESCRIPTOR: google.protobuf.descriptor.Descriptor - @typing_extensions.final + @typing.final class BloqCountsEntry(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor @@ -140,8 +135,8 @@ class BloqLibrary(google.protobuf.message.Message): key: builtins.int = ..., value: qualtran.protos.args_pb2.IntOrSympy | None = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["value", b"value"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ... + def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... BLOQ_ID_FIELD_NUMBER: builtins.int DECOMPOSITION_FIELD_NUMBER: builtins.int @@ -166,8 +161,8 @@ class BloqLibrary(google.protobuf.message.Message): bloq_counts: collections.abc.Mapping[builtins.int, qualtran.protos.args_pb2.IntOrSympy] | None = ..., bloq: global___Bloq | None = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["bloq", b"bloq"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["bloq", b"bloq", "bloq_counts", b"bloq_counts", "bloq_id", b"bloq_id", "decomposition", b"decomposition"]) -> None: ... + def HasField(self, field_name: typing.Literal["bloq", b"bloq"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["bloq", b"bloq", "bloq_counts", b"bloq_counts", "bloq_id", b"bloq_id", "decomposition", b"decomposition"]) -> None: ... NAME_FIELD_NUMBER: builtins.int TABLE_FIELD_NUMBER: builtins.int @@ -181,11 +176,11 @@ class BloqLibrary(google.protobuf.message.Message): name: builtins.str = ..., table: collections.abc.Iterable[global___BloqLibrary.BloqWithDecomposition] | None = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "table", b"table"]) -> None: ... + def ClearField(self, field_name: typing.Literal["name", b"name", "table", b"table"]) -> None: ... global___BloqLibrary = BloqLibrary -@typing_extensions.final +@typing.final class Bloq(google.protobuf.message.Message): """Messages to enable efficient description of a BloqLibrary, including Bloq decompositions in terms of other simpler bloqs. @@ -218,12 +213,12 @@ class Bloq(google.protobuf.message.Message): registers: qualtran.protos.registers_pb2.Registers | None = ..., t_complexity: qualtran.protos.annotations_pb2.TComplexity | None = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["registers", b"registers", "t_complexity", b"t_complexity"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["args", b"args", "name", b"name", "registers", b"registers", "t_complexity", b"t_complexity"]) -> None: ... + def HasField(self, field_name: typing.Literal["registers", b"registers", "t_complexity", b"t_complexity"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["args", b"args", "name", b"name", "registers", b"registers", "t_complexity", b"t_complexity"]) -> None: ... global___Bloq = Bloq -@typing_extensions.final +@typing.final class BloqInstance(google.protobuf.message.Message): """Specific instance of a Bloq.""" @@ -239,11 +234,11 @@ class BloqInstance(google.protobuf.message.Message): instance_id: builtins.int = ..., bloq_id: builtins.int = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["bloq_id", b"bloq_id", "instance_id", b"instance_id"]) -> None: ... + def ClearField(self, field_name: typing.Literal["bloq_id", b"bloq_id", "instance_id", b"instance_id"]) -> None: ... global___BloqInstance = BloqInstance -@typing_extensions.final +@typing.final class Soquet(google.protobuf.message.Message): """One half of a connection.""" @@ -268,13 +263,13 @@ class Soquet(google.protobuf.message.Message): register: qualtran.protos.registers_pb2.Register | None = ..., index: collections.abc.Iterable[builtins.int] | None = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["binst", b"binst", "bloq_instance", b"bloq_instance", "dangling_t", b"dangling_t", "register", b"register"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["binst", b"binst", "bloq_instance", b"bloq_instance", "dangling_t", b"dangling_t", "index", b"index", "register", b"register"]) -> None: ... - def WhichOneof(self, oneof_group: typing_extensions.Literal["binst", b"binst"]) -> typing_extensions.Literal["bloq_instance", "dangling_t"] | None: ... + def HasField(self, field_name: typing.Literal["binst", b"binst", "bloq_instance", b"bloq_instance", "dangling_t", b"dangling_t", "register", b"register"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["binst", b"binst", "bloq_instance", b"bloq_instance", "dangling_t", b"dangling_t", "index", b"index", "register", b"register"]) -> None: ... + def WhichOneof(self, oneof_group: typing.Literal["binst", b"binst"]) -> typing.Literal["bloq_instance", "dangling_t"] | None: ... global___Soquet = Soquet -@typing_extensions.final +@typing.final class Connection(google.protobuf.message.Message): """A connection between two Soquets. Quantum compute graph can be represented as a list of connections. @@ -294,7 +289,7 @@ class Connection(google.protobuf.message.Message): left: global___Soquet | None = ..., right: global___Soquet | None = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["left", b"left", "right", b"right"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["left", b"left", "right", b"right"]) -> None: ... + def HasField(self, field_name: typing.Literal["left", b"left", "right", b"right"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["left", b"left", "right", b"right"]) -> None: ... global___Connection = Connection diff --git a/qualtran/protos/ec_point_pb2.pyi b/qualtran/protos/ec_point_pb2.pyi index ac82158cd6..bfe37949c1 100644 --- a/qualtran/protos/ec_point_pb2.pyi +++ b/qualtran/protos/ec_point_pb2.pyi @@ -14,19 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. """ import builtins +import typing import google.protobuf.descriptor import google.protobuf.message import qualtran.protos.args_pb2 -import sys - -if sys.version_info >= (3, 8): - import typing as typing_extensions -else: - import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor -@typing_extensions.final +@typing.final class ECPoint(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor @@ -50,8 +45,8 @@ class ECPoint(google.protobuf.message.Message): mod: qualtran.protos.args_pb2.IntOrSympy | None = ..., curve_a: qualtran.protos.args_pb2.IntOrSympy | None = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal["_curve_a", b"_curve_a", "curve_a", b"curve_a", "mod", b"mod", "x", b"x", "y", b"y"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal["_curve_a", b"_curve_a", "curve_a", b"curve_a", "mod", b"mod", "x", b"x", "y", b"y"]) -> None: ... - def WhichOneof(self, oneof_group: typing_extensions.Literal["_curve_a", b"_curve_a"]) -> typing_extensions.Literal["curve_a"] | None: ... + def HasField(self, field_name: typing.Literal["_curve_a", b"_curve_a", "curve_a", b"curve_a", "mod", b"mod", "x", b"x", "y", b"y"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["_curve_a", b"_curve_a", "curve_a", b"curve_a", "mod", b"mod", "x", b"x", "y", b"y"]) -> None: ... + def WhichOneof(self, oneof_group: typing.Literal["_curve_a", b"_curve_a"]) -> typing.Literal["curve_a"] | None: ... global___ECPoint = ECPoint diff --git a/qualtran/protos/registers_pb2.pyi b/qualtran/protos/registers_pb2.pyi index e51a9bf096..b3e3f1823b 100644 --- a/qualtran/protos/registers_pb2.pyi +++ b/qualtran/protos/registers_pb2.pyi @@ -19,19 +19,13 @@ limitations under the License. import builtins import collections.abc +import typing import google.protobuf.descriptor import google.protobuf.internal.containers import google.protobuf.internal.enum_type_wrapper import google.protobuf.message import qualtran.protos.args_pb2 import qualtran.protos.data_types_pb2 -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor @@ -41,7 +35,7 @@ class Register(google.protobuf.message.Message): class _Side: ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType + V: typing.TypeAlias = ValueType class _SideEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[Register._Side.ValueType], builtins.type): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor diff --git a/qualtran/protos/sympy_pb2.pyi b/qualtran/protos/sympy_pb2.pyi index 868aae3c3f..48931283ec 100644 --- a/qualtran/protos/sympy_pb2.pyi +++ b/qualtran/protos/sympy_pb2.pyi @@ -19,23 +19,17 @@ limitations under the License. import builtins import collections.abc +import typing import google.protobuf.descriptor import google.protobuf.internal.containers import google.protobuf.internal.enum_type_wrapper import google.protobuf.message -import sys -import typing - -if sys.version_info >= (3, 10): - import typing as typing_extensions -else: - import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor class _Function: ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType + V: typing.TypeAlias = ValueType class _FunctionEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_Function.ValueType], builtins.type): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor @@ -81,7 +75,7 @@ global___Function = Function class _ConstSymbol: ValueType = typing.NewType("ValueType", builtins.int) - V: typing_extensions.TypeAlias = ValueType + V: typing.TypeAlias = ValueType class _ConstSymbolEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ConstSymbol.ValueType], builtins.type): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor diff --git a/qualtran/qref_interop/_bloq_to_qref.py b/qualtran/qref_interop/_bloq_to_qref.py index aab3422ba1..0480a6335e 100644 --- a/qualtran/qref_interop/_bloq_to_qref.py +++ b/qualtran/qref_interop/_bloq_to_qref.py @@ -24,8 +24,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from collections.abc import Iterable from functools import singledispatch -from typing import Any, cast, Iterable, Optional, Union +from typing import Any, cast, Optional, Union import networkx as nx import sympy diff --git a/qualtran/resource_counting/_bloq_counts.py b/qualtran/resource_counting/_bloq_counts.py index 3ed9a4a10a..1c680a2232 100644 --- a/qualtran/resource_counting/_bloq_counts.py +++ b/qualtran/resource_counting/_bloq_counts.py @@ -14,7 +14,8 @@ import logging import warnings from collections import defaultdict -from typing import Callable, cast, Dict, Sequence, Tuple, TYPE_CHECKING +from collections.abc import Callable, Sequence +from typing import cast, TYPE_CHECKING import attrs import networkx as nx @@ -38,10 +39,10 @@ logger = logging.getLogger(__name__) -BloqCountDict = Dict['Bloq', int] +BloqCountDict = dict['Bloq', int] -def _gateset_bloqs_to_tuple(bloqs: Sequence['Bloq']) -> Tuple['Bloq', ...]: +def _gateset_bloqs_to_tuple(bloqs: Sequence['Bloq']) -> tuple['Bloq', ...]: return tuple(bloqs) @@ -74,7 +75,7 @@ def for_gateset(cls, gateset_name: str): """ from qualtran.bloqs.basic_gates import TGate, Toffoli, TwoBitCSwap - bloqs: Tuple['Bloq', ...] + bloqs: tuple['Bloq', ...] if gateset_name == 't': bloqs = (TGate(), TGate(is_adjoint=True)) elif gateset_name == 't+tof': @@ -172,7 +173,7 @@ def __str__(self): return ', '.join(strs) return '-' - def asdict(self) -> Dict[str, int]: + def asdict(self) -> dict[str, int]: d = attrs.asdict(self) def _is_nonzero(v): @@ -206,7 +207,7 @@ def total_t_count( + ts_per_rotation * self.rotation ) - def total_t_and_ccz_count(self, ts_per_rotation: int = 11) -> Dict[str, SymbolicInt]: + def total_t_and_ccz_count(self, ts_per_rotation: int = 11) -> dict[str, SymbolicInt]: n_ccz = self.toffoli + self.cswap + self.and_bloq n_t = self.t + ts_per_rotation * self.rotation return {'n_t': n_t, 'n_ccz': n_ccz} @@ -257,7 +258,7 @@ def to_legacy_t_complexity( + cliffords_per_cswap * self.cswap, ) - def total_beverland_count(self) -> Dict[str, SymbolicInt]: + def total_beverland_count(self) -> dict[str, SymbolicInt]: r"""Counts used by Beverland et al. using notation from the reference. - $M_\mathrm{meas}$ is the number of measurements. diff --git a/qualtran/resource_counting/_call_graph.py b/qualtran/resource_counting/_call_graph.py index 8c1a6debd8..79ebebe0bd 100644 --- a/qualtran/resource_counting/_call_graph.py +++ b/qualtran/resource_counting/_call_graph.py @@ -14,30 +14,17 @@ """Functionality for the `Bloq.call_graph()` protocol.""" -import collections.abc import warnings from collections import defaultdict -from typing import ( - Callable, - cast, - Dict, - Iterable, - List, - Mapping, - MutableMapping, - Optional, - Sequence, - Set, - Tuple, - Union, -) +from collections.abc import Callable, Iterable, Mapping, MutableMapping, Sequence +from typing import cast, Optional, Union import networkx as nx import sympy from qualtran import Bloq, CompositeBloq, DecomposeNotImplementedError, DecomposeTypeError -BloqCountT = Tuple[Bloq, Union[int, sympy.Expr]] +BloqCountT = tuple[Bloq, Union[int, sympy.Expr]] BloqCountDictT = Mapping[Bloq, Union[int, sympy.Expr]] MutableBloqCountDictT = MutableMapping[Bloq, Union[int, sympy.Expr]] from ._generalization import _make_composite_generalizer, GeneralizerT @@ -60,7 +47,7 @@ class SympySymbolAllocator: """ def __init__(self): - self._idxs: Dict[str, int] = defaultdict(lambda: 0) + self._idxs: dict[str, int] = defaultdict(lambda: 0) def new_symbol(self, prefix: str) -> sympy.Symbol: """Return a unique symbol beginning with _prefix.""" @@ -77,7 +64,7 @@ def build_cbloq_call_graph(cbloq: CompositeBloq) -> BloqCountDictT: Args: cbloq: The composite bloq. """ - counts: Dict[Bloq, int] = defaultdict(lambda: 0) + counts: dict[Bloq, int] = defaultdict(lambda: 0) for binst in cbloq.bloq_instances: counts[binst.bloq] += 1 @@ -85,14 +72,14 @@ def build_cbloq_call_graph(cbloq: CompositeBloq) -> BloqCountDictT: def _generalize_callees( - raw_callee_counts: Union[BloqCountDictT, Set[BloqCountT]], generalizer: GeneralizerT -) -> List[BloqCountT]: + raw_callee_counts: Union[BloqCountDictT, set[BloqCountT]], generalizer: GeneralizerT +) -> list[BloqCountT]: """Apply `generalizer` to the results of `bloq.build_call_graph`. This calls `generalizer` on each of the callees returned from that function, and filters out cases where `generalizer` returns `None`. """ - callee_counts: Dict[Bloq, Union[int, sympy.Expr]] = defaultdict(lambda: 0) + callee_counts: dict[Bloq, Union[int, sympy.Expr]] = defaultdict(lambda: 0) if isinstance(raw_callee_counts, set): raw_callee_iterator: Iterable[BloqCountT] = raw_callee_counts warnings.warn( @@ -116,7 +103,7 @@ def get_bloq_callee_counts( generalizer: Optional[Union['GeneralizerT', Sequence['GeneralizerT']]] = None, ssa: Optional[SympySymbolAllocator] = None, ignore_decomp_failure: bool = True, -) -> List[BloqCountT]: +) -> list[BloqCountT]: """Get the direct callees of a bloq and the number of times they are called. This calls `bloq.build_call_graph()` with the correct configuration options. @@ -203,9 +190,9 @@ def _build_call_graph( g.add_edge(bloq, callee, n=n) -def _compute_sigma(root_bloq: Bloq, g: nx.DiGraph) -> Dict[Bloq, Union[int, sympy.Expr]]: +def _compute_sigma(root_bloq: Bloq, g: nx.DiGraph) -> dict[Bloq, Union[int, sympy.Expr]]: """Iterate over nodes to sum up the counts of leaf bloqs.""" - bloq_sigmas: Dict[Bloq, Dict[Bloq, Union[int, sympy.Expr]]] = defaultdict( + bloq_sigmas: dict[Bloq, dict[Bloq, Union[int, sympy.Expr]]] = defaultdict( lambda: defaultdict(lambda: 0) ) for bloq in reversed(list(nx.topological_sort(g))): @@ -232,7 +219,7 @@ def get_bloq_call_graph( ssa: Optional[SympySymbolAllocator] = None, keep: Optional[Callable[[Bloq], bool]] = None, max_depth: Optional[int] = None, -) -> Tuple[nx.DiGraph, Dict[Bloq, Union[int, sympy.Expr]]]: +) -> tuple[nx.DiGraph, dict[Bloq, Union[int, sympy.Expr]]]: """Recursively build the bloq call graph and call totals. See `Bloq.call_graph()` as a convenient way of calling this function. @@ -263,7 +250,7 @@ def get_bloq_call_graph( keep = lambda b: False if generalizer is None: generalizer = lambda b: b - if isinstance(generalizer, collections.abc.Sequence): + if isinstance(generalizer, Sequence): generalizer = _make_composite_generalizer(*generalizer) g = nx.DiGraph() diff --git a/qualtran/resource_counting/_call_graph_test.py b/qualtran/resource_counting/_call_graph_test.py index af540e50c0..ac5ff11181 100644 --- a/qualtran/resource_counting/_call_graph_test.py +++ b/qualtran/resource_counting/_call_graph_test.py @@ -13,8 +13,9 @@ # limitations under the License. from collections import defaultdict +from collections.abc import Iterable, Sequence from functools import cached_property -from typing import Dict, Iterable, Optional, Sequence, Tuple +from typing import Optional import attrs import networkx as nx @@ -58,7 +59,7 @@ class DecompBloq(Bloq): def signature(self) -> 'Signature': return Signature.build(x=self.bitsize) - def build_composite_bloq(self, bb: 'BloqBuilder', x: 'Soquet') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', x: 'Soquet') -> dict[str, 'SoquetT']: qs = bb.split(x) for i in range(self.bitsize): qs[i] = bb.add(SubBloq(unrelated_param=i / 12), q=qs[i]) @@ -78,7 +79,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return {TGate(): 3} -def get_big_bloq_counts_graph_1(bloq: Bloq) -> Tuple[nx.DiGraph, Dict[Bloq, SymbolicInt]]: +def get_big_bloq_counts_graph_1(bloq: Bloq) -> tuple[nx.DiGraph, dict[Bloq, SymbolicInt]]: ss = SympySymbolAllocator() n_c = ss.new_symbol('n_c') diff --git a/qualtran/resource_counting/_costing.py b/qualtran/resource_counting/_costing.py index 4200b0acad..627b49dedb 100644 --- a/qualtran/resource_counting/_costing.py +++ b/qualtran/resource_counting/_costing.py @@ -13,21 +13,11 @@ # limitations under the License. import abc -import collections import logging import time from collections import defaultdict -from typing import ( - Callable, - Dict, - Generic, - Iterable, - Optional, - Sequence, - TYPE_CHECKING, - TypeVar, - Union, -) +from collections.abc import Callable, Iterable, Sequence +from typing import Generic, Optional, TYPE_CHECKING, TypeVar, Union from qualtran import CompositeBloq @@ -102,7 +92,7 @@ def _get_cost_value( bloq: 'Bloq', cost_key: CostKey[CostValT], *, - costs_cache: Dict['Bloq', CostValT], + costs_cache: dict['Bloq', CostValT], generalizer: 'GeneralizerT', ) -> CostValT: """Helper function for getting costs. @@ -154,7 +144,7 @@ def _get_cost_val_internal(callee: 'Bloq'): def get_cost_value( bloq: 'Bloq', cost_key: CostKey[CostValT], - costs_cache: Optional[Dict['Bloq', CostValT]] = None, + costs_cache: Optional[dict['Bloq', CostValT]] = None, generalizer: Optional[Union['GeneralizerT', Sequence['GeneralizerT']]] = None, ) -> CostValT: """Compute the specified cost of the provided bloq. @@ -177,7 +167,7 @@ def get_cost_value( costs_cache = {} if generalizer is None: generalizer = lambda b: b - if isinstance(generalizer, collections.abc.Sequence): + if isinstance(generalizer, Sequence): generalizer = _make_composite_generalizer(*generalizer) cost_val = _get_cost_value(bloq, cost_key, costs_cache=costs_cache, generalizer=generalizer) @@ -187,9 +177,9 @@ def get_cost_value( def get_cost_cache( bloq: 'Bloq', cost_key: CostKey[CostValT], - costs_cache: Optional[Dict['Bloq', CostValT]] = None, + costs_cache: Optional[dict['Bloq', CostValT]] = None, generalizer: Optional[Union['GeneralizerT', Sequence['GeneralizerT']]] = None, -) -> Dict['Bloq', CostValT]: +) -> dict['Bloq', CostValT]: """Build a cache of cost values for the bloq and its callees. This can be useful to inspect how callees' costs flow upwards in a given cost computation. @@ -214,7 +204,7 @@ def get_cost_cache( costs_cache = {} if generalizer is None: generalizer = lambda b: b - if isinstance(generalizer, collections.abc.Sequence): + if isinstance(generalizer, Sequence): generalizer = _make_composite_generalizer(*generalizer) _get_cost_value(bloq, cost_key, costs_cache=costs_cache, generalizer=generalizer) @@ -225,7 +215,7 @@ def query_costs( bloq: 'Bloq', cost_keys: Iterable[CostKey], generalizer: Optional[Union['GeneralizerT', Sequence['GeneralizerT']]] = None, -) -> Dict['Bloq', Dict[CostKey, CostValT]]: +) -> dict['Bloq', dict[CostKey, CostValT]]: """Compute a selection of costs for a bloq and its callees. This function can be used to annotate a call graph diagram with multiple costs @@ -244,7 +234,7 @@ def query_costs( A dictionary of dictionaries forming a table of multiple costs for multiple bloqs. This is indexed by bloq, then cost key. """ - costs: Dict['Bloq', Dict[CostKey, CostValT]] = defaultdict(dict) + costs: dict['Bloq', dict[CostKey, CostValT]] = defaultdict(dict) for cost_key in cost_keys: cost_for_bloqs = get_cost_cache(bloq, cost_key, generalizer=generalizer) for bloq, val in cost_for_bloqs.items(): diff --git a/qualtran/resource_counting/_costing_test.py b/qualtran/resource_counting/_costing_test.py index 9ea0f97d2b..f7bb601b7c 100644 --- a/qualtran/resource_counting/_costing_test.py +++ b/qualtran/resource_counting/_costing_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Callable, List +from collections.abc import Callable import attrs @@ -31,7 +31,7 @@ class TestCostKey(CostKey[int]): def __init__(self): # For testing, keep a log of all the bloqs for which we called 'compute' on. - self._log: List[Bloq] = [] + self._log: list[Bloq] = [] def compute(self, bloq: 'Bloq', get_callee_cost: Callable[['Bloq'], int]) -> int: self._log.append(bloq) diff --git a/qualtran/resource_counting/_generalization.py b/qualtran/resource_counting/_generalization.py index 67b8fee061..a6aa3bdc02 100644 --- a/qualtran/resource_counting/_generalization.py +++ b/qualtran/resource_counting/_generalization.py @@ -11,7 +11,8 @@ # 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 typing import Callable, Optional, TYPE_CHECKING +from collections.abc import Callable +from typing import Optional, TYPE_CHECKING if TYPE_CHECKING: from qualtran import Bloq diff --git a/qualtran/resource_counting/_qubit_counts.py b/qualtran/resource_counting/_qubit_counts.py index cfa748073e..bb7a4ee31c 100644 --- a/qualtran/resource_counting/_qubit_counts.py +++ b/qualtran/resource_counting/_qubit_counts.py @@ -13,7 +13,7 @@ # limitations under the License. import logging -from typing import Callable, Set +from collections.abc import Callable import networkx as nx from attrs import frozen @@ -51,7 +51,7 @@ def _cbloq_max_width( independently. """ max_width: SymbolicInt = 0 - in_play: Set[Connection] = set() + in_play: set[Connection] = set() for cc in nx.weakly_connected_components(binst_graph): for binst in greedy_topological_sort(binst_graph.subgraph(cc)): diff --git a/qualtran/resource_counting/_success_prob.py b/qualtran/resource_counting/_success_prob.py index 4aab783bdd..9f94aaa9d1 100644 --- a/qualtran/resource_counting/_success_prob.py +++ b/qualtran/resource_counting/_success_prob.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import logging -from typing import Callable +from collections.abc import Callable from attrs import frozen diff --git a/qualtran/resource_counting/classify_bloqs.py b/qualtran/resource_counting/classify_bloqs.py index b6016e8f06..f56e17b659 100644 --- a/qualtran/resource_counting/classify_bloqs.py +++ b/qualtran/resource_counting/classify_bloqs.py @@ -13,7 +13,8 @@ # limitations under the License. import collections.abc as abc from collections import defaultdict -from typing import cast, Dict, List, Optional, Sequence, TYPE_CHECKING, Union +from collections.abc import Sequence +from typing import cast, Optional, TYPE_CHECKING, Union import numpy as np import sympy @@ -30,7 +31,7 @@ from qualtran.resource_counting import GeneralizerT -def _get_basic_bloq_classification() -> Dict[str, str]: +def _get_basic_bloq_classification() -> dict[str, str]: """High level classification of bloqs by the module name.""" bloq_classifier = { 'qualtran.bloqs.arithmetic': 'arithmetic', @@ -49,7 +50,7 @@ def _get_basic_bloq_classification() -> Dict[str, str]: return bloq_classifier -def classify_bloq(bloq: Bloq, bloq_classification: Dict[str, str]) -> str: +def classify_bloq(bloq: Bloq, bloq_classification: dict[str, str]) -> str: """Classify a bloq given a bloq_classification. Args: @@ -71,9 +72,9 @@ def classify_bloq(bloq: Bloq, bloq_classification: Dict[str, str]) -> str: def classify_t_count_by_bloq_type( bloq: Bloq, - bloq_classification: Optional[Dict[str, str]] = None, + bloq_classification: Optional[dict[str, str]] = None, generalizer: Optional[Union['GeneralizerT', Sequence['GeneralizerT']]] = None, -) -> Dict[str, Union[int, sympy.Expr]]: +) -> dict[str, Union[int, sympy.Expr]]: """Classify (bin) the T count of a bloq's call graph by type of operation. Args: @@ -92,7 +93,7 @@ def classify_t_count_by_bloq_type( if bloq_classification is None: bloq_classification = _get_basic_bloq_classification() keeper = lambda bloq: classify_bloq(bloq, bloq_classification) != 'other' - basic_generalizer: List['GeneralizerT'] = [ + basic_generalizer: list['GeneralizerT'] = [ ignore_split_join, ignore_alloc_free, ignore_cliffords, @@ -103,7 +104,7 @@ def classify_t_count_by_bloq_type( else: basic_generalizer.append(generalizer) _, sigma = bloq.call_graph(generalizer=basic_generalizer, keep=keeper) - classified_bloqs: Dict[str, Union[int, sympy.Expr]] = defaultdict(int) + classified_bloqs: dict[str, Union[int, sympy.Expr]] = defaultdict(int) for k, v in sigma.items(): classification = classify_bloq(k, bloq_classification) t_counts = get_cost_value(k, QECGatesCost()).total_t_count() diff --git a/qualtran/resource_counting/classify_bloqs_test.py b/qualtran/resource_counting/classify_bloqs_test.py index 753a8c2c3b..5e671c7800 100644 --- a/qualtran/resource_counting/classify_bloqs_test.py +++ b/qualtran/resource_counting/classify_bloqs_test.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property -from typing import Tuple import attrs import numpy as np @@ -50,7 +49,7 @@ class TestBundleOfBloqs(Bloq): """A fake bloq which just defines a call graph""" - bloqs: Tuple[BloqCountT, ...] + bloqs: tuple[BloqCountT, ...] @cached_property def signature(self) -> 'Signature': diff --git a/qualtran/resource_counting/generalizers.py b/qualtran/resource_counting/generalizers.py index 4948411d90..ec5f2b2595 100644 --- a/qualtran/resource_counting/generalizers.py +++ b/qualtran/resource_counting/generalizers.py @@ -19,7 +19,8 @@ into one, more general bloq. The functions in this module can be used as generalizers for this argument. """ -from typing import Callable, Optional +from collections.abc import Callable +from typing import Optional import attrs import sympy diff --git a/qualtran/resource_counting/t_counts_from_sigma.py b/qualtran/resource_counting/t_counts_from_sigma.py index eb4578e362..0e8367eb0f 100644 --- a/qualtran/resource_counting/t_counts_from_sigma.py +++ b/qualtran/resource_counting/t_counts_from_sigma.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import warnings -from typing import Mapping +from collections.abc import Mapping from qualtran import Bloq, Controlled from qualtran.symbolics import ceil, SymbolicInt diff --git a/qualtran/serialization/bloq.py b/qualtran/serialization/bloq.py index 132930b280..d9a3781275 100644 --- a/qualtran/serialization/bloq.py +++ b/qualtran/serialization/bloq.py @@ -14,7 +14,8 @@ import dataclasses import inspect -from typing import Any, Callable, Dict, List, Optional, Tuple, Union +from collections.abc import Callable +from typing import Any, Optional, Union import attrs import cirq @@ -82,7 +83,7 @@ def arg_to_proto(*, name: str, val: Any) -> bloq_pb2.BloqArg: raise ValueError(f"Cannot serialize {val} of unknown type {type(val)}") -def arg_from_proto(arg: bloq_pb2.BloqArg) -> Dict[str, Any]: +def arg_from_proto(arg: bloq_pb2.BloqArg) -> dict[str, Any]: if arg.HasField("int_val"): return {arg.name: arg.int_val} if arg.HasField("float_val"): @@ -112,10 +113,10 @@ def arg_from_proto(arg: bloq_pb2.BloqArg) -> Dict[str, Any]: class _BloqLibDeserializer: def __init__(self, lib: bloq_pb2.BloqLibrary): - self.id_to_proto: Dict[int, bloq_pb2.BloqLibrary.BloqWithDecomposition] = { + self.id_to_proto: dict[int, bloq_pb2.BloqLibrary.BloqWithDecomposition] = { b.bloq_id: b for b in lib.table } - self.id_to_bloq: Dict[int, Bloq] = {} + self.id_to_bloq: dict[int, Bloq] = {} self.dangling_to_singleton = {"LeftDangle": LeftDangle, "RightDangle": RightDangle} def bloq_id_to_bloq(self, bloq_id: int): @@ -169,7 +170,7 @@ def _soquet_from_proto(self, soq: bloq_pb2.Soquet) -> Soquet: ) -def bloqs_from_proto(lib: bloq_pb2.BloqLibrary) -> List[Bloq]: +def bloqs_from_proto(lib: bloq_pb2.BloqLibrary) -> list[Bloq]: """Deserializes a BloqLibrary as a list of Bloqs.""" deserializer = _BloqLibDeserializer(lib) return [deserializer.bloq_id_to_bloq(bloq.bloq_id) for bloq in lib.table] @@ -200,7 +201,7 @@ def bloqs_to_proto( # Set up this mapping and populate it by recursively searching for subbloqs. # Each value is an (id: bool, shallow: bool) tuple, where the second entry can be set to # `True` for bloqs that need to be referred to but do not need a full serialization. - bloq_to_id_ext: Dict[Bloq, Tuple[int, bool]] = {} + bloq_to_id_ext: dict[Bloq, tuple[int, bool]] = {} for bloq in bloqs: _assign_bloq_an_id(bloq, bloq_to_id_ext, shallow=True) _search_for_subbloqs(bloq, bloq_to_id_ext, pred, max_depth) @@ -267,13 +268,13 @@ def _iter_fields(bloq: Bloq): yield field -def _connection_to_proto(cxn: Connection, bloq_to_id: Dict[Bloq, int]): +def _connection_to_proto(cxn: Connection, bloq_to_id: dict[Bloq, int]): return bloq_pb2.Connection( left=_soquet_to_proto(cxn.left, bloq_to_id), right=_soquet_to_proto(cxn.right, bloq_to_id) ) -def _soquet_to_proto(soq: Soquet, bloq_to_id: Dict[Bloq, int]) -> bloq_pb2.Soquet: +def _soquet_to_proto(soq: Soquet, bloq_to_id: dict[Bloq, int]) -> bloq_pb2.Soquet: if isinstance(soq.binst, DanglingT): return bloq_pb2.Soquet( dangling_t=repr(soq.binst), register=registers.register_to_proto(soq.reg), index=soq.idx @@ -287,12 +288,12 @@ def _soquet_to_proto(soq: Soquet, bloq_to_id: Dict[Bloq, int]) -> bloq_pb2.Soque def _bloq_instance_to_proto( - binst: BloqInstance, bloq_to_id: Dict[Bloq, int] + binst: BloqInstance, bloq_to_id: dict[Bloq, int] ) -> bloq_pb2.BloqInstance: return bloq_pb2.BloqInstance(instance_id=binst.i, bloq_id=bloq_to_id[binst.bloq]) -def _assign_bloq_an_id(bloq: Bloq, bloq_to_id: Dict[Bloq, Tuple[int, bool]], shallow: bool = False): +def _assign_bloq_an_id(bloq: Bloq, bloq_to_id: dict[Bloq, tuple[int, bool]], shallow: bool = False): """Assigns a new index for `bloq` and records it into the `bloq_to_id` mapping.""" if bloq in bloq_to_id: # Keep the same id, but if anyone requests a non-shallow serialization; do it. @@ -303,7 +304,7 @@ def _assign_bloq_an_id(bloq: Bloq, bloq_to_id: Dict[Bloq, Tuple[int, bool]], sha bloq_to_id[bloq] = next_idx, shallow -def _cbloq_ordered_bloq_instances(cbloq: CompositeBloq) -> List[BloqInstance]: +def _cbloq_ordered_bloq_instances(cbloq: CompositeBloq) -> list[BloqInstance]: """Equivalent to `cbloq.bloq_instances`, but preserves insertion order among bloq instances.""" ret = {} for cxn in cbloq.connections: @@ -315,7 +316,7 @@ def _cbloq_ordered_bloq_instances(cbloq: CompositeBloq) -> List[BloqInstance]: def _search_for_subbloqs( bloq: Bloq, - bloq_to_id: Dict[Bloq, Tuple[int, bool]], + bloq_to_id: dict[Bloq, tuple[int, bool]], pred: Callable[[BloqInstance], bool], max_depth: int, ) -> None: @@ -372,7 +373,7 @@ def _search_for_subbloqs( def _bloq_to_proto( - bloq: Bloq, *, bloq_to_id: Dict[Bloq, int], shallow: bool = False + bloq: Bloq, *, bloq_to_id: dict[Bloq, int], shallow: bool = False ) -> bloq_pb2.Bloq: if shallow: t_complexity = None @@ -392,8 +393,8 @@ def _bloq_to_proto( def _bloq_args_to_proto( - bloq: Bloq, *, bloq_to_id: Dict[Bloq, int] -) -> Optional[List[bloq_pb2.BloqArg]]: + bloq: Bloq, *, bloq_to_id: dict[Bloq, int] +) -> Optional[list[bloq_pb2.BloqArg]]: if isinstance(bloq, CompositeBloq): return None @@ -405,7 +406,7 @@ def _bloq_args_to_proto( return ret if ret else None -def _bloq_arg_to_proto(name: str, val: Any, bloq_to_id: Dict[Bloq, int]) -> bloq_pb2.BloqArg: +def _bloq_arg_to_proto(name: str, val: Any, bloq_to_id: dict[Bloq, int]) -> bloq_pb2.BloqArg: if isinstance(val, Bloq): return bloq_pb2.BloqArg(name=name, subbloq=bloq_to_id[val]) return arg_to_proto(name=name, val=val) diff --git a/qualtran/serialization/registers.py b/qualtran/serialization/registers.py index 8f449a4877..9e47fae330 100644 --- a/qualtran/serialization/registers.py +++ b/qualtran/serialization/registers.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Iterable, Tuple +from collections.abc import Iterable from qualtran import Register, Side from qualtran.protos import registers_pb2 @@ -24,7 +24,7 @@ def registers_to_proto(registers: Iterable[Register]) -> registers_pb2.Registers return registers_pb2.Registers(registers=[register_to_proto(reg) for reg in registers]) -def registers_from_proto(registers: registers_pb2.Registers) -> Tuple[Register, ...]: +def registers_from_proto(registers: registers_pb2.Registers) -> tuple[Register, ...]: return tuple(register_from_proto(reg) for reg in registers.registers) diff --git a/qualtran/serialization/sympy_to_proto.py b/qualtran/serialization/sympy_to_proto.py index 277f88a625..fd91df0878 100644 --- a/qualtran/serialization/sympy_to_proto.py +++ b/qualtran/serialization/sympy_to_proto.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Any, cast, Dict, Union +from typing import Any, cast, Union import sympy import sympy.codegen.cfunctions @@ -63,7 +63,7 @@ def _get_sympy_function_from_enum(enum: int) -> Any: Sympy functions are represented as a sympy_pb2.Function enum. This method converts this int enum. """ - enum_to_sympy: Dict[int, Any] = { + enum_to_sympy: dict[int, Any] = { sympy_pb2.Function.Mul: sympy.core.mul.Mul, sympy_pb2.Function.Add: sympy.core.add.Add, sympy_pb2.Function.Pow: sympy.core.power.Pow, @@ -89,7 +89,7 @@ def _get_sympy_const_from_enum(enum: int) -> Any: Symbolic constants are serialzed as an enum of type sympy_pb2.ConstSymbol. This method converts the enum representation back to its original sympy representation. """ - enum_to_sympy: Dict[int, Any] = { + enum_to_sympy: dict[int, Any] = { sympy_pb2.ConstSymbol.Pi: sympy.pi, sympy_pb2.ConstSymbol.E: sympy.E, sympy_pb2.ConstSymbol.EulerGamma: sympy.EulerGamma, diff --git a/qualtran/simulation/classical_sim.py b/qualtran/simulation/classical_sim.py index 927c93e00a..546f263dfe 100644 --- a/qualtran/simulation/classical_sim.py +++ b/qualtran/simulation/classical_sim.py @@ -14,19 +14,8 @@ """Functionality for the `Bloq.call_classically(...)` protocol.""" import itertools -from typing import ( - Any, - Dict, - Iterable, - List, - Mapping, - Optional, - Sequence, - Tuple, - Type, - TYPE_CHECKING, - Union, -) +from collections.abc import Iterable, Mapping, Sequence +from typing import Any, Optional, Type, TYPE_CHECKING, Union import networkx as nx import numpy as np @@ -92,7 +81,7 @@ def _empty_ndarray_from_reg(reg: Register) -> np.ndarray: def _get_in_vals( - binst: Union[DanglingT, BloqInstance], reg: Register, soq_assign: Dict[Soquet, ClassicalValT] + binst: Union[DanglingT, BloqInstance], reg: Register, soq_assign: dict[Soquet, ClassicalValT] ) -> ClassicalValT: """Pluck out the correct values from `soq_assign` for `reg` on `binst`.""" if not reg.shape: @@ -144,7 +133,7 @@ def __init__( self._binst_iter = nx.topological_sort(self._binst_graph) # Keep track of each soquet's bit array. Initialize with LeftDangle - self.soq_assign: Dict[Soquet, ClassicalValT] = {} + self.soq_assign: dict[Soquet, ClassicalValT] = {} self._update_assign_from_vals(self._signature.lefts(), LeftDangle, dict(vals)) self.last_binst: Optional['BloqInstance'] = None @@ -170,7 +159,7 @@ def _update_assign_from_vals( self, regs: Iterable[Register], binst: Union[DanglingT, BloqInstance], - vals: Union[Dict[str, Union[sympy.Symbol, ClassicalValT]], Dict[str, ClassicalValT]], + vals: Union[dict[str, Union[sympy.Symbol, ClassicalValT]], dict[str, ClassicalValT]], ) -> None: """Update `self.soq_assign` using `vals`. @@ -265,7 +254,7 @@ def _in_vals(reg: Register): self._binst_basis_state_phase(binst, in_vals) return self - def finalize(self) -> Dict[str, 'ClassicalValT']: + def finalize(self) -> dict[str, 'ClassicalValT']: """Finish simulating a composite bloq and extract final values. Returns: @@ -289,7 +278,7 @@ def _f_vals(reg: Register): final_vals = {reg.name: _f_vals(reg) for reg in self._signature.rights()} return final_vals - def simulate(self) -> Dict[str, 'ClassicalValT']: + def simulate(self) -> dict[str, 'ClassicalValT']: """Simulate the composite bloq and return the final values.""" try: while True: @@ -371,7 +360,7 @@ def call_cbloq_classically( signature: Signature, vals: Mapping[str, Union[sympy.Symbol, ClassicalValT]], binst_graph: nx.DiGraph, -) -> Tuple[Dict[str, ClassicalValT], Dict[Soquet, ClassicalValT]]: +) -> tuple[dict[str, ClassicalValT], dict[Soquet, ClassicalValT]]: """Propagate `on_classical_vals` calls through a composite bloq's contents. While we're handling the plumbing, we also do error checking on the arguments; see @@ -422,7 +411,7 @@ def do_phased_classical_simulation(bloq: 'Bloq', vals: Mapping[str, 'ClassicalVa def get_classical_truth_table( bloq: 'Bloq', -) -> Tuple[List[str], List[str], List[Tuple[Sequence[Any], Sequence[Any]]]]: +) -> tuple[list[str], list[str], list[tuple[Sequence[Any], Sequence[Any]]]]: """Get a 'truth table' for a classical-reversible bloq. Args: @@ -441,14 +430,14 @@ def get_classical_truth_table( if reg.shape: raise NotImplementedError() - in_names: List[str] = [] + in_names: list[str] = [] iters = [] for reg in bloq.signature.lefts(): in_names.append(reg.name) iters.append(reg.dtype.get_classical_domain()) - out_names: List[str] = [reg.name for reg in bloq.signature.rights()] + out_names: list[str] = [reg.name for reg in bloq.signature.rights()] - truth_table: List[Tuple[Sequence[Any], Sequence[Any]]] = [] + truth_table: list[tuple[Sequence[Any], Sequence[Any]]] = [] for in_val_tuple in itertools.product(*iters): in_val_d = {name: val for name, val in zip(in_names, in_val_tuple)} out_val_tuple = bloq.call_classically(**in_val_d) @@ -460,7 +449,7 @@ def get_classical_truth_table( def format_classical_truth_table( in_names: Sequence[str], out_names: Sequence[str], - truth_table: Sequence[Tuple[Sequence[Any], Sequence[Any]]], + truth_table: Sequence[tuple[Sequence[Any], Sequence[Any]]], ) -> str: """Get a formatted tabular representation of the classical truth table.""" heading = ' '.join(in_names) + ' | ' + ' '.join(out_names) + '\n' diff --git a/qualtran/simulation/classical_sim_test.py b/qualtran/simulation/classical_sim_test.py index 582f5057a1..4e4ef8e80a 100644 --- a/qualtran/simulation/classical_sim_test.py +++ b/qualtran/simulation/classical_sim_test.py @@ -13,7 +13,6 @@ # limitations under the License. import itertools -from typing import Dict import networkx as nx import numpy as np @@ -93,7 +92,7 @@ def signature(self) -> 'Signature': [Register('x', QBit(), shape=(5,)), Register('z', QBit(), shape=(5,), side=Side.RIGHT)] ) - def on_classical_vals(self, *, x: NDArray[np.uint8]) -> Dict[str, NDArray[np.uint8]]: + def on_classical_vals(self, *, x: NDArray[np.uint8]) -> dict[str, NDArray[np.uint8]]: const = np.array([1, 0, 1, 0, 1], dtype=np.uint8) z = np.logical_xor(x, const).astype(np.uint8) return {'x': x, 'z': z} diff --git a/qualtran/simulation/tensor/_dense.py b/qualtran/simulation/tensor/_dense.py index f4e630ddb0..3cb0dba500 100644 --- a/qualtran/simulation/tensor/_dense.py +++ b/qualtran/simulation/tensor/_dense.py @@ -14,7 +14,7 @@ import logging from collections import defaultdict -from typing import Dict, List, Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING from numpy.typing import NDArray @@ -30,8 +30,8 @@ def _order_incoming_outgoing_indices( - signature: Signature, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] -) -> List[Tuple[Connection, int]]: + signature: Signature, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] +) -> list[tuple[Connection, int]]: """Order incoming and outgoing indices provided by the tensor protocol according to `signature`. This can be used if you have a well-ordered, dense numpy array. @@ -41,7 +41,7 @@ def _order_incoming_outgoing_indices( >>> return [qtn.Tensor(data=data, inds=inds)] """ - inds: List[Tuple[Connection, int]] = [] + inds: list[tuple[Connection, int]] = [] # Nested for loops: # reg: each register in the signature @@ -67,7 +67,7 @@ def _order_incoming_outgoing_indices( def _group_outer_inds( tn: 'qtn.TensorNetwork', signature: Signature, superoperator: bool = False -) -> List[List[_IndT]]: +) -> list[list[_IndT]]: """Group outer indices of a tensor network. This is used by 'bloq_to_dense` and `quimb_to_dense` to return a 1-, 2-, or 4-dimensional @@ -80,17 +80,17 @@ def _group_outer_inds( superoperator: Whether `tn` is a pure-state or open-system tensor network. """ reg_name: str - idx: Tuple[int, ...] + idx: tuple[int, ...] j: int group: str - _KeyT = Tuple[str, Tuple[int, ...], int] - ind_groups_d: Dict[str, Dict[_KeyT, _IndT]] = defaultdict(dict) + _KeyT = tuple[str, tuple[int, ...], int] + ind_groups_d: dict[str, dict[_KeyT, _IndT]] = defaultdict(dict) for ind in tn.outer_inds(): reg_name, idx, j, group = ind ind_groups_d[group][reg_name, idx, j] = ind - ind_groups_l: Dict[str, List[_IndT]] = defaultdict(list) + ind_groups_l: dict[str, list[_IndT]] = defaultdict(list) def _sort_group(regs, group_name): for reg in regs: diff --git a/qualtran/simulation/tensor/_dense_test.py b/qualtran/simulation/tensor/_dense_test.py index 45f1e42238..4104556e36 100644 --- a/qualtran/simulation/tensor/_dense_test.py +++ b/qualtran/simulation/tensor/_dense_test.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict, List import numpy as np import pytest @@ -51,8 +50,8 @@ def signature(self) -> 'Signature': ) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: assert sorted(incoming.keys()) == ['qubits', 'x'] in_qubits = incoming['qubits'] assert isinstance(in_qubits, np.ndarray) @@ -104,7 +103,7 @@ class XNest(Bloq): def signature(self) -> 'Signature': return Signature.build(r=1) - def build_composite_bloq(self, bb: 'BloqBuilder', r: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', r: 'SoquetT') -> dict[str, 'SoquetT']: r = bb.add(XGate(), q=r) return {'r': r} @@ -115,7 +114,7 @@ class XDoubleNest(Bloq): def signature(self) -> 'Signature': return Signature.build(s=1) - def build_composite_bloq(self, bb: 'BloqBuilder', s: 'SoquetT') -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', s: 'SoquetT') -> dict[str, 'SoquetT']: s = bb.add(XNest(), r=s) return {'s': s} @@ -144,7 +143,7 @@ def signature(self) -> 'Signature': def build_composite_bloq( self, bb: 'BloqBuilder', q0: Soquet, q1: Soquet - ) -> Dict[str, 'SoquetT']: + ) -> dict[str, 'SoquetT']: q0 = bb.add(XGate(), q=q0) q0, q1 = bb.add(CNOT(), ctrl=q0, target=q1) q1 = bb.add(ZGate(), q=q1) @@ -172,15 +171,15 @@ def __init__(self): def signature(self) -> 'Signature': return Signature.build(a=1, b=1) - def build_composite_bloq(self, bb: 'BloqBuilder', a: Soquet, b: Soquet) -> Dict[str, 'SoquetT']: + def build_composite_bloq(self, bb: 'BloqBuilder', a: Soquet, b: Soquet) -> dict[str, 'SoquetT']: self.called_build_composite_bloq = True a, b = bb.add(CNOT(), ctrl=a, target=b) a, b = bb.add(CNOT(), ctrl=a, target=b) return {'a': a, 'b': b} def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: self.called_my_tensors = True return [ qtn.Tensor( diff --git a/qualtran/simulation/tensor/_quimb.py b/qualtran/simulation/tensor/_quimb.py index 7a4583fdc4..789fce75c7 100644 --- a/qualtran/simulation/tensor/_quimb.py +++ b/qualtran/simulation/tensor/_quimb.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. import logging -from typing import Any, cast, Dict, Iterable, Tuple, TypeAlias, Union +from collections.abc import Iterable +from typing import Any, cast, TypeAlias, Union import attrs import numpy as np @@ -111,12 +112,12 @@ def _get_placeholder_tensors(cxn): ) -_OuterIndT = Tuple[str, Tuple[int, ...], int, str] +_OuterIndT = tuple[str, tuple[int, ...], int, str] def _get_outer_indices( tn: 'qtn.TensorNetwork', friendly_indices: bool = False -) -> Dict[_IndT, Union[str, _OuterIndT]]: +) -> dict[_IndT, Union[str, _OuterIndT]]: """Provide a mapping for a tensor network's outer indices. Internal indices effectively use `qualtran.Connection` objects as their indices. The @@ -131,7 +132,7 @@ def _get_outer_indices( This function is called at the end of `cbloq_to_quimb` as part of a `tn.reindex(...) operation. """ - ind_name_map: Dict[_IndT, Union[str, _OuterIndT]] = {} + ind_name_map: dict[_IndT, Union[str, _OuterIndT]] = {} # Each index is a (cxn: Connection, j: int) tuple. cxn: Connection @@ -179,7 +180,7 @@ class DiscardInd: individual bits. """ - ind_tuple: Tuple['ConnectionT', int] + ind_tuple: tuple['ConnectionT', int] def make_forward_tensor(t: qtn.Tensor): @@ -266,12 +267,12 @@ def cbloq_to_superquimb(cbloq: CompositeBloq, friendly_indices: bool = False) -> return tn.reindex(_get_outer_superindices(tn, friendly_indices=friendly_indices)) -_SuperOuterIndT = Tuple[str, Tuple[int, ...], int, str] +_SuperOuterIndT = tuple[str, tuple[int, ...], int, str] def _get_outer_superindices( tn: 'qtn.TensorNetwork', friendly_indices: bool = False -) -> Dict[_IndT, Union[str, _SuperOuterIndT]]: +) -> dict[_IndT, Union[str, _SuperOuterIndT]]: """Provide a mapping for a super-tensor network's outer indices. Internal indices effectively use `qualtran.Connection` objects as their indices. The @@ -293,7 +294,7 @@ def _get_outer_superindices( j: int forward: bool - ind_name_map: Dict[_IndT, Union[str, _SuperOuterIndT]] = {} + ind_name_map: dict[_IndT, Union[str, _SuperOuterIndT]] = {} for ind in tn.outer_inds(): cxn, j, forward = ind if cxn.left.binst is LeftDangle: @@ -317,12 +318,12 @@ def _get_outer_superindices( return ind_name_map -def _add_classical_kets(bb: BloqBuilder, registers: Iterable[Register]) -> Dict[str, 'SoquetT']: +def _add_classical_kets(bb: BloqBuilder, registers: Iterable[Register]) -> dict[str, 'SoquetT']: """Use `bb` to add `IntState(0)` for all the `vals`.""" from qualtran.bloqs.basic_gates import IntState - soqs: Dict[str, 'SoquetT'] = {} + soqs: dict[str, 'SoquetT'] = {} for reg in registers: if reg.shape: reg_vals = np.zeros(reg.shape, dtype=int) diff --git a/qualtran/simulation/tensor/_quimb_test.py b/qualtran/simulation/tensor/_quimb_test.py index ceb9a347a0..079e012e2b 100644 --- a/qualtran/simulation/tensor/_quimb_test.py +++ b/qualtran/simulation/tensor/_quimb_test.py @@ -13,7 +13,6 @@ # limitations under the License. from functools import cached_property -from typing import Dict, List import numpy as np import quimb.tensor as qtn @@ -31,8 +30,8 @@ def signature(self) -> 'Signature': return Signature.build(x=1) def my_tensors( - self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] - ) -> List['qtn.Tensor']: + self, incoming: dict[str, 'ConnectionT'], outgoing: dict[str, 'ConnectionT'] + ) -> list['qtn.Tensor']: assert list(incoming.keys()) == ['x'] assert list(outgoing.keys()) == ['x'] return [qtn.Tensor(data=np.eye(2), inds=[(incoming['x'], 0), (outgoing['x'], 0)])] diff --git a/qualtran/simulation/tensor/_tensor_data_manipulation.py b/qualtran/simulation/tensor/_tensor_data_manipulation.py index 5029ae22e5..98851bdf68 100644 --- a/qualtran/simulation/tensor/_tensor_data_manipulation.py +++ b/qualtran/simulation/tensor/_tensor_data_manipulation.py @@ -14,7 +14,7 @@ """Utility methods to generate and manipulate tensor data for Bloqs.""" import itertools -from typing import List, Tuple, Union +from typing import Union import attrs import numpy as np @@ -24,7 +24,7 @@ def tensor_out_inp_shape_from_signature( signature: Signature, -) -> Tuple[Tuple[int, ...], Tuple[int, ...]]: +) -> tuple[tuple[int, ...], tuple[int, ...]]: """Returns a tuple for tensor data corresponding to signature. Tensor data for a bloq with a given `signature` can be expressed as a ndarray of @@ -42,7 +42,7 @@ def tensor_out_inp_shape_from_signature( return tuple(out_indices_shape), tuple(inp_indices_shape) -def tensor_shape_from_signature(signature: Signature) -> Tuple[int, ...]: +def tensor_shape_from_signature(signature: Signature) -> tuple[int, ...]: """Returns a tuple for tensor data corresponding to signature. Tensor data for a bloq with a given `signature` can be expressed as a ndarray of @@ -61,7 +61,7 @@ def tensor_shape_from_signature(signature: Signature) -> Tuple[int, ...]: def active_space_for_ctrl_spec( signature: Signature, ctrl_spec: CtrlSpec -) -> Tuple[Union[int, slice], ...]: +) -> tuple[Union[int, slice], ...]: """Returns the "active" subspace corresponding to `signature` and `ctrl_spec`. Assumes first n-registers for `signature` are control registers corresponding to `ctrl_spec`. @@ -73,7 +73,7 @@ def active_space_for_ctrl_spec( out_ind, inp_ind = tensor_out_inp_shape_from_signature(signature) data_shape = out_ind + inp_ind - active_idx: List[Union[int, slice]] = [slice(x) for x in data_shape] + active_idx: list[Union[int, slice]] = [slice(x) for x in data_shape] ctrl_idx = 0 for cv in ctrl_spec.cvs: assert isinstance(cv, np.ndarray) @@ -117,7 +117,7 @@ def tensor_data_from_unitary_and_signature(unitary: np.ndarray, signature: Signa unitary = unitary.reshape(unitary_shape) # Find the subspace corresponding to registers with sides. - idx: List[Union[int, slice]] = [slice(x) for x in unitary_shape] + idx: list[Union[int, slice]] = [slice(x) for x in unitary_shape] curr_idx = 0 for reg in signature: if reg.side == Side.LEFT: diff --git a/qualtran/simulation/tensor/_tensor_from_classical.py b/qualtran/simulation/tensor/_tensor_from_classical.py index bf87b44b32..5c3814cc30 100644 --- a/qualtran/simulation/tensor/_tensor_from_classical.py +++ b/qualtran/simulation/tensor/_tensor_from_classical.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. import itertools -from typing import Iterable, TYPE_CHECKING +from collections.abc import Iterable +from typing import TYPE_CHECKING import numpy as np from numpy.typing import NDArray diff --git a/qualtran/simulation/xcheck_classical_quimb.py b/qualtran/simulation/xcheck_classical_quimb.py index 9b644d67b7..21b2452c37 100644 --- a/qualtran/simulation/xcheck_classical_quimb.py +++ b/qualtran/simulation/xcheck_classical_quimb.py @@ -11,7 +11,8 @@ # 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 typing import cast, Dict, Iterable, Optional, TYPE_CHECKING +from collections.abc import Iterable +from typing import cast, Optional, TYPE_CHECKING import numpy as np @@ -23,10 +24,10 @@ def _add_classical_kets( - bb: BloqBuilder, registers: Iterable[Register], vals: Dict[str, 'ClassicalValT'] -) -> Dict[str, 'SoquetT']: + bb: BloqBuilder, registers: Iterable[Register], vals: dict[str, 'ClassicalValT'] +) -> dict[str, 'SoquetT']: """Use `bb` to add `IntState` for all the `vals`.""" - soqs: Dict[str, 'SoquetT'] = {} + soqs: dict[str, 'SoquetT'] = {} for reg in registers: if reg.shape: reg_vals = np.asarray(vals[reg.name]) @@ -43,8 +44,8 @@ def _add_classical_kets( def _add_classical_bras( bb: BloqBuilder, registers: Iterable[Register], - vals: Dict[str, 'ClassicalValT'], - soqs: Dict[str, 'SoquetT'], + vals: dict[str, 'ClassicalValT'], + soqs: dict[str, 'SoquetT'], ) -> None: """Use `bb` to add `IntEffect` on `soqs` for all the `vals`.""" for reg in registers: @@ -63,8 +64,8 @@ def _add_classical_bras( def flank_with_classical_vectors( bloq: 'Bloq', - in_vals: Dict[str, 'ClassicalValT'], - out_vals: Optional[Dict[str, 'ClassicalValT']] = None, + in_vals: dict[str, 'ClassicalValT'], + out_vals: Optional[dict[str, 'ClassicalValT']] = None, ) -> 'CompositeBloq': """Surround `bloq` with computational basis vectors according to the provided values. diff --git a/qualtran/surface_code/gidney_fowler_model.py b/qualtran/surface_code/gidney_fowler_model.py index 3452b58e02..0877031217 100644 --- a/qualtran/surface_code/gidney_fowler_model.py +++ b/qualtran/surface_code/gidney_fowler_model.py @@ -13,7 +13,8 @@ # limitations under the License. import math -from typing import Callable, cast, Iterable, Iterator, Optional, Tuple, TYPE_CHECKING +from collections.abc import Callable, Iterable, Iterator +from typing import cast, Optional, TYPE_CHECKING from .algorithm_summary import AlgorithmSummary from .ccz2t_factory import CCZ2TFactory @@ -189,7 +190,7 @@ def get_ccz2t_costs_from_grid_search( factory_iter: Iterable[MagicStateFactory] = tuple(iter_ccz2t_factories()), data_block_iter: Iterable[DataBlock] = tuple(iter_simple_data_blocks()), cost_function: Callable[[PhysicalCostsSummary], float] = (lambda pc: pc.qubit_hours), -) -> Tuple[PhysicalCostsSummary, MagicStateFactory, SimpleDataBlock]: +) -> tuple[PhysicalCostsSummary, MagicStateFactory, SimpleDataBlock]: """Grid search over parameters to minimize the space-time volume. Args: @@ -213,7 +214,7 @@ def get_ccz2t_costs_from_grid_search( version of the spreadsheet from https://arxiv.org/abs/1812.01238 """ best_cost: Optional[PhysicalCostsSummary] = None - best_params: Optional[Tuple[MagicStateFactory, SimpleDataBlock]] = None + best_params: Optional[tuple[MagicStateFactory, SimpleDataBlock]] = None for factory in factory_iter: for data_block in data_block_iter: cost = get_ccz2t_costs( diff --git a/qualtran/surface_code/physical_cost_model.py b/qualtran/surface_code/physical_cost_model.py index 4134fe0c77..f1aae7e4f8 100644 --- a/qualtran/surface_code/physical_cost_model.py +++ b/qualtran/surface_code/physical_cost_model.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from functools import cached_property, lru_cache -from typing import Tuple, TYPE_CHECKING +from typing import TYPE_CHECKING from attrs import frozen @@ -159,7 +159,7 @@ def make_gidney_fowler(cls, data_d: int): @classmethod def make_beverland_et_al( - cls, data_d: int, data_block_name: str = 'compact', factory_ds: Tuple = (9, 3, 3) + cls, data_d: int, data_block_name: str = 'compact', factory_ds: tuple = (9, 3, 3) ): from qualtran.surface_code import ( CompactDataBlock, diff --git a/qualtran/surface_code/t_factory_utils.py b/qualtran/surface_code/t_factory_utils.py index 934703ab8d..382ed1fc64 100644 --- a/qualtran/surface_code/t_factory_utils.py +++ b/qualtran/surface_code/t_factory_utils.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Sequence +from collections.abc import Sequence import cirq import numpy as np diff --git a/qualtran/surface_code/ui.py b/qualtran/surface_code/ui.py index 85f4010c42..d0e81e88fd 100644 --- a/qualtran/surface_code/ui.py +++ b/qualtran/surface_code/ui.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Any, Dict, List, Sequence, Tuple +from collections.abc import Sequence +from typing import Any import numpy as np import pandas as pd @@ -411,7 +412,7 @@ def create_qubit_pie_chart( return fig -def format_duration(duration: Sequence[float]) -> Tuple[str, Sequence[float]]: +def format_duration(duration: Sequence[float]) -> tuple[str, Sequence[float]]: """Returns a tuple of the format (unit, duration) Finds the best unit to report `duration` and assumes that `duration` is initially in us. @@ -445,7 +446,7 @@ def create_runtime_plot( magic_count: int, rotation_model: rotation_cost_model.RotationCostModel, n_logical_gates: 'GateCounts', -) -> Tuple[Dict[str, Any], go.Figure]: +) -> tuple[dict[str, Any], go.Figure]: """Creates the runtime figure and decides whether to display it or not. Currently displays the runtime plot for the Beverland model only. @@ -589,7 +590,7 @@ def update( ) -def total_magic(estimation_model: str, n_logical_gates: 'GateCounts') -> Tuple[List[str], str]: +def total_magic(estimation_model: str, n_logical_gates: 'GateCounts') -> tuple[list[str], str]: """Compute the number of magic states needed for the algorithm and their type.""" total_t = n_logical_gates.total_t_count() total_ccz = total_t / 4 @@ -607,7 +608,7 @@ def min_num_factories( rotation_model: rotation_cost_model.RotationCostModel, magic_factory: MagicStateFactory, n_logical_gates: 'GateCounts', -) -> Tuple[Dict[str, Any], int]: +) -> tuple[dict[str, Any], int]: if estimation_model == _GIDNEY_FOWLER_MODEL: return {'display': 'none'}, 1 c_min = beverland_et_al_model.minimum_time_steps( @@ -631,7 +632,7 @@ def compute_duration( rotation_model: rotation_cost_model.RotationCostModel, magic_count: int, n_logical_gates: 'GateCounts', -) -> Tuple[Dict[str, Any], str]: +) -> tuple[dict[str, Any], str]: """Compute the duration of running the algorithm and whether to display the result or not. Currently displays the result only for GidneyFowler (arxiv:1812.01238). diff --git a/qualtran/symbolics/math_funcs.py b/qualtran/symbolics/math_funcs.py index e55c1725b2..512caa094a 100644 --- a/qualtran/symbolics/math_funcs.py +++ b/qualtran/symbolics/math_funcs.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. import math -from typing import cast, Iterable, overload, TypeVar +from collections.abc import Iterable +from typing import cast, overload, TypeVar import numpy as np import sympy diff --git a/qualtran/testing.py b/qualtran/testing.py index 646d4887c7..87778fa2ec 100644 --- a/qualtran/testing.py +++ b/qualtran/testing.py @@ -16,9 +16,10 @@ import itertools import traceback +from collections.abc import Sequence from enum import Enum from pathlib import Path -from typing import Dict, List, Optional, Sequence, Tuple, Union +from typing import Optional, Union import numpy as np import sympy @@ -236,7 +237,7 @@ def assert_valid_bloq_decomposition(bloq: Optional[Bloq]) -> CompositeBloq: return cbloq -def assert_wire_symbols_match_expected(bloq: Bloq, expected_ws: List[Union[str, WireSymbol]]): +def assert_wire_symbols_match_expected(bloq: Bloq, expected_ws: list[Union[str, WireSymbol]]): """Assert a bloq's wire symbols match the expected ones. For multi-dimensional registers (with a shape), this will iterate @@ -376,7 +377,7 @@ def assert_bloq_example_make(bloq_ex: BloqExample) -> None: return -def check_bloq_example_make(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, str]: +def check_bloq_example_make(bloq_ex: BloqExample) -> tuple[BloqCheckResult, str]: """Check that the BloqExample returns the desired bloq. Returns: @@ -418,7 +419,7 @@ def assert_bloq_example_decompose(bloq_ex: BloqExample) -> None: raise BloqCheckException.fail(str(e)) from e -def check_bloq_example_decompose(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, str]: +def check_bloq_example_decompose(bloq_ex: BloqExample) -> tuple[BloqCheckResult, str]: """Check that the BloqExample has a valid decomposition. This will use `assert_valid_decomposition` which has a variety of sub-checks. A failure @@ -462,8 +463,8 @@ def assert_equivalent_bloq_example_counts(bloq_ex: BloqExample) -> None: has_manual_counts: bool has_decomp_counts: bool - manual_counts: Dict['Bloq', Union[int, 'sympy.Expr']] = {} - decomp_counts: Dict['Bloq', Union[int, 'sympy.Expr']] = {} + manual_counts: dict['Bloq', Union[int, 'sympy.Expr']] = {} + decomp_counts: dict['Bloq', Union[int, 'sympy.Expr']] = {} # Notable implementation detail: since `bloq.build_call_graph` has a default fallback # that uses the decomposition, we could accidentally be comparing two identical code paths @@ -530,7 +531,7 @@ def assert_equivalent_bloq_counts( ) -def check_equivalent_bloq_example_counts(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, str]: +def check_equivalent_bloq_example_counts(bloq_ex: BloqExample) -> tuple[BloqCheckResult, str]: """Check that the BloqExample has consistent bloq counts. Bloq counts can be annotated directly via the `Bloq.build_call_graph` override. @@ -594,7 +595,7 @@ def assert_bloq_example_serializes(bloq_ex: BloqExample) -> None: return None -def check_bloq_example_serializes(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, str]: +def check_bloq_example_serializes(bloq_ex: BloqExample) -> tuple[BloqCheckResult, str]: """Check that the BloqExample has consistent serialization. This function checks that the given bloq can be serialized to a proto format and the @@ -619,7 +620,7 @@ def check_bloq_example_serializes(bloq_ex: BloqExample) -> Tuple[BloqCheckResult return BloqCheckResult.PASS, '' -def assert_bloq_example_qtyping(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, str]: +def assert_bloq_example_qtyping(bloq_ex: BloqExample) -> tuple[BloqCheckResult, str]: """Assert that the bloq example has valid quantum data types throughout its decomposition. If the bloq has no decomposition, this check is not applicable. Otherwise: we check the @@ -669,7 +670,7 @@ def assert_bloq_example_qtyping(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, return BloqCheckResult.PASS, '' -def check_bloq_example_qtyping(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, str]: +def check_bloq_example_qtyping(bloq_ex: BloqExample) -> tuple[BloqCheckResult, str]: """Check that the bloq example has valid quantum data types throughout its decomposition. If the bloq has no decomposition, this check is not applicable. Otherwise: we check the