From 7dc26843321b1a81dd79c2469be72f02e39da176 Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 22 May 2026 18:37:02 +0200 Subject: [PATCH 01/25] Most of the tests passing --- graphix/sim/base_backend.py | 1 + graphix/sim/density_matrix.py | 15 +- graphix/sim/statevec.py | 746 +++++++++++++++++++++++----------- graphix/transpiler.py | 4 +- tests/test_density_matrix.py | 4 +- tests/test_statevec.py | 690 ++++++++++++++++++++++++------- 6 files changed, 1066 insertions(+), 394 deletions(-) diff --git a/graphix/sim/base_backend.py b/graphix/sim/base_backend.py index ef1977b3c..11ebeb9cc 100644 --- a/graphix/sim/base_backend.py +++ b/graphix/sim/base_backend.py @@ -714,6 +714,7 @@ class DenseStateBackend(Backend[_DenseStateT_co], Generic[_DenseStateT_co]): :class:`StatevecBackend`, :class:`DensityMatrixBackend`, :class:`TensorNetworkBackend` """ + _: dataclasses.KW_ONLY node_index: NodeIndex = dataclasses.field(default_factory=NodeIndex) branch_selector: BranchSelector = dataclasses.field(default_factory=RandomBranchSelector) symbolic: bool = False diff --git a/graphix/sim/density_matrix.py b/graphix/sim/density_matrix.py index cb5570e2a..16a334d29 100644 --- a/graphix/sim/density_matrix.py +++ b/graphix/sim/density_matrix.py @@ -20,7 +20,7 @@ from graphix.channels import KrausChannel from graphix.parameter import Expression, ExpressionOrFloat, ExpressionOrSupportsComplex from graphix.sim.base_backend import DenseState, DenseStateBackend, Matrix, kron, matmul, outer, tensordot, vdot -from graphix.sim.statevec import CNOT_TENSOR, CZ_TENSOR, SWAP_TENSOR, Statevec +from graphix.sim.statevec import Statevec from graphix.states import BasicStates, State if TYPE_CHECKING: @@ -31,6 +31,19 @@ from graphix.parameter import ExpressionOrSupportsFloat, Parameter from graphix.sim.data import Data +CZ_TENSOR = np.array( + [[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, -1]]]], + dtype=np.complex128, +) +CNOT_TENSOR = np.array( + [[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [0, 1]], [[0, 0], [1, 0]]]], + dtype=np.complex128, +) +SWAP_TENSOR = np.array( + [[[[1, 0], [0, 0]], [[0, 0], [1, 0]]], [[[0, 1], [0, 0]], [[0, 0], [0, 1]]]], + dtype=np.complex128, +) + class DensityMatrix(DenseState): """DensityMatrix object.""" diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 1f7dd23e6..6d2122e59 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -1,98 +1,116 @@ -"""MBQC state vector backend.""" +"""MBQC state vector backend simulator based on 10.48550/arXiv.2506.08142.""" from __future__ import annotations -import copy import dataclasses import functools import math from collections.abc import Iterable +from copy import deepcopy from dataclasses import dataclass from typing import TYPE_CHECKING, SupportsComplex, SupportsFloat +import numba as nb import numpy as np import numpy.typing as npt from typing_extensions import override -from graphix import parameter, states -from graphix.parameter import Expression, ExpressionOrSupportsComplex, check_expression_or_float -from graphix.sim.base_backend import DenseState, DenseStateBackend, Matrix, kron, tensordot -from graphix.states import BasicStates +from graphix.parameter import ExpressionOrSupportsComplex +from graphix.sim.base_backend import DenseState, DenseStateBackend, Matrix +from graphix.states import BasicStates, State if TYPE_CHECKING: - from collections.abc import Callable, Mapping, Sequence - from typing import Any, Literal, TypeVar + from collections.abc import Callable, Sequence + from typing import Any, Literal, Self, TypeAlias, TypeVar - from graphix.parameter import ExpressionOrFloat, ExpressionOrSupportsFloat, Parameter from graphix.sim.data import Data _ENCODING = Literal["LSB", "MSB"] _ScalarT = TypeVar("_ScalarT", bound=np.generic[Any]) + from graphix.parameter import ExpressionOrSupportsComplex -CZ_TENSOR = np.array( - [[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, -1]]]], - dtype=np.complex128, -) -CNOT_TENSOR = np.array( - [[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [0, 1]], [[0, 0], [1, 0]]]], - dtype=np.complex128, -) -SWAP_TENSOR = np.array( - [[[[1, 0], [0, 0]], [[0, 0], [1, 0]]], [[[0, 1], [0, 0]], [[0, 0], [0, 1]]]], - dtype=np.complex128, -) + EvolveSingleJit: TypeAlias = Callable[[npt.NDArray[np.complex128], npt.NDArray[np.complex128], int, int], None] # type introduced in 3.12 + ExpectationSingleJit: TypeAlias = Callable[ # type introduced in 3.12 + [npt.NDArray[np.complex128], npt.NDArray[np.complex128], int, int], complex + ] + EntangleJit: TypeAlias = Callable[[npt.NDArray[np.complex128], int, int, int], None] # type introduced in 3.12 +NUM_QUBIT_PARALLEL = 15 +"""This constant determines the number of qubits above which matrix operations are multi-threaded. For lower counts, the overhead does not compensate parallelization.""" + +# TODO: Use q for function parameters class Statevec(DenseState): - """Statevector object.""" + """Statevector object. + + Attributes + ---------- + psi : numpy.ndarray of numpy.complex128 + Complex-valued 1-dimensional array representing the quantum statevector. + Throughout the simulation ``psi`` has constant size ``2**max_qubits``. Only the first ``2**nqubit`` complex values have meaning. - psi: Matrix + _max_qubits : int + Maximum Hilbert space size allowed for internal computations. It determines the size of ``psi``. For circuit simulations, it corresponds to the number of qubits, while for pattern simulations it corresponds to the pattern's maximum space. + + _nqubit : int + Number of active qubits at any given time. + """ + + psi: npt.NDArray[np.complex128] + _max_qubits: int + _nqubit: int def __init__( - self, - data: Data = BasicStates.PLUS, - nqubit: int | None = None, + self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max_qubits: int | None = None ) -> None: """Initialize statevector objects. - `data` can be: - - a single :class:`graphix.states.State` (classical description of a quantum state) - - an iterable of :class:`graphix.states.State` objects - - an iterable of scalars (A 2**n numerical statevector) - - a *graphix.statevec.Statevec* object - - If *nqubit* is not provided, the number of qubit is inferred from *data* and checked for consistency. - If only one :class:`graphix.states.State` is provided and nqubit is a valid integer, initialize the statevector - in the tensor product state. - If both *nqubit* and *data* are provided, consistency of the dimensions is checked. - If a *graphix.statevec.Statevec* is passed, returns a copy. + See :class:`graphix.sim.statevec.Statevec` for additional information. Parameters ---------- data : Data, optional - input data to prepare the state. Can be a classical description or a numerical input, defaults to graphix.states.BasicStates.PLUS - nqubit : int, optional - number of qubits to prepare, defaults to None + Input data to prepare the state. Can be a classical description or a numerical input, defaults to `graphix.states.BasicStates.PLUS` + nqubit : int | None, optional + Number of qubits to prepare. If ``None`` (default), it's inferred from ``data``. + max_qubits : int | None, optional. + Maximum Hilbert space size for array preallocation. If ``None`` (default), it's set equal to ``nqubit``. + + Raises + ------ + ValueError + If `max_qubits` is smaller than `nqubit` or the number of qubits inferred from ``data``. """ if nqubit is not None and nqubit < 0: - raise ValueError("nqubit must be a non-negative integer.") + raise ValueError("`nqubit` must be a non-negative integer.") + + if max_qubits is not None and max_qubits < 0: + raise ValueError("`max_qubits` must be a non-negative integer.") if isinstance(data, Statevec): - # assert nqubit is None or len(state.flatten()) == 2**nqubit - if nqubit is not None and len(data.flatten()) != 2**nqubit: + if nqubit is not None and len(data.flatten()) != 1 << nqubit: raise ValueError( f"Inconsistent parameters between nqubit = {nqubit} and the inferred number of qubit = {len(data.flatten())}." ) self.psi = data.psi.copy() + self._max_qubits = data.max_qubits + self._nqubit = data.nqubit + + if max_qubits is not None: + if max_qubits < data.max_qubits: + raise ValueError( + f"`max_qubits` can't be smaller than the capacity of input state: {max_qubits} < {data.max_qubits}" + ) + self.ensure_capacity(max_qubits) return # The type # list[states.State] | list[ExpressionOrSupportsComplex] | list[Iterable[ExpressionOrSupportsComplex]] # would be more precise, but given a value X of type Iterable[A] | Iterable[B], # mypy infers that list(X) has type list[A | B] instead of list[A] | list[B]. - input_list: list[states.State | ExpressionOrSupportsComplex | Iterable[ExpressionOrSupportsComplex]] - if isinstance(data, states.State): + input_list: list[State | ExpressionOrSupportsComplex | Iterable[ExpressionOrSupportsComplex]] + if isinstance(data, State): if nqubit is None: nqubit = 1 input_list = [data] * nqubit @@ -104,52 +122,109 @@ def __init__( if len(input_list) == 0: if nqubit is not None and nqubit != 0: raise ValueError("nqubit is not null but input state is empty.") + nqubit = 0 + psi = np.array([1], dtype=np.complex128) - self.psi = np.array(1, dtype=np.complex128) - - elif isinstance(input_list[0], states.State): + elif isinstance(input_list[0], State): + length = len(input_list) if nqubit is None: - nqubit = len(input_list) - elif nqubit != len(input_list): - raise ValueError("Mismatch between nqubit and length of input state.") + nqubit = length + elif nqubit != length: + raise ValueError(f"Mismatch between nqubit and length of input state: {nqubit} != {length}.") def state_to_statevector( - s: states.State | ExpressionOrSupportsComplex | Iterable[ExpressionOrSupportsComplex], + s: State | ExpressionOrSupportsComplex | Iterable[ExpressionOrSupportsComplex], ) -> npt.NDArray[np.complex128]: - if not isinstance(s, states.State): + if not isinstance(s, State): raise TypeError("Data should be an homogeneous sequence of states.") return s.to_statevector() - list_of_sv = [state_to_statevector(s) for s in input_list] + psi = functools.reduce( + lambda m0, m1: np.kron(m0, m1).astype(np.complex128, copy=False), + (state_to_statevector(s) for s in input_list), + ) - tmp_psi = functools.reduce(lambda m0, m1: np.kron(m0, m1).astype(np.complex128), list_of_sv) - # reshape - self.psi = tmp_psi.reshape((2,) * nqubit) # `SupportsFloat` is needed because `numpy.float64` is not an instance of `SupportsComplex`! - elif isinstance(input_list[0], (Expression, SupportsComplex, SupportsFloat)): + elif isinstance(input_list[0], (SupportsComplex, SupportsFloat)): + length = len(input_list) + inferred_nqubit = length.bit_length() - 1 if nqubit is None: - length = len(input_list) if length & (length - 1): - raise ValueError("Length is not a power of two") - nqubit = length.bit_length() - 1 - elif nqubit != len(input_list).bit_length() - 1: - raise ValueError("Mismatch between nqubit and length of input state") - psi = np.array(input_list) - # check only if the matrix is not symbolic - if psi.dtype != "O" and not np.allclose(np.sqrt(np.sum(np.abs(psi) ** 2)), 1): + raise ValueError(f"Length of input data is not a power of two: {length}") + nqubit = inferred_nqubit + elif nqubit != inferred_nqubit: + raise ValueError(f"Mismatch between nqubit and inferred nqubit: {nqubit} != {inferred_nqubit}") + psi = np.array(input_list, dtype=np.complex128) + if not np.isclose(np.linalg.norm(psi), 1.0): raise ValueError("Input state is not normalized") - self.psi = psi.reshape((2,) * nqubit) + else: raise TypeError(f"First element of data has type {type(input_list[0])} whereas Number or State is expected") + if max_qubits is not None: + if max_qubits < nqubit: + raise ValueError( + f"`max_qubits` can't be smaller than the length of input state: {max_qubits} < {nqubit}" + ) + else: + max_qubits = nqubit + + self.psi = psi + self._max_qubits = nqubit # bootstrap for self.ensure_capacity + self._nqubit = nqubit + self.ensure_capacity(max_qubits) # may extend both self.psi and self._max_qubits + def __str__(self) -> str: """Return a string description.""" - return f"Statevec object with statevector {self.psi} and length {self.dims()}." + sv = self.psi + return f"Statevec object with statevector {sv} and length {len(sv)}." + + # Note that `@property` must appear before `@override` for pyright + @property + @override + def nqubit(self) -> int: + """Return the number of qubits.""" + return self._nqubit + + @property + def max_qubits(self) -> int: + """Return the preallocated number of qubits.""" + return self._max_qubits + + @property + def size_valid_psi(self) -> int: + """Return the number of meaningful elements in ``self.psi``.""" + return 1 << self.nqubit # 2**self.nqubit + + def ensure_capacity(self, required_qubits: int) -> None: + """Extend the state vector if the required qubit capacity exceeds the current one. + + Does nothing if ``required_qubits <= self.max_qubits``. + + Parameters + ---------- + required_qubits : int + Minimum number of qubits the state vector must support. If expansion + is needed, ``self.psi`` is extended to size ``2**required_qubits``. + """ + if required_qubits > self.max_qubits: + offset = (1 << required_qubits) - len(self.psi) + self.psi = np.concatenate([self.psi, np.empty(offset, dtype=self.psi.dtype)]) + self._max_qubits = required_qubits + + @override + def flatten(self) -> Matrix: + """Return flattened state. + + A view of only the first ``2**self.nqubit`` elements of ``self.psi`` is returned. + """ + return self.psi[: self.size_valid_psi] @override def add_nodes(self, nqubit: int, data: Data) -> None: - r""" - Add nodes (qubits) to the state vector and initialize them in a specified state. + r"""Add nodes (qubits) to the state vector and initialize them in a specified state. + + Previously existing nodes remain unchanged. Parameters ---------- @@ -163,16 +238,28 @@ def add_nodes(self, nqubit: int, data: Data) -> None: - If a list of basic states is provided, it must match the length of ``nodes``, and each node is initialized with its corresponding state. - A single-qubit state vector will be broadcast to all nodes. - - A multi-qubit state vector of dimension :math:`2^n`, where :math:`n = \mathrm{len}(nodes)`, - initializes the new nodes jointly. + - A multi-qubit state vector of dimension :math:`2^n`, where :math:`n = \mathrm{len}(nodes)`, initializes the new nodes jointly. Notes ----- - Previously existing nodes remain unchanged. + This method can extend the size of ``self.psi`` for convenience, but this requires allocating a full new array. """ + self.ensure_capacity(required_qubits=self.nqubit + nqubit) sv_to_add = Statevec(nqubit=nqubit, data=data) self.tensor(sv_to_add) + @override + def entangle(self, edge: tuple[int, int]) -> None: + """Connect graph nodes. + + Parameters + ---------- + edge : tuple of int + (control, target) qubit indices + """ + kernel = _entangle_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _entangle_jit + kernel(self.psi, self.nqubit, *edge) + @override def evolve_single(self, op: Matrix, i: int) -> None: """Apply a single-qubit operation. @@ -184,8 +271,30 @@ def evolve_single(self, op: Matrix, i: int) -> None: i : int qubit index """ - psi = tensordot(op, self.psi, (1, i)) - self.psi = np.moveaxis(psi, 0, i) + self._check_bounds(i) + kernel = _evolve_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _evolve_single_jit + # We cast to np.complex128 to match numba signature. + kernel(self.psi, op.astype(np.complex128), self.nqubit, i) + + @override + def expectation_single(self, op: Matrix, loc: int) -> complex: + """Return the expectation value of single-qubit operator. + + Parameters + ---------- + op : numpy.ndarray + 2*2 operator + loc : int + target qubit index + + Returns + ------- + complex : expectation value. + """ + self._check_bounds(loc) + kernel = _expectation_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _expectation_single_jit + # We cast to np.complex128 to match numba signature. + return kernel(self.psi, op.astype(np.complex128), self.nqubit, loc) @override def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: @@ -201,24 +310,62 @@ def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: op_dim = int(np.log2(len(op))) # TODO shape = (2,)* 2 * op_dim shape = [2 for _ in range(2 * op_dim)] + psi_t = self.flatten().reshape((2,) * self.nqubit) op_tensor = op.reshape(shape) - psi = tensordot( + psi = np.tensordot( op_tensor, - self.psi, + psi_t, (tuple(op_dim + i for i in range(len(qargs))), qargs), ) - self.psi = np.moveaxis(psi, range(len(qargs)), qargs) + self.psi[:self.size_valid_psi] = np.moveaxis(psi, range(len(qargs)), qargs).reshape(1<< self.nqubit) + + # @override + # def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: + # """Apply a multi-qubit operation. + + # Parameters + # ---------- + # op : numpy.ndarray + # 2^n*2^n matrix + # qargs : list of int + # target qubits' indices + # """ + # nq = len(qargs) + # # treat x as a tensor with ng output + ng input legs + # op_t = op.reshape((2,) * (nq * 2)) + # psi_t = self.flatten().reshape((2,) * self.nqubit) + + # state_idx = list(range(self.nqubit)) # [0, 1, 2, 3] + # out_idx = list(range(self.nqubit, self.nqubit + nq)) # [4, 5] + + # # x subscripts: [out_0, out_1, in_0, in_1] → [4, 5, 1, 3] + # xt_idx = out_idx + list(qargs) + + # # result subscripts: same as state but source slots replaced by out labels + # # [0, 4, 2, 5] + # res_idx = state_idx.copy() + # for i, s in enumerate(qargs): + # res_idx[s] = out_idx[i] + + # return np.einsum(op_t, xt_idx, psi_t, state_idx, res_idx).reshape(1 << self.nqubit) - def dims(self) -> tuple[int, ...]: - """Return the dimensions.""" - return self.psi.shape + def expectation_value(self, op: Matrix, qargs: Sequence[int]) -> complex: + """Return the expectation value of multi-qubit operator. - # Note that `@property` must appear before `@override` for pyright - @property - @override - def nqubit(self) -> int: - """Return the number of qubits.""" - return self.psi.ndim + Parameters + ---------- + op : numpy.ndarray + 2^n*2^n operator + qargs : list of int + target qubit indices + + Returns + ------- + complex : expectation value + """ + sv = deepcopy(self) + sv.evolve(op, qargs) + return complex(np.dot(self.flatten().conjugate(), sv.flatten())) @override def remove_qubit(self, qarg: int) -> None: @@ -260,61 +407,8 @@ def remove_qubit(self, qarg: int) -> None: qarg : int qubit index """ - norm = _norm(self.psi) - if isinstance(norm, SupportsFloat): - assert not np.isclose(norm, 0) - index: list[slice[int] | int] = [slice(None)] * self.psi.ndim - index[qarg] = 0 - psi = self.psi[tuple(index)] - norm = _norm(psi) - if isinstance(norm, SupportsFloat) and math.isclose(norm, 0): - index[qarg] = 1 - psi = self.psi[tuple(index)] - self.psi = psi - self.normalize() - - @override - def entangle(self, edge: tuple[int, int]) -> None: - """Connect graph nodes. - - Parameters - ---------- - edge : tuple of int - (control, target) qubit indices - """ - # contraction: 2nd index - control index, and 3rd index - target index. - psi = tensordot(CZ_TENSOR, self.psi, ((2, 3), edge)) - # sort back axes - self.psi = np.moveaxis(psi, (0, 1), edge) - - def tensor(self, other: Statevec) -> None: - r"""Tensor product state with other qubits. - - Results in self :math:`\otimes` other. - - Parameters - ---------- - other : :class:`graphix.sim.statevec.Statevec` - statevector to be tensored with self - """ - psi_self = self.psi.flatten() - psi_other = other.psi.flatten() - - total_num = len(self.dims()) + len(other.dims()) - self.psi = kron(psi_self, psi_other).reshape((2,) * total_num) - - def cnot(self, qubits: tuple[int, int]) -> None: - """Apply CNOT. - - Parameters - ---------- - qubits : tuple of int - (control, target) qubit indices - """ - # contraction: 2nd index - control index, and 3rd index - target index. - psi = tensordot(CNOT_TENSOR, self.psi, ((2, 3), qubits)) - # sort back axes - self.psi = np.moveaxis(psi, (0, 1), qubits) + self._check_bounds(qarg) + self._nqubit = _remove_qubit_jit(self.psi, self.nqubit, qarg, atol=1e-10) @override def swap(self, qubits: tuple[int, int]) -> None: @@ -325,72 +419,29 @@ def swap(self, qubits: tuple[int, int]) -> None: qubits : tuple of int (control, target) qubit indices """ - # contraction: 2nd index - control index, and 3rd index - target index. - psi = tensordot(SWAP_TENSOR, self.psi, ((2, 3), qubits)) - # sort back axes - self.psi = np.moveaxis(psi, (0, 1), qubits) - - def normalize(self) -> None: - """Normalize the state in-place.""" - # Note that the following calls to `astype` are guaranteed to - # return the original NumPy array itself, since `copy=False` and - # the `dtype` matches. This is important because the array is - # then modified in place. - if self.psi.dtype == np.object_: - psi_o = self.psi.astype(np.object_, copy=False) - norm_o = _norm_symbolic(psi_o) - psi_o /= norm_o - self.psi = psi_o - else: - psi_c = self.psi.astype(np.complex128, copy=False) - norm_c = _norm_numeric(psi_c) - psi_c /= norm_c - self.psi = psi_c + _swap_jit(self.psi, self.nqubit, *qubits) - def flatten(self) -> Matrix: - """Return flattened statevector.""" - return self.psi.flatten() + def tensor(self, other: Statevec) -> None: + r"""Tensor product state with other qubits. - @override - def expectation_single(self, op: Matrix, loc: int) -> complex: - """Return the expectation value of single-qubit operator. + Results in ``self`` :math:`\otimes` ``other``. Parameters ---------- - op : numpy.ndarray - 2*2 operator - loc : int - target qubit index - - Returns - ------- - complex : expectation value. + other : :class:`graphix.sim.statevec.Statevec` + Statevector to be tensored with ``self``. """ - st1 = copy.copy(self) - st1.normalize() - st2 = copy.copy(st1) - st1.evolve_single(op, loc) - return complex(np.dot(st2.psi.flatten().conjugate(), st1.psi.flatten())) - - def expectation_value(self, op: Matrix, qargs: Sequence[int]) -> complex: - """Return the expectation value of multi-qubit operator. + _tensor_jit(self.psi, other.psi, self.nqubit, other.nqubit) + self._nqubit += other.nqubit - Parameters - ---------- - op : numpy.ndarray - 2^n*2^n operator - qargs : list of int - target qubit indices + def _check_bounds(self, i: int) -> None: + """Check if qubit index is valid. - Returns - ------- - complex : expectation value + This check is necessary because there is no bounds checking in Numba. See + https://numba.pydata.org/numba-doc/dev/reference/pysemantics.html#bounds-checking """ - st2 = copy.copy(self) - st2.normalize() - st1 = copy.copy(st2) - st1.evolve(op, qargs) - return complex(np.dot(st2.psi.flatten().conjugate(), st1.psi.flatten())) + if not 0 <= i < self.nqubit: + raise IndexError(f"Qubit index {i} out of range [0, {self.nqubit})") def fidelity(self, other: Statevec) -> float: r"""Calculate the fidelity against another statevector. @@ -437,7 +488,7 @@ def to_dict( *, rtol: float = 0.0, atol: float = 1e-8, - ) -> dict[str, np.object_ | np.complex128]: + ) -> dict[str, np.object_ | np.complex128]: r"""Convert the statevector to dictionary form. This dictionary representation uses a ket-like notation where the dictionary ``keys`` are qubit strings for the basis vectors and ``values`` are the corresponding complex amplitudes. Amplitudes below a certain threshold are filtered out. @@ -488,7 +539,7 @@ def to_dict( def to_prob_dict( self, encoding: _ENCODING = "MSB", *, rtol: float = 0.0, atol: float = 1e-8 - ) -> dict[str, np.object_ | np.float64]: + ) -> dict[str, np.object_ | np.float64]: r"""Convert the statevector to a probability distirbution in a dictionary form. This dictionary representation uses a ket-like notation where the dictionary ``keys`` are qubit strings for the basis vectors and ``values`` are the corresponding probabilities. @@ -527,52 +578,285 @@ def _to_dict_map( *, rtol: float = 0.0, atol: float = 1e-8, - ) -> dict[str, _ScalarT]: + ) -> dict[str, _ScalarT]: mask = np.logical_not(np.isclose(np.abs(self.flatten()), 0, rtol=rtol, atol=atol)) i_vals = np.arange(1 << self.nqubit)[mask] amp_vals = f(self.flatten()[mask]) return {_format_encoding(self.nqubit, i, encoding): amp for i, amp in zip(i_vals, amp_vals, strict=True)} - def subs(self, variable: Parameter, substitute: ExpressionOrSupportsFloat) -> Statevec: - """Return a copy of the state vector where all occurrences of the given variable in measurement angles are substituted by the given value.""" - result = Statevec() - result.psi = np.vectorize(lambda value: parameter.subs(value, variable, substitute))(self.psi) - return result +#TODO: type **kwargs with Unpack +#TODO: Update tests +@dataclass(frozen=True) +class StatevectorBackend(DenseStateBackend[Statevec]): + """MBQC state vector backend simulator based on 10.48550/arXiv.2506.08142.""" - def xreplace(self, assignment: Mapping[Parameter, ExpressionOrSupportsFloat]) -> Statevec: - """Return a copy of the state vector where all occurrences of the given keys in measurement angles are substituted by the given values in parallel.""" - result = Statevec() - result.psi = np.vectorize(lambda value: parameter.xreplace(value, assignment))(self.psi) - return result + state: Statevec = dataclasses.field(init=True, default_factory=lambda: Statevec(nqubit=0)) + @classmethod + def with_capacity(cls, max_qubits: int, state: Statevec | None = None, **kwargs) -> Self: + """Initialize the backend with the required capacity to perform the simulation. -@dataclass(frozen=True) -class StatevectorBackend(DenseStateBackend[Statevec]): - """MBQC simulator with statevector method.""" + Parameters + ---------- + max_qubits : int + Number of qubits the state vector must support. For pattern simulations this corresponds to ``Pattern.max_space()``. + """ + state_init = ( + Statevec(nqubit=0, max_qubits=max_qubits) if state is None else Statevec(state, max_qubits=max_qubits) + ) + return cls(state_init, **kwargs) + + +@nb.njit("(c16[::1], c16[::1], int32, int32)") +def _tensor_jit( + psi: npt.NDArray[np.complex128], + psi_other: npt.NDArray[np.complex128], + nqubit: int, + nqubit_other: int, +) -> None: + size_psi = 1 << nqubit + size_other = 1 << nqubit_other + # We update the elements of `psi` in-place. + # This requires starting the update for the last element of the new psi, `size_psi * size_other - 1` + k = size_psi * size_other - 1 + sp_m1 = size_psi - 1 + so_m1 = size_other - 1 + + for i in range(size_psi): + alpha_old = psi[sp_m1 - i] + for j in range(size_other): + psi[k] = alpha_old * psi_other[so_m1 - j] + k -= 1 + + +@nb.njit("(c16[::1], int32, int32, int32)") +def _swap_jit(psi: npt.NDArray[np.complex128], nqubit: int, q1: int, q2: int) -> None: + + if q1 == q2: + return + size_sv = 1 << nqubit + mask_1 = 1 << nqubit - 1 - q1 + mask_2 = 1 << nqubit - 1 - q2 + mask = mask_1 | mask_2 + # `mask` is an integer number whose binary representation has 1s at positions `q1` and `q2` and 0s elsewhere. + + for i in range(size_sv): + # i & mask_1 = 2^(nqubit - 1 - q_1) if the binary representation of `i` has a 1 at position `q1` and 0 otherwise. + i_has_1_at_q1 = bool(i & mask_1) + i_has_1_at_q2 = bool(i & mask_2) + if i_has_1_at_q1 != i_has_1_at_q2: + # `j` has the same binary representation as `i` except for bits `q1` and `q2` which are flipped. + j = i ^ mask + if j > i: # Ensure we don't swap the same indices twice. + psi[j], psi[i] = psi[i], psi[j] + + +def _evolve_single(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, q: int) -> None: + r"""Apply a single-qubit operation. + + This function is inspired from 10.48550/arXiv.2506.08142. + """ + nblocks = 1 << q + size_block = 1 << nqubit - q # 2**(nqubit - q) + size_half_block = ( + size_block >> 1 + ) # Left-to-right tensor product encoding (first qubit corresponds to most significant bit). For right-to-left encoding use `size_half_block = 1 << i` + + for b in nb.prange(nblocks): + # WARNING: setting `b0 += size_block` may result in a race condition if `parallel=True` + b0 = size_block * b + for offset in range(size_half_block): + i1 = b0 | offset + i2 = i1 | size_half_block + psi1 = psi[i1] + psi2 = psi[i2] + psi[i1] = op[0, 0] * psi1 + op[0, 1] * psi2 + psi[i2] = op[1, 0] * psi1 + op[1, 1] * psi2 + + +_evolve_single_jit: EvolveSingleJit = nb.njit("(c16[::1], c16[:, :], int32, int32)", parallel=False)(_evolve_single) +_evolve_single_jit_parallel: EvolveSingleJit = nb.njit("(c16[::1], c16[:, :], int32, int32)", parallel=True)( + _evolve_single +) - state: Statevec = dataclasses.field(init=False, default_factory=lambda: Statevec(nqubit=0)) +def _expectation_single( + psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, q: int +) -> complex: + nblocks = 1 << q + size_block = 1 << nqubit - q + size_half_block = ( + size_block >> 1 + ) # Left-to-right tensor product encoding (first qubit corresponds to most significant bit). For right-to-left encoding use `size_half_block = 1 << i` -def _norm_symbolic(psi: npt.NDArray[np.object_]) -> ExpressionOrFloat: - """Return norm of the state.""" - flat = psi.flatten() - return check_expression_or_float(np.sqrt(np.sum(flat.conj() * flat))) + result = 0.0 + 0.0j + for b in nb.prange(nblocks): + # WARNING: setting `b0 += size_block` may result in a race condition if `parallel=True` + b0 = b << nqubit - q + for offset in range(size_half_block): + i1 = b0 | offset + i2 = i1 | size_half_block + psi1 = psi[i1] + psi2 = psi[i2] + b1 = op[0, 0] * psi1 + op[0, 1] * psi2 + b2 = op[1, 0] * psi1 + op[1, 1] * psi2 + result += psi1.conjugate() * b1 + psi2.conjugate() * b2 -def _norm_numeric(psi: npt.NDArray[np.complex128]) -> float: - flat = psi.flatten() - norm_sq = np.sum(flat.conj() * flat) - assert math.isclose(norm_sq.imag, 0, abs_tol=1e-15) - return math.sqrt(norm_sq.real) + return result -def _norm(psi: Matrix) -> ExpressionOrFloat: - """Return norm of the state.""" - # Narrow psi to concrete dtype - if psi.dtype == np.object_: - return _norm_symbolic(psi.astype(np.object_, copy=False)) - return _norm_numeric(psi.astype(np.complex128, copy=False)) +_expectation_single_jit: ExpectationSingleJit = nb.njit("c16(c16[::1], c16[:, :], int32, int32)", parallel=False)( + _expectation_single +) +_expectation_single_jit_parallel: ExpectationSingleJit = nb.njit( + "c16(c16[::1], c16[:, :], int32, int32)", parallel=True +)(_expectation_single) + + +def _entangle(psi: npt.NDArray[np.complex128], nqubit: int, control: int, target: int) -> None: + size_sv = 1 << nqubit + mask_control = 1 << nqubit - 1 - control + mask_target = 1 << nqubit - 1 - target + mask = mask_control | mask_target + # `mask` is an integer number whose binary representation has 1s at positions `control` and `target` and 0s elsewhere. + + for i in nb.prange(size_sv): + if mask & i == mask: + psi[i] = -psi[i] + + +_entangle_jit: EntangleJit = nb.njit("(c16[::1], int32, int32, int32)", parallel=False)(_entangle) +_entangle_jit_parallel: EntangleJit = nb.njit("(c16[::1], int32, int32, int32)", parallel=True)(_entangle) + + +@nb.njit("int32(c16[::1], int32, int32, f8)", parallel=False) +def _remove_qubit_jit( + psi: npt.NDArray[np.complex128], + nqubit: int, + q: int, + atol: float, +) -> int: + new_nqubit = nqubit - 1 + + n_blocks = 1 << q + size_block = 1 << nqubit - q # 2**(nqubits - q) + size_half_block = size_block >> 1 + + # Compute norm of branch 0 + norm2 = 0.0 + shift = 0 + b0 = shift + for _ in range(n_blocks): + # If parallelization, set `b0 = b * size_block + shift` with `b` the loop variable to avoid race condition. + # Parallelization for norm computation is not worth, execution-time controlled by the update loop which can't be parallelized without cache. + for j in range(size_half_block): + a = psi[b0 | j] + a_re = a.real + a_im = a.imag + norm2 += a_re * a_re + a_im * a_im + b0 += size_block + + # If norm of branch 0 is 0, compute norm of branch 1 and set shift to branch 1 + if norm2 <= atol: + norm2 = 0 + shift = size_half_block + b0 = shift + for _ in range(n_blocks): + for j in range(size_half_block): + a = psi[b0 | j] + a_re = a.real + a_im = a.imag + norm2 += a_re * a_re + a_im * a_im + b0 += size_block + + b0 = shift + k = 0 + inv_norm = 1.0 / math.sqrt(norm2) + + # Update `psi` with selected and normalized elements. + for _ in range(n_blocks): + for j in range(size_half_block): + psi[k] = ( + psi[b0 | j] * inv_norm + ) # b0 | j equivalent to b0 + j because the active bits of b0 and j don't overlap. + k += 1 + b0 += size_block + + return new_nqubit + + + + +# @override +# def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: +# """Apply a multi-qubit operation. + +# Parameters +# ---------- +# op : numpy.ndarray +# 2^n*2^n matrix +# qargs : list of int +# target qubits' indices +# """ +# op_dim = int(np.log2(len(op))) +# # TODO shape = (2,)* 2 * op_dim +# shape = [2 for _ in range(2 * op_dim)] +# op_tensor = op.reshape(shape) +# psi = tensordot( +# op_tensor, +# self.psi, +# (tuple(op_dim + i for i in range(len(qargs))), qargs), +# ) +# self.psi = np.moveaxis(psi, range(len(qargs)), qargs) + + + + +# def normalize(self) -> None: +# """Normalize the state in-place.""" +# # Note that the following calls to `astype` are guaranteed to +# # return the original NumPy array itself, since `copy=False` and +# # the `dtype` matches. This is important because the array is +# # then modified in place. +# if self.psi.dtype == np.object_: +# psi_o = self.psi.astype(np.object_, copy=False) +# norm_o = _norm_symbolic(psi_o) +# psi_o /= norm_o +# self.psi = psi_o +# else: +# psi_c = self.psi.astype(np.complex128, copy=False) +# norm_c = _norm_numeric(psi_c) +# psi_c /= norm_c +# self.psi = psi_c + + + + + + + + +# def _norm_symbolic(psi: npt.NDArray[np.object_]) -> ExpressionOrFloat: +# """Return norm of the state.""" +# flat = psi.flatten() +# return check_expression_or_float(np.sqrt(np.sum(flat.conj() * flat))) + + +# def _norm_numeric(psi: npt.NDArray[np.complex128]) -> float: +# flat = psi.flatten() +# norm_sq = np.sum(flat.conj() * flat) +# assert math.isclose(norm_sq.imag, 0, abs_tol=1e-15) +# return math.sqrt(norm_sq.real) + + +# def _norm(psi: Matrix) -> ExpressionOrFloat: +# """Return norm of the state.""" +# # Narrow psi to concrete dtype +# if psi.dtype == np.object_: +# return _norm_symbolic(psi.astype(np.object_, copy=False)) +# return _norm_numeric(psi.astype(np.complex128, copy=False)) def _format_encoding(nqubit: int, i: int, encoding: _ENCODING) -> str: diff --git a/graphix/transpiler.py b/graphix/transpiler.py index c009b62b0..1c4015d88 100644 --- a/graphix/transpiler.py +++ b/graphix/transpiler.py @@ -989,9 +989,7 @@ def evolve(op: Matrix, qargs: Iterable[int]) -> None: match instr.kind: case instruction.InstructionKind.CNOT: - backend.state.cnot( - (backend.node_index.index(instr.control), backend.node_index.index(instr.target)) - ) + evolve(Ops.CNOT, [instr.control, instr.target]) case instruction.InstructionKind.SWAP: u, v = instr.targets backend.state.swap((backend.node_index.index(u), backend.node_index.index(v))) diff --git a/tests/test_density_matrix.py b/tests/test_density_matrix.py index 7c67909c5..44db6fc92 100644 --- a/tests/test_density_matrix.py +++ b/tests/test_density_matrix.py @@ -15,8 +15,8 @@ from graphix.channels import KrausChannel, dephasing_channel, depolarising_channel from graphix.fundamentals import ANGLE_PI, Plane from graphix.ops import Ops -from graphix.sim.density_matrix import DensityMatrix, DensityMatrixBackend -from graphix.sim.statevec import CNOT_TENSOR, CZ_TENSOR, SWAP_TENSOR, Statevec +from graphix.sim.density_matrix import CNOT_TENSOR, CZ_TENSOR, SWAP_TENSOR, DensityMatrix, DensityMatrixBackend +from graphix.sim.statevec import Statevec from graphix.simulator import DefaultMeasureMethod from graphix.states import BasicStates, PlanarState from graphix.transpiler import Circuit diff --git a/tests/test_statevec.py b/tests/test_statevec.py index e7ce8d925..c31fca771 100644 --- a/tests/test_statevec.py +++ b/tests/test_statevec.py @@ -1,15 +1,15 @@ from __future__ import annotations -import functools from typing import TYPE_CHECKING import numpy as np +import numpy.typing as npt import pytest +from numpy.random import Generator -from graphix.fundamentals import ANGLE_PI, Plane -from graphix.pattern import Pattern -from graphix.sim.statevec import Statevec, _norm_numeric -from graphix.states import BasicStates, PlanarState +from graphix.clifford import Clifford +from graphix.sim.statevec import Statevec +from graphix.states import BasicStates if TYPE_CHECKING: from collections.abc import Mapping @@ -19,149 +19,232 @@ _ENCODING = Literal["LSB", "MSB"] + from graphix.states import State + + +def generate_rnd_data(rng: Generator, nqubits: int) -> npt.NDArray[np.complex128]: + length = 1 << nqubits + data = rng.random(length) + 1j * rng.random(length) + data /= np.sqrt(np.sum(np.abs(data) ** 2)) + return data -class TestStatevec: - """Test for Statevec class. Particularly new constructor.""" - - # test initializing one qubit in plus state - def test_default_success(self) -> None: - vec = Statevec(nqubit=1) - assert np.allclose(vec.psi, np.array([1, 1] / np.sqrt(2))) - assert len(vec.dims()) == 1 - - def test_basicstates_success(self) -> None: - # minus - vec = Statevec(nqubit=1, data=BasicStates.MINUS) - assert np.allclose(vec.psi, np.array([1, -1] / np.sqrt(2))) - assert len(vec.dims()) == 1 - - # zero - vec = Statevec(nqubit=1, data=BasicStates.ZERO) - assert np.allclose(vec.psi, np.array([1, 0]), rtol=0, atol=1e-15) - assert len(vec.dims()) == 1 - - # one - vec = Statevec(nqubit=1, data=BasicStates.ONE) - assert np.allclose(vec.psi, np.array([0, 1]), rtol=0, atol=1e-15) - assert len(vec.dims()) == 1 - - # plus_i - vec = Statevec(nqubit=1, data=BasicStates.PLUS_I) - assert np.allclose(vec.psi, np.array([1, 1j] / np.sqrt(2))) - assert len(vec.dims()) == 1 - - # minus_i - vec = Statevec(nqubit=1, data=BasicStates.MINUS_I) - assert np.allclose(vec.psi, np.array([1, -1j] / np.sqrt(2))) - assert len(vec.dims()) == 1 - - # even more tests? - def test_default_tensor_success(self, fx_rng: Generator) -> None: - nqb = int(fx_rng.integers(2, 5)) - print(f"nqb is {nqb}") - vec = Statevec(nqubit=nqb) - assert np.allclose(vec.psi, np.ones((2,) * nqb) / (np.sqrt(2)) ** nqb) - assert len(vec.dims()) == nqb - - vec = Statevec(nqubit=nqb, data=BasicStates.MINUS_I) - sv_list = [BasicStates.MINUS_I.to_statevector() for _ in range(nqb)] - sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) - assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) - assert len(vec.dims()) == nqb - - # tensor of same state - rand_angle = fx_rng.random() * 2 * ANGLE_PI - rand_plane = fx_rng.choice(np.array(Plane)) - state = PlanarState(rand_plane, rand_angle) - vec = Statevec(nqubit=nqb, data=state) - sv_list = [state.to_statevector() for _ in range(nqb)] - sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) - assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) - assert len(vec.dims()) == nqb - - # tensor of different states - rand_angles = fx_rng.random(nqb) * 2 * ANGLE_PI - rand_planes = fx_rng.choice(np.array(Plane), nqb) - states = [PlanarState(plane=i, angle=j) for i, j in zip(rand_planes, rand_angles, strict=True)] - vec = Statevec(nqubit=nqb, data=states) - sv_list = [state.to_statevector() for state in states] - sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) - assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) - assert len(vec.dims()) == nqb - - def test_data_success(self, fx_rng: Generator) -> None: - nqb = fx_rng.integers(2, 5) - length = 2**nqb - rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) - rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) - vec = Statevec(data=rand_vec) - assert np.allclose(vec.psi, rand_vec.reshape((2,) * nqb)) - assert len(vec.dims()) == nqb - # fail: incorrect len - def test_data_dim_fail(self, fx_rng: Generator) -> None: - length = 5 +class TestInit: + N_JUMPS = 3 + + @pytest.mark.parametrize( + ("state", "data_ref"), + [ + (BasicStates.PLUS, np.array([1, 1] / np.sqrt(2))), + (BasicStates.MINUS, np.array([1, -1] / np.sqrt(2))), + (BasicStates.ZERO, np.array([1, 0])), + (BasicStates.ONE, np.array([0, 1])), + (BasicStates.PLUS_I, np.array([1, 1j] / np.sqrt(2))), + (BasicStates.MINUS_I, np.array([1, -1j] / np.sqrt(2))), + ], + ) + def test_init_basic_states(self, state: State, data_ref: npt.NDArray[np.complex128]) -> None: + sv = Statevec(data=state) + assert np.allclose(sv.flatten(), data_ref) + + @pytest.mark.parametrize("nqubit", range(5)) + def test_init_random_state(self, fx_rng: Generator, nqubit: int) -> None: + data = generate_rnd_data(fx_rng, nqubit) + sv = Statevec(data) + assert np.allclose(sv.flatten(), data) + + def test_init_preallocation(self) -> None: + nqubit = 2 + max_qubits = 5 + sv = Statevec(data=[BasicStates.PLUS, BasicStates.ZERO], nqubit=nqubit, max_qubits=max_qubits) + + assert np.allclose(sv.flatten(), np.array([1, 0, 1, 0]) / np.sqrt(2)) + assert sv.nqubit == nqubit + assert sv.max_qubits == max_qubits + assert len(sv.psi) == 2**max_qubits + + @pytest.mark.parametrize("nqubit", range(5)) + def test_init_statevec(self, fx_rng: Generator, nqubit: int) -> None: + data = generate_rnd_data(fx_rng, nqubit) + sv_1 = Statevec(data) + sv_2 = Statevec(sv_1) + assert np.allclose(sv_1.psi, sv_2.psi) + assert sv_1.nqubit == sv_2.nqubit + assert sv_1.max_qubits == sv_2.max_qubits + + @pytest.mark.parametrize("nqubit", range(5)) + def test_init_statevec_max_qubits(self, fx_rng: Generator, nqubit: int) -> None: + data = generate_rnd_data(fx_rng, nqubit) + sv_1 = Statevec(data) + sv_2 = Statevec(data=sv_1, max_qubits=nqubit + 1) + assert np.allclose(sv_1.flatten(), sv_2.flatten()) + assert sv_1.nqubit == sv_2.nqubit + assert sv_1.max_qubits + 1 == sv_2.max_qubits + + # fail: length data is not a power of 2 + @pytest.mark.parametrize("length", [3, 5, 6, 7]) + def test_init_dim_fail(self, fx_rng: Generator, length: int) -> None: rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) with pytest.raises(ValueError): - _vec = Statevec(data=rand_vec) + Statevec(data=rand_vec) - # fail: with less qubit than number of qubits inferred from a correct state vect - def test_data_dim_fail_mismatch(self, fx_rng: Generator) -> None: - nqb = 3 - rand_vec = fx_rng.random(2**nqb) + 1j * fx_rng.random(2**nqb) - rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) + # fail: different qubit than number of qubits inferred from data + @pytest.mark.parametrize("nqubit", [2, 4]) + def test_init_dim_mismatch_fail(self, fx_rng: Generator, nqubit: int) -> None: + data = generate_rnd_data(fx_rng, nqubit) with pytest.raises(ValueError): - _vec = Statevec(nqubit=2, data=rand_vec) + Statevec(nqubit=3, data=data) # fail: not normalized - def test_data_norm_fail(self, fx_rng: Generator) -> None: - nqb = fx_rng.integers(2, 5) - length = 2**nqb - rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) + def test_init_norm_fail(self, fx_rng: Generator) -> None: + data = 5 * generate_rnd_data(fx_rng, 3) with pytest.raises(ValueError): - _vec = Statevec(data=rand_vec) + Statevec(data=data) - def test_defaults_to_one(self) -> None: - vec = Statevec() - assert len(vec.dims()) == 1 + # fail: max qubits smaller than number of qubits + def test_init_max_qubits_fail(self) -> None: + nqubit = 4 + max_qubits = 3 + with pytest.raises(ValueError): + Statevec(nqubit=nqubit, max_qubits=max_qubits) - # try copying Statevec input - def test_copy_success(self, fx_rng: Generator) -> None: - nqb = fx_rng.integers(2, 5) - length = 2**nqb - rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) - rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) - test_vec = Statevec(data=rand_vec) - # try to copy it - vec = Statevec(data=test_vec) + # fail: incorrect number of qubits + @pytest.mark.parametrize("nqubit", range(5)) + def test_init_statevec_fail(self, fx_rng: Generator, nqubit: int) -> None: + data = generate_rnd_data(fx_rng, nqubit) + sv_1 = Statevec(data) + with pytest.raises(ValueError): + Statevec(data=sv_1, nqubit=nqubit + 1) - assert np.allclose(vec.psi, test_vec.psi) - assert len(vec.dims()) == len(test_vec.dims()) + # fail: incorrect max_qubits qubits + @pytest.mark.parametrize("nqubit", range(5)) + def test_init_statevec_max_qubits_fail(self, fx_rng: Generator, nqubit: int) -> None: + data = generate_rnd_data(fx_rng, nqubit) + sv_1 = Statevec(data=data, max_qubits=6) + with pytest.raises(ValueError): + Statevec(data=sv_1, max_qubits=nqubit + 1) - # try calling with incorrect number of qubits compared to inferred one - def test_copy_fail(self, fx_rng: Generator) -> None: - nqb = int(fx_rng.integers(2, 5)) - length = 1 << nqb - rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) - rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) - test_vec = Statevec(data=rand_vec) - with pytest.raises(ValueError): - _vec = Statevec(nqubit=length - 1, data=test_vec) +class TestSimulation: + @pytest.mark.parametrize( + ("sv", "edge", "data_ref"), + [ + (Statevec(data=BasicStates.ZERO, nqubit=2), (0, 1), np.array([1, 0, 0, 0])), + (Statevec(data=[BasicStates.PLUS, BasicStates.PLUS]), (0, 1), np.array([1, 1, 1, -1]) / 2), + (Statevec(data=[BasicStates.ONE, BasicStates.MINUS]), (0, 1), np.array([0, 0, 1, 1]) / np.sqrt(2)), + ( + Statevec(data=np.array([1, 0, 0, 0, 0, 0, 0, 1]) / np.sqrt(2)), + (0, 2), + np.array([1, 0, 0, 0, 0, 0, 0, -1]) / np.sqrt(2), + ), + ], + ) + def test_entangle(self, sv: Statevec, edge: tuple[int, int], data_ref: npt.NDArray[np.complex128]) -> None: + sv.entangle(edge) + assert np.allclose(sv.flatten(), data_ref) + + @pytest.mark.parametrize( + ("sv", "q", "op", "data_ref"), + [ + (Statevec(data=BasicStates.ZERO, nqubit=2), 0, Clifford.X.matrix, np.array([0, 0, 1, 0])), + ( + Statevec(data=[BasicStates.PLUS, BasicStates.PLUS]), + 1, + Clifford.H.matrix, + np.array([1, 0, 1, 0]) / np.sqrt(2), + ), + ( + Statevec(data=[BasicStates.PLUS, BasicStates.MINUS]), + 0, + np.array([[1, 0], [0, np.exp(0.25j * np.pi)]]), + np.array([1, -1, np.exp(0.25j * np.pi), -np.exp(0.25j * np.pi)]) / 2, + ), + ( + Statevec(data=np.array([1, 0, 0, 0, 0, 0, 0, 1]) / np.sqrt(2)), + 1, + Clifford.Z.matrix, + np.array([1, 0, 0, 0, 0, 0, 0, -1]) / np.sqrt(2), + ), + ], + ) + def test_evolve_single( + self, sv: Statevec, q: int, op: npt.NDArray[np.complex128], data_ref: npt.NDArray[np.complex128] + ) -> None: + sv.evolve_single(op, q) + assert np.allclose(sv.flatten(), data_ref) - def test_nqubits(self) -> None: - for i in [1, 2, 5]: - sv = Statevec(nqubit=i) - assert sv.nqubit == i + @pytest.mark.parametrize( + ("sv", "q", "op", "exp_ref"), + [ + (Statevec(data=BasicStates.ZERO, nqubit=2), 0, Clifford.X.matrix, 0), + (Statevec(data=[BasicStates.PLUS, BasicStates.PLUS]), 1, Clifford.H.matrix, 1 / np.sqrt(2)), + ( + Statevec(data=[BasicStates.PLUS, BasicStates.MINUS]), + 0, + np.array([[1, 0], [0, np.exp(0.25j * np.pi)]]), + (1 + np.exp(0.25j * np.pi)) / 2, + ), + ( + Statevec(data=np.array([1, 0, 0, 0, 0, 0, 0, 1]) / np.sqrt(2)), + 1, + Clifford.Z.matrix, + 0, + ), + ], + ) + def test_expectation_single( + self, sv: Statevec, q: int, op: npt.NDArray[np.complex128], exp_ref: np.complex128 + ) -> None: + assert np.isclose(sv.expectation_single(op, q), exp_ref) - def test_nqubits_pattern(self) -> None: - p = Pattern(input_nodes=[0, 1, 2]) - sv = p.simulate_pattern(backend="statevector") - assert sv.nqubit == 3 + def test_add_nodes(self, fx_rng: Generator) -> None: + max_qubits = 5 + sv_test = Statevec(nqubit=0, max_qubits=max_qubits) + psi_ref = np.array([1.0 + 0.0j]) + for _ in range(max_qubits): # Add a node at each iteration + data = generate_rnd_data(fx_rng, nqubits=1) + psi_ref = np.kron(psi_ref, data) + sv_test.add_nodes(1, data) + assert np.allclose(sv_test.flatten(), psi_ref) -class TestFidelityIsclose: + def test_add_nodes_beyond_max_qubits(self, fx_rng: Generator) -> None: + max_qubits = 3 + sv_test = Statevec(nqubit=max_qubits, max_qubits=max_qubits) + + # We create a reference to `psi` to ensure that array is not extended with np.ndarray.resize + psi_ref = sv_test.psi # noqa: F841 + + nqubits_new = 2 + data = generate_rnd_data(fx_rng, nqubits=nqubits_new) + psi = np.kron(sv_test.psi, data) + + sv_test.add_nodes(nqubits_new, data) + assert np.allclose(sv_test.flatten(), psi) + + @pytest.mark.parametrize( + ("sv", "q", "sv_ref"), + [ + (Statevec(data=BasicStates.ZERO, nqubit=2), 0, Statevec(data=BasicStates.ZERO, nqubit=1)), + (Statevec(data=[BasicStates.PLUS, BasicStates.PLUS]), 1, Statevec(data=BasicStates.PLUS, nqubit=1)), + (Statevec(data=[BasicStates.PLUS, BasicStates.MINUS]), 0, Statevec(data=BasicStates.MINUS, nqubit=1)), + (Statevec(data=[BasicStates.ZERO, BasicStates.ONE]), 0, Statevec(data=BasicStates.ONE, nqubit=1)), + # In previous testcase, branch 1 is 0 (psi_10 == psi_11 == 0), and first element of branch 0 is 0 too (psi_00 == 0)! + ( + Statevec(data=[BasicStates.PLUS_I, BasicStates.ONE, BasicStates.PLUS]), + 1, + Statevec(data=[BasicStates.PLUS_I, BasicStates.PLUS], nqubit=2), + ), + ], + ) + def test_remove_qubit(self, sv: Statevec, q: int, sv_ref: Statevec) -> None: + sv.remove_qubit(q) + assert np.allclose(sv.flatten(), sv_ref.flatten()) + + +# TODO: Refactor using parametrize +class TestFidelity: def test_fidelity_same_state(self) -> None: state = Statevec(data=BasicStates.PLUS) assert state.fidelity(state) == pytest.approx(1) @@ -212,34 +295,327 @@ def test_isclose_tolerance(self) -> None: assert not zero.isclose(almost) assert zero.isclose(almost, atol=1e-6) - @pytest.mark.parametrize( - ("encoding", "dict_ref"), - [ - ("LSB", {"000": 0.5, "010": 0.5, "100": -0.5, "110": -0.5}), - ("MSB", {"000": 0.5, "010": 0.5, "001": -0.5, "011": -0.5}), - ], - ) - def test_to_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: - sv = Statevec(data=[BasicStates.ZERO, BasicStates.PLUS, BasicStates.MINUS]) - for ket, amp in sv.to_dict(encoding=encoding).items(): - assert np.isclose(dict_ref[ket], amp.real) - assert np.isclose(0, amp.imag) - @pytest.mark.parametrize( - ("encoding", "dict_ref"), - [ - ("LSB", {"001": 0.25, "011": 0.25, "101": 0.25, "111": 0.25}), - ("MSB", {"100": 0.25, "110": 0.25, "101": 0.25, "111": 0.25}), - ], - ) - def test_to_prob_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: - sv = Statevec(data=[BasicStates.ONE, BasicStates.PLUS, BasicStates.MINUS]) - for ket, amp2 in sv.to_prob_dict(encoding=encoding).items(): - assert np.isclose(dict_ref[ket], amp2.real) - assert np.isclose(0, amp2.imag) +@pytest.mark.parametrize( + ("encoding", "dict_ref"), + [ + ("LSB", {"000": 0.5, "010": 0.5, "100": -0.5, "110": -0.5}), + ("MSB", {"000": 0.5, "010": 0.5, "001": -0.5, "011": -0.5}), + ], +) +def test_to_dict(encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: + sv = Statevec(data=[BasicStates.ZERO, BasicStates.PLUS, BasicStates.MINUS]) + for ket, amp in sv.to_dict(encoding=encoding).items(): + assert np.isclose(dict_ref[ket], amp.real) + assert np.isclose(0, amp.imag) + +@pytest.mark.parametrize( + ("encoding", "dict_ref"), + [ + ("LSB", {"001": 0.25, "011": 0.25, "101": 0.25, "111": 0.25}), + ("MSB", {"100": 0.25, "110": 0.25, "101": 0.25, "111": 0.25}), + ], +) +def test_to_prob_dict(encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: + sv = Statevec(data=[BasicStates.ONE, BasicStates.PLUS, BasicStates.MINUS]) + for ket, amp2 in sv.to_prob_dict(encoding=encoding).items(): + assert np.isclose(dict_ref[ket], amp2.real) + assert np.isclose(0, amp2.imag) + + +# class TestStatevecLegacy: +# """Tests in this class compare the result against the existing statevector simulator in Graphix. They are not self-contained.""" + +# N_JUMPS = 3 + +# @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) +# def test_entangle(self, fx_bg: PCG64, jumps: int) -> None: +# rng = Generator(fx_bg.jumped(jumps)) +# nqubits = 5 +# sv_test = Statevec(generate_rnd_data(rng, nqubits)) +# sv_ref = SVLegacy(data=sv_test.flatten()) +# edge: tuple[int, int] = tuple(rng.choice(range(nqubits), size=2, replace=False)) +# for sv in [sv_test, sv_ref]: +# sv.entangle(edge) + +# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) + +# @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) +# def test_swap(self, fx_bg: PCG64, jumps: int) -> None: +# rng = Generator(fx_bg.jumped(jumps)) +# nqubits = 5 +# sv_test = Statevec(generate_rnd_data(rng, nqubits)) +# sv_ref = SVLegacy(data=sv_test.flatten()) +# edge: tuple[int, int] = tuple(rng.choice(range(nqubits), size=2, replace=False)) +# for sv in [sv_test, sv_ref]: +# sv.swap(edge) +# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) -def test_normalize() -> None: - statevec = Statevec(nqubit=1, data=BasicStates.PLUS) - statevec.remove_qubit(0) - assert _norm_numeric(statevec.psi.astype(np.complex128, copy=False)) == 1 +# def test_evolve_single(self, fx_rng: Generator) -> None: +# nqubits = 5 +# for clifford in Clifford: +# sv_test = Statevec(generate_rnd_data(fx_rng, nqubits)) +# sv_ref = SVLegacy(data=sv_test.flatten()) +# qubit = int(fx_rng.integers(0, nqubits)) +# for sv in [sv_test, sv_ref]: +# sv.evolve_single(clifford.matrix, qubit) +# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) + +# def test_expectation_single(self, fx_rng: Generator) -> None: +# nqubits = 5 +# for clifford in Clifford: +# sv_test = Statevec(generate_rnd_data(fx_rng, nqubits)) +# sv_ref = SVLegacy(data=sv_test.flatten()) +# qubit = int(fx_rng.integers(0, nqubits)) + +# val_test = sv_test.expectation_single(clifford.matrix, qubit) +# val_ref = sv_ref.expectation_single(clifford.matrix, qubit) + +# assert math.isclose(val_test.real, val_ref.real, abs_tol=1e-12) +# assert math.isclose(val_test.imag, val_ref.imag, abs_tol=1e-12) + +# def test_add_nodes(self, fx_rng: Generator) -> None: + +# max_qubits = 5 +# sv_test = Statevec(nqubit=0, max_qubits=max_qubits) +# sv_ref = SVLegacy(nqubit=0) + +# for _ in range(max_qubits): # Add a node at each iteration +# data = generate_rnd_data(fx_rng, nqubits=1) +# sv_test.add_nodes(1, data) +# sv_ref.add_nodes(1, data) + +# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) + +# @pytest.mark.parametrize( +# "projector", [np.array([[1, 0], [0, 0]], dtype=np.complex128), np.array([[0, 0], [0, 1]], dtype=np.complex128)] +# ) +# def test_remove_nodes(self, fx_rng: Generator, projector: npt.NDArray[np.complex128]) -> None: + +# nqubits = 5 +# sv_test = Statevec(generate_rnd_data(fx_rng, nqubits)) +# sv_ref = SVLegacy(data=sv_test.flatten()) +# q = 0 +# for _ in range(nqubits - 1): # Remove a node at each iteration +# sv_test.evolve_single(projector, q) +# sv_test.remove_qubit(q) +# sv_ref.evolve_single(projector, q) +# sv_ref.remove_qubit(q) + +# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) + + +# @pytest.mark.parametrize("jumps", range(1, 6)) +# def test_pattern_simulator(fx_bg: PCG64, jumps: int) -> None: +# rng = Generator(fx_bg.jumped(jumps)) + +# nqubits = 5 + +# pattern = rand_circuit(nqubits, depth=5, rng=rng).transpile().pattern +# pattern.remove_pauli_measurements() + +# backend = StatevectorBackend.with_capacity(pattern.max_space()) +# sv_test = pattern.simulate_pattern(backend=backend, rng=rng) +# sv_ref = pattern.simulate_pattern(backend=SBLegacy(), rng=rng) + +# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) + + + +# from __future__ import annotations + +# import functools +# from typing import TYPE_CHECKING + +# import numpy as np +# import pytest + +# from graphix.fundamentals import ANGLE_PI, Plane +# from graphix.pattern import Pattern +# from graphix.sim.statevec import Statevec, _norm_numeric +# from graphix.states import BasicStates, PlanarState + +# if TYPE_CHECKING: +# from collections.abc import Mapping +# from typing import Literal + +# from numpy.random import Generator + +# _ENCODING = Literal["LSB", "MSB"] + + +# class TestStatevec: +# """Test for Statevec class. Particularly new constructor.""" + +# # test initializing one qubit in plus state +# def test_default_success(self) -> None: +# vec = Statevec(nqubit=1) +# assert np.allclose(vec.psi, np.array([1, 1] / np.sqrt(2))) +# assert len(vec.dims()) == 1 + +# def test_basicstates_success(self) -> None: +# # minus +# vec = Statevec(nqubit=1, data=BasicStates.MINUS) +# assert np.allclose(vec.psi, np.array([1, -1] / np.sqrt(2))) +# assert len(vec.dims()) == 1 + +# # zero +# vec = Statevec(nqubit=1, data=BasicStates.ZERO) +# assert np.allclose(vec.psi, np.array([1, 0]), rtol=0, atol=1e-15) +# assert len(vec.dims()) == 1 + +# # one +# vec = Statevec(nqubit=1, data=BasicStates.ONE) +# assert np.allclose(vec.psi, np.array([0, 1]), rtol=0, atol=1e-15) +# assert len(vec.dims()) == 1 + +# # plus_i +# vec = Statevec(nqubit=1, data=BasicStates.PLUS_I) +# assert np.allclose(vec.psi, np.array([1, 1j] / np.sqrt(2))) +# assert len(vec.dims()) == 1 + +# # minus_i +# vec = Statevec(nqubit=1, data=BasicStates.MINUS_I) +# assert np.allclose(vec.psi, np.array([1, -1j] / np.sqrt(2))) +# assert len(vec.dims()) == 1 + +# # even more tests? +# def test_default_tensor_success(self, fx_rng: Generator) -> None: +# nqb = int(fx_rng.integers(2, 5)) +# print(f"nqb is {nqb}") +# vec = Statevec(nqubit=nqb) +# assert np.allclose(vec.psi, np.ones((2,) * nqb) / (np.sqrt(2)) ** nqb) +# assert len(vec.dims()) == nqb + +# vec = Statevec(nqubit=nqb, data=BasicStates.MINUS_I) +# sv_list = [BasicStates.MINUS_I.to_statevector() for _ in range(nqb)] +# sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) +# assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) +# assert len(vec.dims()) == nqb + +# # tensor of same state +# rand_angle = fx_rng.random() * 2 * ANGLE_PI +# rand_plane = fx_rng.choice(np.array(Plane)) +# state = PlanarState(rand_plane, rand_angle) +# vec = Statevec(nqubit=nqb, data=state) +# sv_list = [state.to_statevector() for _ in range(nqb)] +# sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) +# assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) +# assert len(vec.dims()) == nqb + +# # tensor of different states +# rand_angles = fx_rng.random(nqb) * 2 * ANGLE_PI +# rand_planes = fx_rng.choice(np.array(Plane), nqb) +# states = [PlanarState(plane=i, angle=j) for i, j in zip(rand_planes, rand_angles, strict=True)] +# vec = Statevec(nqubit=nqb, data=states) +# sv_list = [state.to_statevector() for state in states] +# sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) +# assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) +# assert len(vec.dims()) == nqb + +# def test_data_success(self, fx_rng: Generator) -> None: +# nqb = fx_rng.integers(2, 5) +# length = 2**nqb +# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) +# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) +# vec = Statevec(data=rand_vec) +# assert np.allclose(vec.psi, rand_vec.reshape((2,) * nqb)) +# assert len(vec.dims()) == nqb + +# # fail: incorrect len +# def test_data_dim_fail(self, fx_rng: Generator) -> None: +# length = 5 +# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) +# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) +# with pytest.raises(ValueError): +# _vec = Statevec(data=rand_vec) + +# # fail: with less qubit than number of qubits inferred from a correct state vect +# def test_data_dim_fail_mismatch(self, fx_rng: Generator) -> None: +# nqb = 3 +# rand_vec = fx_rng.random(2**nqb) + 1j * fx_rng.random(2**nqb) +# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) +# with pytest.raises(ValueError): +# _vec = Statevec(nqubit=2, data=rand_vec) + +# # fail: not normalized +# def test_data_norm_fail(self, fx_rng: Generator) -> None: +# nqb = fx_rng.integers(2, 5) +# length = 2**nqb +# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) +# with pytest.raises(ValueError): +# _vec = Statevec(data=rand_vec) + +# def test_defaults_to_one(self) -> None: +# vec = Statevec() +# assert len(vec.dims()) == 1 + +# # try copying Statevec input +# def test_copy_success(self, fx_rng: Generator) -> None: +# nqb = fx_rng.integers(2, 5) +# length = 2**nqb +# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) +# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) +# test_vec = Statevec(data=rand_vec) +# # try to copy it +# vec = Statevec(data=test_vec) + +# assert np.allclose(vec.psi, test_vec.psi) +# assert len(vec.dims()) == len(test_vec.dims()) + +# # try calling with incorrect number of qubits compared to inferred one +# def test_copy_fail(self, fx_rng: Generator) -> None: +# nqb = int(fx_rng.integers(2, 5)) +# length = 1 << nqb +# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) +# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) +# test_vec = Statevec(data=rand_vec) + +# with pytest.raises(ValueError): +# _vec = Statevec(nqubit=length - 1, data=test_vec) + +# def test_nqubits(self) -> None: +# for i in [1, 2, 5]: +# sv = Statevec(nqubit=i) +# assert sv.nqubit == i + +# def test_nqubits_pattern(self) -> None: +# p = Pattern(input_nodes=[0, 1, 2]) +# sv = p.simulate_pattern(backend="statevector") +# assert sv.nqubit == 3 + + + + +# @pytest.mark.parametrize( +# ("encoding", "dict_ref"), +# [ +# ("LSB", {"000": 0.5, "010": 0.5, "100": -0.5, "110": -0.5}), +# ("MSB", {"000": 0.5, "010": 0.5, "001": -0.5, "011": -0.5}), +# ], +# ) +# def test_to_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: +# sv = Statevec(data=[BasicStates.ZERO, BasicStates.PLUS, BasicStates.MINUS]) +# for ket, amp in sv.to_dict(encoding=encoding).items(): +# assert np.isclose(dict_ref[ket], amp.real) +# assert np.isclose(0, amp.imag) + +# @pytest.mark.parametrize( +# ("encoding", "dict_ref"), +# [ +# ("LSB", {"001": 0.25, "011": 0.25, "101": 0.25, "111": 0.25}), +# ("MSB", {"100": 0.25, "110": 0.25, "101": 0.25, "111": 0.25}), +# ], +# ) +# def test_to_prob_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: +# sv = Statevec(data=[BasicStates.ONE, BasicStates.PLUS, BasicStates.MINUS]) +# for ket, amp2 in sv.to_prob_dict(encoding=encoding).items(): +# assert np.isclose(dict_ref[ket], amp2.real) +# assert np.isclose(0, amp2.imag) + + +# def test_normalize() -> None: +# statevec = Statevec(nqubit=1, data=BasicStates.PLUS) +# statevec.remove_qubit(0) +# assert _norm_numeric(statevec.psi.astype(np.complex128, copy=False)) == 1 From 50d6913814427efa5958dad348fd2c577d5a2240 Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 22 May 2026 18:43:22 +0200 Subject: [PATCH 02/25] Fixed more tests --- tests/test_graphsim.py | 3 --- tests/test_parameter.py | 14 -------------- tests/test_pattern.py | 2 +- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/test_graphsim.py b/tests/test_graphsim.py index 180c38929..bc0799b04 100644 --- a/tests/test_graphsim.py +++ b/tests/test_graphsim.py @@ -84,21 +84,18 @@ def test_fig2(self) -> None: gstate = graph_state_to_statevec(g) g.measure_x(0) gstate.evolve_single(meas_op(0), 0) # x meas - gstate.normalize() gstate.remove_qubit(0) gstate2 = graph_state_to_statevec(g) assert gstate.isclose(gstate2) g.measure_y(1, choice=0) gstate.evolve_single(meas_op(0.5 * ANGLE_PI), 0) # y meas - gstate.normalize() gstate.remove_qubit(0) gstate2 = graph_state_to_statevec(g) assert gstate.isclose(gstate2) g.measure_z(3) gstate.evolve_single(meas_op(0.5 * ANGLE_PI, plane=Plane.YZ), 1) # z meas - gstate.normalize() gstate.remove_qubit(1) gstate2 = graph_state_to_statevec(g) assert gstate.isclose(gstate2) diff --git a/tests/test_parameter.py b/tests/test_parameter.py index 88f68d07e..d8b2160dd 100644 --- a/tests/test_parameter.py +++ b/tests/test_parameter.py @@ -12,7 +12,6 @@ from graphix.pattern import DrawPatternAnnotations, Pattern from graphix.random_objects import rand_circuit from graphix.sim.density_matrix import DensityMatrix -from graphix.sim.statevec import Statevec if TYPE_CHECKING: from numpy.random import PCG64, Generator @@ -132,19 +131,6 @@ def test_parallel_substitution_with_zero() -> None: assert not pattern23.is_parameterized() -def test_statevec_subs() -> None: - alpha = Placeholder("alpha") - statevec = Statevec([alpha]) - assert np.allclose(statevec.subs(alpha, 1).psi, np.array([1])) - - -def test_statevec_xreplace() -> None: - alpha = Placeholder("alpha") - beta = Placeholder("beta") - statevec = Statevec([alpha, beta]) - assert np.allclose(statevec.xreplace({alpha: 1, beta: 2}).psi, np.array([1, 2])) - - def test_density_matrix_subs() -> None: alpha = Placeholder("alpha") dm = DensityMatrix([[alpha]]) diff --git a/tests/test_pattern.py b/tests/test_pattern.py index d340ffaf2..a3b898f13 100644 --- a/tests/test_pattern.py +++ b/tests/test_pattern.py @@ -170,7 +170,7 @@ def simulate_and_measure() -> int: sim.run(rng=fx_rng) state = sim.backend.state if isinstance(state, Statevec): - assert state.dims() == () + assert state.nqubit == 0 elif isinstance(state, DensityMatrix): assert state.dims() == (1, 1) elif isinstance(state, MBQCTensorNet): From b0e361318334aa9b9bb87a3d43369aa5b20d67b1 Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 26 May 2026 13:16:08 +0200 Subject: [PATCH 03/25] wip --- graphix/sim/statevec.py | 102 ++++++++++++++++------------------ tests/test_statevec.py | 116 ++++++++++++++++++++++++++++----------- tests/test_transpiler.py | 6 +- 3 files changed, 136 insertions(+), 88 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 6d2122e59..a6c4c7d06 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -30,7 +30,9 @@ from graphix.parameter import ExpressionOrSupportsComplex - EvolveSingleJit: TypeAlias = Callable[[npt.NDArray[np.complex128], npt.NDArray[np.complex128], int, int], None] # type introduced in 3.12 + EvolveSingleJit: TypeAlias = Callable[ + [npt.NDArray[np.complex128], npt.NDArray[np.complex128], int, int], None + ] # type introduced in 3.12 ExpectationSingleJit: TypeAlias = Callable[ # type introduced in 3.12 [npt.NDArray[np.complex128], npt.NDArray[np.complex128], int, int], complex ] @@ -40,6 +42,7 @@ NUM_QUBIT_PARALLEL = 15 """This constant determines the number of qubits above which matrix operations are multi-threaded. For lower counts, the overhead does not compensate parallelization.""" + # TODO: Use q for function parameters class Statevec(DenseState): """Statevector object. @@ -61,9 +64,7 @@ class Statevec(DenseState): _max_qubits: int _nqubit: int - def __init__( - self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max_qubits: int | None = None - ) -> None: + def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max_qubits: int | None = None) -> None: """Initialize statevector objects. See :class:`graphix.sim.statevec.Statevec` for additional information. @@ -296,29 +297,6 @@ def expectation_single(self, op: Matrix, loc: int) -> complex: # We cast to np.complex128 to match numba signature. return kernel(self.psi, op.astype(np.complex128), self.nqubit, loc) - @override - def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: - """Apply a multi-qubit operation. - - Parameters - ---------- - op : numpy.ndarray - 2^n*2^n matrix - qargs : list of int - target qubits' indices - """ - op_dim = int(np.log2(len(op))) - # TODO shape = (2,)* 2 * op_dim - shape = [2 for _ in range(2 * op_dim)] - psi_t = self.flatten().reshape((2,) * self.nqubit) - op_tensor = op.reshape(shape) - psi = np.tensordot( - op_tensor, - psi_t, - (tuple(op_dim + i for i in range(len(qargs))), qargs), - ) - self.psi[:self.size_valid_psi] = np.moveaxis(psi, range(len(qargs)), qargs).reshape(1<< self.nqubit) - # @override # def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: # """Apply a multi-qubit operation. @@ -330,24 +308,47 @@ def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: # qargs : list of int # target qubits' indices # """ - # nq = len(qargs) - # # treat x as a tensor with ng output + ng input legs - # op_t = op.reshape((2,) * (nq * 2)) + # op_dim = int(np.log2(len(op))) + # # TODO shape = (2,)* 2 * op_dim + # shape = [2 for _ in range(2 * op_dim)] # psi_t = self.flatten().reshape((2,) * self.nqubit) + # op_tensor = op.reshape(shape) + # psi = np.tensordot( + # op_tensor, + # psi_t, + # (tuple(op_dim + i for i in range(len(qargs))), qargs), + # ).astype(np.complex128) + # self.psi[:self.size_valid_psi] = np.moveaxis(psi, range(len(qargs)), qargs).reshape(1<< self.nqubit) - # state_idx = list(range(self.nqubit)) # [0, 1, 2, 3] - # out_idx = list(range(self.nqubit, self.nqubit + nq)) # [4, 5] + @override + def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: + """Apply a multi-qubit operation. - # # x subscripts: [out_0, out_1, in_0, in_1] → [4, 5, 1, 3] - # xt_idx = out_idx + list(qargs) + Parameters + ---------- + op : numpy.ndarray + 2^n*2^n matrix + qargs : list of int + target qubits' indices + """ + nq = len(qargs) + # treat x as a tensor with ng output + ng input legs + op_t = op.reshape((2,) * (nq * 2)).astype(np.complex128, copy=False) + psi_t = self.flatten().reshape((2,) * self.nqubit).astype(np.complex128, copy=False) - # # result subscripts: same as state but source slots replaced by out labels - # # [0, 4, 2, 5] - # res_idx = state_idx.copy() - # for i, s in enumerate(qargs): - # res_idx[s] = out_idx[i] + state_idx = np.array(range(self.nqubit)) # [0, 1, 2, 3] + out_idx = np.array(range(self.nqubit, self.nqubit + nq)) # [4, 5] - # return np.einsum(op_t, xt_idx, psi_t, state_idx, res_idx).reshape(1 << self.nqubit) + # x subscripts: [out_0, out_1, in_0, in_1] → [4, 5, 1, 3] + xt_idx = np.concatenate((out_idx, qargs)) + + # result subscripts: same as state but source slots replaced by out labels + # [0, 4, 2, 5] + res_idx = state_idx.copy() + for i, s in enumerate(qargs): + res_idx[s] = out_idx[i] + + self.psi[: self.size_valid_psi] = np.einsum(op_t, xt_idx, psi_t, state_idx, res_idx).reshape(1 << self.nqubit) def expectation_value(self, op: Matrix, qargs: Sequence[int]) -> complex: """Return the expectation value of multi-qubit operator. @@ -488,7 +489,7 @@ def to_dict( *, rtol: float = 0.0, atol: float = 1e-8, - ) -> dict[str, np.object_ | np.complex128]: + ) -> dict[str, np.object_ | np.complex128]: r"""Convert the statevector to dictionary form. This dictionary representation uses a ket-like notation where the dictionary ``keys`` are qubit strings for the basis vectors and ``values`` are the corresponding complex amplitudes. Amplitudes below a certain threshold are filtered out. @@ -539,7 +540,7 @@ def to_dict( def to_prob_dict( self, encoding: _ENCODING = "MSB", *, rtol: float = 0.0, atol: float = 1e-8 - ) -> dict[str, np.object_ | np.float64]: + ) -> dict[str, np.object_ | np.float64]: r"""Convert the statevector to a probability distirbution in a dictionary form. This dictionary representation uses a ket-like notation where the dictionary ``keys`` are qubit strings for the basis vectors and ``values`` are the corresponding probabilities. @@ -578,15 +579,16 @@ def _to_dict_map( *, rtol: float = 0.0, atol: float = 1e-8, - ) -> dict[str, _ScalarT]: + ) -> dict[str, _ScalarT]: mask = np.logical_not(np.isclose(np.abs(self.flatten()), 0, rtol=rtol, atol=atol)) i_vals = np.arange(1 << self.nqubit)[mask] amp_vals = f(self.flatten()[mask]) return {_format_encoding(self.nqubit, i, encoding): amp for i, amp in zip(i_vals, amp_vals, strict=True)} -#TODO: type **kwargs with Unpack -#TODO: Update tests + +# TODO: type **kwargs with Unpack +# TODO: Update tests @dataclass(frozen=True) class StatevectorBackend(DenseStateBackend[Statevec]): """MBQC state vector backend simulator based on 10.48550/arXiv.2506.08142.""" @@ -787,8 +789,6 @@ def _remove_qubit_jit( return new_nqubit - - # @override # def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: # """Apply a multi-qubit operation. @@ -812,8 +812,6 @@ def _remove_qubit_jit( # self.psi = np.moveaxis(psi, range(len(qargs)), qargs) - - # def normalize(self) -> None: # """Normalize the state in-place.""" # # Note that the following calls to `astype` are guaranteed to @@ -832,12 +830,6 @@ def _remove_qubit_jit( # self.psi = psi_c - - - - - - # def _norm_symbolic(psi: npt.NDArray[np.object_]) -> ExpressionOrFloat: # """Return norm of the state.""" # flat = psi.flatten() diff --git a/tests/test_statevec.py b/tests/test_statevec.py index c31fca771..707fb631f 100644 --- a/tests/test_statevec.py +++ b/tests/test_statevec.py @@ -1,5 +1,6 @@ from __future__ import annotations +import functools from typing import TYPE_CHECKING import numpy as np @@ -8,6 +9,8 @@ from numpy.random import Generator from graphix.clifford import Clifford +from graphix.ops import Ops +from graphix.random_objects import rand_unit from graphix.sim.statevec import Statevec from graphix.states import BasicStates @@ -15,7 +18,7 @@ from collections.abc import Mapping from typing import Literal - from numpy.random import Generator + from numpy.random import PCG64 _ENCODING = Literal["LSB", "MSB"] @@ -242,6 +245,86 @@ def test_remove_qubit(self, sv: Statevec, q: int, sv_ref: Statevec) -> None: sv.remove_qubit(q) assert np.allclose(sv.flatten(), sv_ref.flatten()) + @pytest.mark.parametrize( + ("sv", "qargs", "op", "data_ref"), + [ + (Statevec(data=BasicStates.ZERO, nqubit=2), (0,), Clifford.X.matrix, np.array([0, 0, 1, 0])), + ( + Statevec(data=[BasicStates.PLUS, BasicStates.PLUS]), + (1,), + Clifford.H.matrix, + np.array([1, 0, 1, 0]) / np.sqrt(2), + ), + ( + Statevec(data=[BasicStates.PLUS, BasicStates.MINUS]), + (0,), + np.array([[1, 0], [0, np.exp(0.25j * np.pi)]]), + np.array([1, -1, np.exp(0.25j * np.pi), -np.exp(0.25j * np.pi)]) / 2, + ), + ( + Statevec(data=np.array([1, 0, 0, 0, 0, 0, 0, 1]) / np.sqrt(2)), + (1,), + Clifford.Z.matrix, + np.array([1, 0, 0, 0, 0, 0, 0, -1]) / np.sqrt(2), + ), + ( + Statevec(data=np.array([1, 0, 0, 0, 0, 0, 0, 1]) / np.sqrt(2)), + (0, 1), + Ops.CNOT, + np.array([1, 0, 0, 0, 0, 1, 0, 0]) / np.sqrt(2), + ), + ( + Statevec(data=np.array([1, 0, 0, 0, 0, 0, 0, 1]) / np.sqrt(2)), + (0, 2), + Ops.CNOT, + np.array([1, 0, 0, 0, 0, 0, 1, 0]) / np.sqrt(2), + ), + ( + Statevec(data=np.array([1, 0, 0, 0, 0, 0, 0, 1]) / np.sqrt(2), max_qubits=5), + (1, 2), + Ops.CNOT, + np.array([1, 0, 0, 0, 0, 0, 1, 0]) / np.sqrt(2), + ), + ( + Statevec(data=np.array([1, 0, 0, 0, 0, 0, 0, 1]) / np.sqrt(2), max_qubits=5), + (0, 1, 2), + Ops.CCX, + np.array([1, 0, 0, 0, 0, 0, 1, 0]) / np.sqrt(2), + ), + ], + ) + def test_evolve( + self, sv: Statevec, qargs: tuple[int, ...], op: npt.NDArray[np.complex128], data_ref: npt.NDArray[np.complex128] + ) -> None: + sv.evolve(op, qargs) + assert np.allclose(sv.flatten(), data_ref) + + @pytest.mark.parametrize("jumps", range(1, 5)) + def test_evolve_rnd(self, fx_bg: PCG64, jumps: int) -> None: + rng = Generator(fx_bg.jumped(jumps)) + nqubits = 4 + data = generate_rnd_data(rng, nqubits) + sv = Statevec(data=data) + op = rand_unit(8, rng) + + sv.evolve(op, (1, 2, 3)) + data_ref = np.kron(np.eye(2), op) @ data + sv_ref = Statevec(data_ref) + + assert sv.isclose(sv_ref) + + @pytest.mark.parametrize("jumps", range(1, 5)) + def test_expectation_value(self, fx_bg: PCG64, jumps: int) -> None: + rng = Generator(fx_bg.jumped(jumps)) + nqubits = 4 + data = generate_rnd_data(rng, nqubits) + sv = Statevec(data=data) + op = rand_unit(4, rng) + + val_test = sv.expectation_value(op, (1, 2)) + val_ref = np.conjugate(data) @ functools.reduce(np.kron, (np.eye(2), op, np.eye(2))) @ data + assert val_test == pytest.approx(val_ref) + # TODO: Refactor using parametrize class TestFidelity: @@ -309,6 +392,7 @@ def test_to_dict(encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: assert np.isclose(dict_ref[ket], amp.real) assert np.isclose(0, amp.imag) + @pytest.mark.parametrize( ("encoding", "dict_ref"), [ @@ -422,7 +506,6 @@ def test_to_prob_dict(encoding: _ENCODING, dict_ref: Mapping[str, float]) -> Non # assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) - # from __future__ import annotations # import functools @@ -586,35 +669,6 @@ def test_to_prob_dict(encoding: _ENCODING, dict_ref: Mapping[str, float]) -> Non # assert sv.nqubit == 3 - - -# @pytest.mark.parametrize( -# ("encoding", "dict_ref"), -# [ -# ("LSB", {"000": 0.5, "010": 0.5, "100": -0.5, "110": -0.5}), -# ("MSB", {"000": 0.5, "010": 0.5, "001": -0.5, "011": -0.5}), -# ], -# ) -# def test_to_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: -# sv = Statevec(data=[BasicStates.ZERO, BasicStates.PLUS, BasicStates.MINUS]) -# for ket, amp in sv.to_dict(encoding=encoding).items(): -# assert np.isclose(dict_ref[ket], amp.real) -# assert np.isclose(0, amp.imag) - -# @pytest.mark.parametrize( -# ("encoding", "dict_ref"), -# [ -# ("LSB", {"001": 0.25, "011": 0.25, "101": 0.25, "111": 0.25}), -# ("MSB", {"100": 0.25, "110": 0.25, "101": 0.25, "111": 0.25}), -# ], -# ) -# def test_to_prob_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: -# sv = Statevec(data=[BasicStates.ONE, BasicStates.PLUS, BasicStates.MINUS]) -# for ket, amp2 in sv.to_prob_dict(encoding=encoding).items(): -# assert np.isclose(dict_ref[ket], amp2.real) -# assert np.isclose(0, amp2.imag) - - # def test_normalize() -> None: # statevec = Statevec(nqubit=1, data=BasicStates.PLUS) # statevec.remove_qubit(0) diff --git a/tests/test_transpiler.py b/tests/test_transpiler.py index d73f9133d..eb8ea4913 100644 --- a/tests/test_transpiler.py +++ b/tests/test_transpiler.py @@ -11,6 +11,7 @@ from graphix.fundamentals import ANGLE_PI, Axis, Sign from graphix.instruction import I, InstructionKind from graphix.random_objects import rand_circuit, rand_gate, rand_state_vector +from graphix.sim import Statevec from graphix.states import BasicStates from graphix.transpiler import Circuit, transpile_swaps from tests.test_branch_selector import CheckedBranchSelector @@ -278,8 +279,9 @@ def test_transpile_swaps(fx_bg: PCG64, jumps: int) -> None: for qubit in transpiled_swaps.qubits: assert qubit is not None qubits.append(qubit) - state2.psi = np.transpose(state2.psi, qubits) - assert state.isclose(state2) + psi_t = np.transpose(state2.flatten().reshape((2,) * nqubits), qubits) + state2_test = Statevec(psi_t.reshape(1 << nqubits)) + assert state.isclose(state2_test) @pytest.mark.parametrize("jumps", range(1, 11)) From e25a6994535233c7a9c502cd8bba071d8dbba0d1 Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 26 May 2026 16:06:47 +0200 Subject: [PATCH 04/25] Update tests --- graphix/sim/statevec.py | 107 ++--------- tests/test_statevec.py | 328 ++++++++++++++++++++++++--------- tests/test_statevec_backend.py | 189 ------------------- tests/test_tnsim.py | 6 +- 4 files changed, 254 insertions(+), 376 deletions(-) delete mode 100644 tests/test_statevec_backend.py diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index a6c4c7d06..51492be99 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -297,29 +297,6 @@ def expectation_single(self, op: Matrix, loc: int) -> complex: # We cast to np.complex128 to match numba signature. return kernel(self.psi, op.astype(np.complex128), self.nqubit, loc) - # @override - # def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: - # """Apply a multi-qubit operation. - - # Parameters - # ---------- - # op : numpy.ndarray - # 2^n*2^n matrix - # qargs : list of int - # target qubits' indices - # """ - # op_dim = int(np.log2(len(op))) - # # TODO shape = (2,)* 2 * op_dim - # shape = [2 for _ in range(2 * op_dim)] - # psi_t = self.flatten().reshape((2,) * self.nqubit) - # op_tensor = op.reshape(shape) - # psi = np.tensordot( - # op_tensor, - # psi_t, - # (tuple(op_dim + i for i in range(len(qargs))), qargs), - # ).astype(np.complex128) - # self.psi[:self.size_valid_psi] = np.moveaxis(psi, range(len(qargs)), qargs).reshape(1<< self.nqubit) - @override def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: """Apply a multi-qubit operation. @@ -332,23 +309,21 @@ def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: target qubits' indices """ nq = len(qargs) - # treat x as a tensor with ng output + ng input legs + # treat op as a tensor with nq output + nq input legs op_t = op.reshape((2,) * (nq * 2)).astype(np.complex128, copy=False) psi_t = self.flatten().reshape((2,) * self.nqubit).astype(np.complex128, copy=False) - state_idx = np.array(range(self.nqubit)) # [0, 1, 2, 3] - out_idx = np.array(range(self.nqubit, self.nqubit + nq)) # [4, 5] + psi_idx = np.array(range(self.nqubit)) + out_idx = np.array(range(self.nqubit, self.nqubit + nq)) # fresh labels - # x subscripts: [out_0, out_1, in_0, in_1] → [4, 5, 1, 3] - xt_idx = np.concatenate((out_idx, qargs)) + op_idx = np.concatenate((out_idx, qargs)) - # result subscripts: same as state but source slots replaced by out labels - # [0, 4, 2, 5] - res_idx = state_idx.copy() + # result subscripts: same as psi but modified indices (qargs) replaced by out labels + res_idx = psi_idx.copy() for i, s in enumerate(qargs): res_idx[s] = out_idx[i] - self.psi[: self.size_valid_psi] = np.einsum(op_t, xt_idx, psi_t, state_idx, res_idx).reshape(1 << self.nqubit) + self.psi[: self.size_valid_psi] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) def expectation_value(self, op: Matrix, qargs: Sequence[int]) -> complex: """Return the expectation value of multi-qubit operator. @@ -588,7 +563,6 @@ def _to_dict_map( # TODO: type **kwargs with Unpack -# TODO: Update tests @dataclass(frozen=True) class StatevectorBackend(DenseStateBackend[Statevec]): """MBQC state vector backend simulator based on 10.48550/arXiv.2506.08142.""" @@ -762,7 +736,7 @@ def _remove_qubit_jit( # If norm of branch 0 is 0, compute norm of branch 1 and set shift to branch 1 if norm2 <= atol: - norm2 = 0 + norm2 = 0.0 shift = size_half_block b0 = shift for _ in range(n_blocks): @@ -773,6 +747,9 @@ def _remove_qubit_jit( norm2 += a_re * a_re + a_im * a_im b0 += size_block + if norm2 <= atol: + raise RuntimeError(f"Attempted to remove qubit {q} from 0-norm statevector.") + b0 = shift k = 0 inv_norm = 1.0 / math.sqrt(norm2) @@ -789,68 +766,6 @@ def _remove_qubit_jit( return new_nqubit -# @override -# def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: -# """Apply a multi-qubit operation. - -# Parameters -# ---------- -# op : numpy.ndarray -# 2^n*2^n matrix -# qargs : list of int -# target qubits' indices -# """ -# op_dim = int(np.log2(len(op))) -# # TODO shape = (2,)* 2 * op_dim -# shape = [2 for _ in range(2 * op_dim)] -# op_tensor = op.reshape(shape) -# psi = tensordot( -# op_tensor, -# self.psi, -# (tuple(op_dim + i for i in range(len(qargs))), qargs), -# ) -# self.psi = np.moveaxis(psi, range(len(qargs)), qargs) - - -# def normalize(self) -> None: -# """Normalize the state in-place.""" -# # Note that the following calls to `astype` are guaranteed to -# # return the original NumPy array itself, since `copy=False` and -# # the `dtype` matches. This is important because the array is -# # then modified in place. -# if self.psi.dtype == np.object_: -# psi_o = self.psi.astype(np.object_, copy=False) -# norm_o = _norm_symbolic(psi_o) -# psi_o /= norm_o -# self.psi = psi_o -# else: -# psi_c = self.psi.astype(np.complex128, copy=False) -# norm_c = _norm_numeric(psi_c) -# psi_c /= norm_c -# self.psi = psi_c - - -# def _norm_symbolic(psi: npt.NDArray[np.object_]) -> ExpressionOrFloat: -# """Return norm of the state.""" -# flat = psi.flatten() -# return check_expression_or_float(np.sqrt(np.sum(flat.conj() * flat))) - - -# def _norm_numeric(psi: npt.NDArray[np.complex128]) -> float: -# flat = psi.flatten() -# norm_sq = np.sum(flat.conj() * flat) -# assert math.isclose(norm_sq.imag, 0, abs_tol=1e-15) -# return math.sqrt(norm_sq.real) - - -# def _norm(psi: Matrix) -> ExpressionOrFloat: -# """Return norm of the state.""" -# # Narrow psi to concrete dtype -# if psi.dtype == np.object_: -# return _norm_symbolic(psi.astype(np.object_, copy=False)) -# return _norm_numeric(psi.astype(np.complex128, copy=False)) - - def _format_encoding(nqubit: int, i: int, encoding: _ENCODING) -> str: """Format the i-th basis vector as a ket. See :meth:`Statevec.to_dict` for additional details.""" display_width = nqubit diff --git a/tests/test_statevec.py b/tests/test_statevec.py index 707fb631f..547d3d807 100644 --- a/tests/test_statevec.py +++ b/tests/test_statevec.py @@ -9,9 +9,11 @@ from numpy.random import Generator from graphix.clifford import Clifford +from graphix.measurements import Measurement from graphix.ops import Ops +from graphix.pauli import Pauli from graphix.random_objects import rand_unit -from graphix.sim.statevec import Statevec +from graphix.sim.statevec import Statevec, StatevectorBackend from graphix.states import BasicStates if TYPE_CHECKING: @@ -22,7 +24,9 @@ _ENCODING = Literal["LSB", "MSB"] - from graphix.states import State + from graphix.states import PlanarState, State + +N_JUMPS = 3 def generate_rnd_data(rng: Generator, nqubits: int) -> npt.NDArray[np.complex128]: @@ -32,9 +36,7 @@ def generate_rnd_data(rng: Generator, nqubits: int) -> npt.NDArray[np.complex128 return data -class TestInit: - N_JUMPS = 3 - +class TestStatevec: @pytest.mark.parametrize( ("state", "data_ref"), [ @@ -128,8 +130,6 @@ def test_init_statevec_max_qubits_fail(self, fx_rng: Generator, nqubit: int) -> with pytest.raises(ValueError): Statevec(data=sv_1, max_qubits=nqubit + 1) - -class TestSimulation: @pytest.mark.parametrize( ("sv", "edge", "data_ref"), [ @@ -245,6 +245,34 @@ def test_remove_qubit(self, sv: Statevec, q: int, sv_ref: Statevec) -> None: sv.remove_qubit(q) assert np.allclose(sv.flatten(), sv_ref.flatten()) + @pytest.mark.parametrize( + "state", + [ + BasicStates.PLUS, + BasicStates.MINUS, + BasicStates.ZERO, + BasicStates.ONE, + BasicStates.PLUS_I, + BasicStates.MINUS_I, + ], + ) + def test_measurement_into_each_xyz_basis(self, state: PlanarState) -> None: + n = 3 + k = 0 + statevector = state.to_statevector() + m_op = np.outer(statevector, statevector.T.conjugate()) + sv = Statevec(nqubit=n) + sv.evolve_single(m_op, k) + + if state is BasicStates.MINUS: + # Measurement into |-> results in a 0-norm vector + with pytest.raises(RuntimeError): + sv.remove_qubit(k) + else: + sv.remove_qubit(k) + sv2 = Statevec(nqubit=n - 1) + assert sv.isclose(sv2) + @pytest.mark.parametrize( ("sv", "qargs", "op", "data_ref"), [ @@ -299,7 +327,7 @@ def test_evolve( sv.evolve(op, qargs) assert np.allclose(sv.flatten(), data_ref) - @pytest.mark.parametrize("jumps", range(1, 5)) + @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) def test_evolve_rnd(self, fx_bg: PCG64, jumps: int) -> None: rng = Generator(fx_bg.jumped(jumps)) nqubits = 4 @@ -313,7 +341,7 @@ def test_evolve_rnd(self, fx_bg: PCG64, jumps: int) -> None: assert sv.isclose(sv_ref) - @pytest.mark.parametrize("jumps", range(1, 5)) + @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) def test_expectation_value(self, fx_bg: PCG64, jumps: int) -> None: rng = Generator(fx_bg.jumped(jumps)) nqubits = 4 @@ -325,86 +353,210 @@ def test_expectation_value(self, fx_bg: PCG64, jumps: int) -> None: val_ref = np.conjugate(data) @ functools.reduce(np.kron, (np.eye(2), op, np.eye(2))) @ data assert val_test == pytest.approx(val_ref) + @pytest.mark.parametrize( + ("sv1", "sv2", "fidelity"), + [ + (Statevec(data=BasicStates.PLUS), Statevec(data=BasicStates.PLUS), 1), + (Statevec(data=BasicStates.ZERO), Statevec(data=BasicStates.ONE), 0), + (Statevec(data=BasicStates.ZERO), Statevec(data=BasicStates.PLUS), 0.5), + (Statevec(data=BasicStates.PLUS), Statevec(data=np.array([1, 1]) / np.sqrt(2) * 1j), 1), + ], + ) + def test_fidelity(self, sv1: Statevec, sv2: Statevec, fidelity: float) -> None: + assert sv1.fidelity(sv2) == pytest.approx(fidelity) + + @pytest.mark.parametrize( + ("sv1", "sv2", "isclose", "atol"), + [ + (Statevec(data=BasicStates.PLUS), Statevec(data=BasicStates.PLUS), True, 0.0), + (Statevec(data=BasicStates.ZERO), Statevec(data=BasicStates.ONE), False, 0.0), + ( + Statevec(data=BasicStates.PLUS), + Statevec(data=np.array([1, 1]) / np.sqrt(2) * np.exp(1j * 0.7)), + True, + 0.0, + ), + (Statevec(data=BasicStates.ZERO), Statevec(data=np.array([np.sqrt(1 - 1e-8), np.sqrt(1e-8)])), False, 0.0), + ( + Statevec(data=BasicStates.ZERO), + Statevec(data=np.array([np.sqrt(1 - 1e-8), np.sqrt(1e-8)])), + True, + 1.0e-6, + ), + ], + ) + def test_isclose(self, sv1: Statevec, sv2: Statevec, isclose: bool, atol: float) -> None: + if isclose: + assert sv1.isclose(sv2, atol=atol) + else: + assert not sv1.isclose(sv2, atol=atol) + + @pytest.mark.parametrize( + ("encoding", "dict_ref"), + [ + ("LSB", {"000": 0.5, "010": 0.5, "100": -0.5, "110": -0.5}), + ("MSB", {"000": 0.5, "010": 0.5, "001": -0.5, "011": -0.5}), + ], + ) + def test_to_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: + sv = Statevec(data=[BasicStates.ZERO, BasicStates.PLUS, BasicStates.MINUS]) + for ket, amp in sv.to_dict(encoding=encoding).items(): + assert np.isclose(dict_ref[ket], amp.real) + assert np.isclose(0, amp.imag) + + @pytest.mark.parametrize( + ("encoding", "dict_ref"), + [ + ("LSB", {"001": 0.25, "011": 0.25, "101": 0.25, "111": 0.25}), + ("MSB", {"100": 0.25, "110": 0.25, "101": 0.25, "111": 0.25}), + ], + ) + def test_to_prob_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: + sv = Statevec(data=[BasicStates.ONE, BasicStates.PLUS, BasicStates.MINUS]) + for ket, amp2 in sv.to_prob_dict(encoding=encoding).items(): + assert np.isclose(dict_ref[ket], amp2.real) + assert np.isclose(0, amp2.imag) + + +class TestStatevectorBackend: + @pytest.mark.parametrize( + ("state", "data_ref"), + [ + (BasicStates.PLUS, np.array([1, 1] / np.sqrt(2))), + (BasicStates.MINUS, np.array([1, -1] / np.sqrt(2))), + (BasicStates.ZERO, np.array([1, 0])), + (BasicStates.ONE, np.array([0, 1])), + (BasicStates.PLUS_I, np.array([1, 1j] / np.sqrt(2))), + (BasicStates.MINUS_I, np.array([1, -1j] / np.sqrt(2))), + ], + ) + def test_init_basic_states(self, state: State, data_ref: npt.NDArray[np.complex128]) -> None: + backend = StatevectorBackend() + backend.add_nodes([0], data=state) + sv = Statevec(data=data_ref) + assert backend.state.isclose(sv) + + @pytest.mark.parametrize( + ("n_nodes"), + range(5), + ) + def test_init_capacity(self, n_nodes: int, fx_rng: Generator) -> None: + capacity = 3 + data = generate_rnd_data(fx_rng, n_nodes) + backend = StatevectorBackend.with_capacity(capacity) + backend.add_nodes(range(n_nodes), data=data) + sv = Statevec(data=data) + assert backend.state.isclose(sv) + assert backend.state.max_qubits == max(n_nodes, capacity) + + @pytest.mark.parametrize( + ("clifford"), + Clifford, + ) + def test_clifford(self, clifford: Clifford, fx_rng: Generator) -> None: + nqubits = 4 + data = generate_rnd_data(fx_rng, nqubits=nqubits) -# TODO: Refactor using parametrize -class TestFidelity: - def test_fidelity_same_state(self) -> None: - state = Statevec(data=BasicStates.PLUS) - assert state.fidelity(state) == pytest.approx(1) - - def test_fidelity_orthogonal(self) -> None: - zero = Statevec(data=BasicStates.ZERO) - one = Statevec(data=BasicStates.ONE) - assert zero.fidelity(one) == pytest.approx(0) - - def test_fidelity_known_value(self) -> None: - # F(|0>, |+>) = 0.5 - zero = Statevec(data=BasicStates.ZERO) - plus = Statevec(data=BasicStates.PLUS) - assert zero.fidelity(plus) == pytest.approx(0.5) - - def test_fidelity_global_phase(self) -> None: - plus = Statevec(data=BasicStates.PLUS) - plus_rotated = Statevec(data=np.array([1, 1]) / np.sqrt(2) * 1j) - assert plus.fidelity(plus_rotated) == pytest.approx(1) - - def test_fidelity_symmetry(self, fx_rng: Generator) -> None: - length = 4 - vec_a = fx_rng.random(length) + 1j * fx_rng.random(length) - vec_a /= np.sqrt(np.sum(np.abs(vec_a) ** 2)) - vec_b = fx_rng.random(length) + 1j * fx_rng.random(length) - vec_b /= np.sqrt(np.sum(np.abs(vec_b) ** 2)) - a = Statevec(data=vec_a) - b = Statevec(data=vec_b) - assert a.fidelity(b) == pytest.approx(b.fidelity(a)) - - def test_isclose_same_state(self) -> None: - state = Statevec(data=BasicStates.PLUS) - assert state.isclose(state) - - def test_isclose_orthogonal(self) -> None: - zero = Statevec(data=BasicStates.ZERO) - one = Statevec(data=BasicStates.ONE) - assert not zero.isclose(one) - - def test_isclose_global_phase(self) -> None: - plus = Statevec(data=BasicStates.PLUS) - rotated = Statevec(data=np.array([1, 1]) / np.sqrt(2) * np.exp(1j * 0.7)) - assert plus.isclose(rotated) - - def test_isclose_tolerance(self) -> None: - zero = Statevec(data=BasicStates.ZERO) - almost = Statevec(data=np.array([np.sqrt(1 - 1e-8), np.sqrt(1e-8)])) - assert not zero.isclose(almost) - assert zero.isclose(almost, atol=1e-6) - - -@pytest.mark.parametrize( - ("encoding", "dict_ref"), - [ - ("LSB", {"000": 0.5, "010": 0.5, "100": -0.5, "110": -0.5}), - ("MSB", {"000": 0.5, "010": 0.5, "001": -0.5, "011": -0.5}), - ], -) -def test_to_dict(encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: - sv = Statevec(data=[BasicStates.ZERO, BasicStates.PLUS, BasicStates.MINUS]) - for ket, amp in sv.to_dict(encoding=encoding).items(): - assert np.isclose(dict_ref[ket], amp.real) - assert np.isclose(0, amp.imag) - - -@pytest.mark.parametrize( - ("encoding", "dict_ref"), - [ - ("LSB", {"001": 0.25, "011": 0.25, "101": 0.25, "111": 0.25}), - ("MSB", {"100": 0.25, "110": 0.25, "101": 0.25, "111": 0.25}), - ], -) -def test_to_prob_dict(encoding: _ENCODING, dict_ref: Mapping[str, float]) -> None: - sv = Statevec(data=[BasicStates.ONE, BasicStates.PLUS, BasicStates.MINUS]) - for ket, amp2 in sv.to_prob_dict(encoding=encoding).items(): - assert np.isclose(dict_ref[ket], amp2.real) - assert np.isclose(0, amp2.imag) + backend = StatevectorBackend() + backend.add_nodes(nodes=range(nqubits), data=data) + backend.apply_clifford(node=0, clifford=clifford) + + vec = Statevec(nqubit=nqubits, data=data) + vec.evolve_single(clifford.matrix, 0) + + assert backend.state.isclose(vec) + + @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) + def test_deterministic_measure_0(self, fx_bg: PCG64, jumps: int) -> None: + rng = Generator(fx_bg.jumped(jumps)) + # plus state & zero state (default), but with tossed coins + + backend = StatevectorBackend() + coins = [rng.choice([0, 1]), rng.choice([0, 1])] + expected_result = sum(coins) % 2 + states = [ + Pauli.X.eigenstate(coins[0]), + Pauli.Z.eigenstate(coins[1]), + ] + nodes = range(len(states)) + backend.add_nodes(nodes=nodes, data=states) + backend.entangle_nodes(edge=(nodes[0], nodes[1])) + measurement = Measurement.X + node_to_measure = backend.node_index[0] + result = backend.measure(node=node_to_measure, measurement=measurement, rng=rng) + assert result == expected_result + + @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) + def test_deterministic_measure_1(self, fx_bg: PCG64, jumps: int) -> None: + """Entangle |+> state with N |0> states, the (XY,0) measurement yields the outcome 0 with probability 1.""" + rng = Generator(fx_bg.jumped(jumps)) + n_nodes = 11 + backend = StatevectorBackend.with_capacity(n_nodes) + states = [BasicStates.PLUS, *(BasicStates.ZERO for _ in range(n_nodes - 1))] + backend.add_nodes(nodes=range(n_nodes), data=states) + for i in range(1, n_nodes): + backend.entangle_nodes(edge=(0, i)) + measurement = Measurement.X + node_to_measure = backend.node_index[0] + result = backend.measure(node=node_to_measure, measurement=measurement, rng=rng) + assert result == 0 + assert list(backend.node_index) == list(range(1, n_nodes)) + + @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) + def test_deterministic_measure_many(self, fx_bg: PCG64, jumps: int) -> None: + """Entangle |+> state with N |0> states, the (XY,0) measurement yields the outcome 0 with probability 1.""" + rng = Generator(fx_bg.jumped(jumps)) + # plus state (default) + backend = StatevectorBackend() + n_traps = 5 + n_neighbors = 5 + n_others = 5 + traps = [Pauli.X.eigenstate() for _ in range(n_traps)] + dummies = [Pauli.Z.eigenstate() for _ in range(n_neighbors)] + others = [Pauli.I.eigenstate() for _ in range(n_others)] + states = traps + dummies + others + nodes = range(len(states)) + backend.add_nodes(nodes=nodes, data=states) + + for dummy in nodes[n_traps : n_traps + n_neighbors]: + for trap in nodes[:n_traps]: + backend.entangle_nodes(edge=(trap, dummy)) + for other in nodes[n_traps + n_neighbors :]: + backend.entangle_nodes(edge=(other, dummy)) + + # Same measurement for all traps + measurement = Measurement.X + + for trap in nodes[:n_traps]: + node_to_measure = trap + result = backend.measure(node=node_to_measure, measurement=measurement, rng=rng) + assert result == 0 + + assert list(backend.node_index) == list(range(n_traps, n_neighbors + n_traps + n_others)) + + @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) + def test_deterministic_measure_with_coin(self, fx_bg: PCG64, jumps: int) -> None: + """Entangle |+> state with N |0> states, the (XY,0) measurement yields the outcome 0 with probability 1. + + We add coin toss to that. + """ + rng = Generator(fx_bg.jumped(jumps)) + # plus state (default) + backend = StatevectorBackend() + n_neighbors = 10 + coins = [rng.choice([0, 1])] + [rng.choice([0, 1]) for _ in range(n_neighbors)] + expected_result = sum(coins) % 2 + states = [Pauli.X.eigenstate(coins[0])] + [Pauli.Z.eigenstate(coins[i + 1]) for i in range(n_neighbors)] + nodes = range(len(states)) + backend.add_nodes(nodes=nodes, data=states) + + for i in range(1, n_neighbors + 1): + backend.entangle_nodes(edge=(nodes[0], i)) + measurement = Measurement.X + node_to_measure = backend.node_index[0] + result = backend.measure(node=node_to_measure, measurement=measurement, rng=rng) + assert result == expected_result + assert list(backend.node_index) == list(range(1, n_neighbors + 1)) # class TestStatevecLegacy: diff --git a/tests/test_statevec_backend.py b/tests/test_statevec_backend.py deleted file mode 100644 index acab2c527..000000000 --- a/tests/test_statevec_backend.py +++ /dev/null @@ -1,189 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -import numpy as np -import pytest - -from graphix.clifford import Clifford -from graphix.fundamentals import ANGLE_PI, Plane -from graphix.measurements import Measurement -from graphix.pauli import Pauli -from graphix.sim.statevec import Statevec, StatevectorBackend -from graphix.states import BasicStates, PlanarState - -if TYPE_CHECKING: - from numpy.random import Generator - - from graphix import Pattern - - -class TestStatevec: - @pytest.mark.parametrize( - "state", [BasicStates.PLUS, BasicStates.ZERO, BasicStates.ONE, BasicStates.PLUS_I, BasicStates.MINUS_I] - ) - def test_measurement_into_each_xyz_basis(self, state: PlanarState) -> None: - n = 3 - k = 0 - # for measurement into |-> returns [[0, 0], ..., [0, 0]] (whose norm is zero) - statevector = state.to_statevector() - m_op = np.outer(statevector, statevector.T.conjugate()) - sv = Statevec(nqubit=n) - sv.evolve(m_op.astype(np.complex128, copy=False), [k]) - sv.remove_qubit(k) - - sv2 = Statevec(nqubit=n - 1) - assert sv.isclose(sv2) - - def test_measurement_into_minus_state(self) -> None: - n = 3 - k = 0 - m_op = np.outer(BasicStates.MINUS.to_statevector(), BasicStates.MINUS.to_statevector().T.conjugate()) - sv = Statevec(nqubit=n) - sv.evolve(m_op.astype(np.complex128, copy=False), [k]) - with pytest.raises(AssertionError): - sv.remove_qubit(k) - - -class TestStatevecNew: - # test initialization only - def test_init_success(self, hadamardpattern: Pattern, fx_rng: Generator) -> None: - # plus state (default) - backend = StatevectorBackend() - backend.add_nodes(hadamardpattern.input_nodes) - vec = Statevec(nqubit=1) - assert np.allclose(vec.psi, backend.state.psi) - assert len(backend.state.dims()) == 1 - - # minus state - backend = StatevectorBackend() - backend.add_nodes(hadamardpattern.input_nodes, data=BasicStates.MINUS) - vec = Statevec(nqubit=1, data=BasicStates.MINUS) - assert np.allclose(vec.psi, backend.state.psi) - assert len(backend.state.dims()) == 1 - - # random planar state - rand_angle = fx_rng.random() * 2 * ANGLE_PI - rand_plane = fx_rng.choice(np.array(Plane)) - state = PlanarState(rand_plane, rand_angle) - backend = StatevectorBackend() - backend.add_nodes(hadamardpattern.input_nodes, data=state) - vec = Statevec(nqubit=1, data=state) - assert np.allclose(vec.psi, backend.state.psi) - # assert backend.state.nqubit == 1 - assert len(backend.state.dims()) == 1 - - # data input and Statevec input - - def test_init_fail(self, hadamardpattern: Pattern, fx_rng: Generator) -> None: - rand_angle = fx_rng.random(2) * 2 * ANGLE_PI - rand_plane = fx_rng.choice(np.array(Plane), 2) - - state = PlanarState(rand_plane[0], rand_angle[0]) - state2 = PlanarState(rand_plane[1], rand_angle[1]) - with pytest.raises(ValueError): - StatevectorBackend().add_nodes(hadamardpattern.input_nodes, data=[state, state2]) - - def test_clifford(self) -> None: - for clifford in Clifford: - state = BasicStates.PLUS - vec = Statevec(nqubit=1, data=state) - backend = StatevectorBackend() - backend.add_nodes(nodes=[0], data=state) - # Applies clifford gate "Z" - vec.evolve_single(clifford.matrix, 0) - backend.apply_clifford(node=0, clifford=clifford) - np.testing.assert_allclose( - vec.psi.astype(np.complex128, copy=False), backend.state.psi.astype(np.complex128, copy=False) - ) - - def test_deterministic_measure_one(self, fx_rng: Generator) -> None: - # plus state & zero state (default), but with tossed coins - for _ in range(10): - backend = StatevectorBackend() - coins = [fx_rng.choice([0, 1]), fx_rng.choice([0, 1])] - expected_result = sum(coins) % 2 - states = [ - Pauli.X.eigenstate(coins[0]), - Pauli.Z.eigenstate(coins[1]), - ] - nodes = range(len(states)) - backend.add_nodes(nodes=nodes, data=states) - - backend.entangle_nodes(edge=(nodes[0], nodes[1])) - measurement = Measurement.X - node_to_measure = backend.node_index[0] - result = backend.measure(node=node_to_measure, measurement=measurement, rng=fx_rng) - assert result == expected_result - - def test_deterministic_measure(self, fx_rng: Generator) -> None: - """Entangle |+> state with N |0> states, the (XY,0) measurement yields the outcome 0 with probability 1.""" - for _ in range(10): - # plus state (default) - backend = StatevectorBackend() - n_neighbors = 10 - states = [Pauli.X.eigenstate()] + [Pauli.Z.eigenstate() for i in range(n_neighbors)] - nodes = range(len(states)) - backend.add_nodes(nodes=nodes, data=states) - - for i in range(1, n_neighbors + 1): - backend.entangle_nodes(edge=(nodes[0], i)) - measurement = Measurement.X - node_to_measure = backend.node_index[0] - result = backend.measure(node=node_to_measure, measurement=measurement, rng=fx_rng) - assert result == 0 - assert list(backend.node_index) == list(range(1, n_neighbors + 1)) - - def test_deterministic_measure_many(self, fx_rng: Generator) -> None: - """Entangle |+> state with N |0> states, the (XY,0) measurement yields the outcome 0 with probability 1.""" - for _ in range(10): - # plus state (default) - backend = StatevectorBackend() - n_traps = 5 - n_neighbors = 5 - n_whatever = 5 - traps = [Pauli.X.eigenstate() for _ in range(n_traps)] - dummies = [Pauli.Z.eigenstate() for _ in range(n_neighbors)] - others = [Pauli.I.eigenstate() for _ in range(n_whatever)] - states = traps + dummies + others - nodes = range(len(states)) - backend.add_nodes(nodes=nodes, data=states) - - for dummy in nodes[n_traps : n_traps + n_neighbors]: - for trap in nodes[:n_traps]: - backend.entangle_nodes(edge=(trap, dummy)) - for other in nodes[n_traps + n_neighbors :]: - backend.entangle_nodes(edge=(other, dummy)) - - # Same measurement for all traps - measurement = Measurement.X - - for trap in nodes[:n_traps]: - node_to_measure = trap - result = backend.measure(node=node_to_measure, measurement=measurement, rng=fx_rng) - assert result == 0 - - assert list(backend.node_index) == list(range(n_traps, n_neighbors + n_traps + n_whatever)) - - def test_deterministic_measure_with_coin(self, fx_rng: Generator) -> None: - """Entangle |+> state with N |0> states, the (XY,0) measurement yields the outcome 0 with probability 1. - - We add coin toss to that. - """ - for _ in range(10): - # plus state (default) - backend = StatevectorBackend() - n_neighbors = 10 - coins = [fx_rng.choice([0, 1])] + [fx_rng.choice([0, 1]) for _ in range(n_neighbors)] - expected_result = sum(coins) % 2 - states = [Pauli.X.eigenstate(coins[0])] + [Pauli.Z.eigenstate(coins[i + 1]) for i in range(n_neighbors)] - nodes = range(len(states)) - backend.add_nodes(nodes=nodes, data=states) - - for i in range(1, n_neighbors + 1): - backend.entangle_nodes(edge=(nodes[0], i)) - measurement = Measurement.X - node_to_measure = backend.node_index[0] - result = backend.measure(node=node_to_measure, measurement=measurement, rng=fx_rng) - assert result == expected_result - assert list(backend.node_index) == list(range(1, n_neighbors + 1)) diff --git a/tests/test_tnsim.py b/tests/test_tnsim.py index c347e492b..bd4d23e13 100644 --- a/tests/test_tnsim.py +++ b/tests/test_tnsim.py @@ -12,7 +12,7 @@ from graphix.command import E from graphix.fundamentals import ANGLE_PI from graphix.ops import Ops -from graphix.random_objects import rand_circuit +from graphix.random_objects import rand_circuit, rand_unit from graphix.sim.statevec import Statevec from graphix.sim.tensornet import MBQCTensorNet, gen_str from graphix.states import BasicStates @@ -399,8 +399,8 @@ def test_evolve(self, fx_bg: PCG64, jumps: int, fx_rng: Generator) -> None: pattern.remove_pauli_measurements() state = circuit.simulate_statevector().statevec tn_mbqc = pattern.simulate_pattern(backend="tensornetwork", rng=fx_rng) - random_op3 = random_op(3, rng) - random_op3_exp = random_op(3, rng) + random_op3 = rand_unit(2**3, rng) + random_op3_exp = rand_unit(2**3, rng) state.evolve(random_op3, [0, 1, 2]) tn_mbqc.evolve(random_op3, [0, 1, 2], decompose=False) From c29885fb1366c4010977edf7f80a65273707d933 Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 26 May 2026 18:35:16 +0200 Subject: [PATCH 05/25] Rename parameters functions --- graphix/sim/base_backend.py | 22 ++- graphix/sim/density_matrix.py | 52 +++--- graphix/sim/statevec.py | 62 ++++--- graphix/simulator.py | 11 +- tests/test_statevec.py | 326 ++++++---------------------------- 5 files changed, 141 insertions(+), 332 deletions(-) diff --git a/graphix/sim/base_backend.py b/graphix/sim/base_backend.py index 11ebeb9cc..593feb590 100644 --- a/graphix/sim/base_backend.py +++ b/graphix/sim/base_backend.py @@ -6,7 +6,7 @@ import math from abc import ABC, abstractmethod from dataclasses import dataclass -from typing import TYPE_CHECKING, Generic, SupportsFloat, TypeAlias, TypeVar +from typing import TYPE_CHECKING, Generic, SupportsFloat, TypeAlias, TypedDict, TypeVar import numpy as np import numpy.typing as npt @@ -380,12 +380,12 @@ def add_nodes(self, nqubit: int, data: Data) -> None: """ @abstractmethod - def entangle(self, edge: tuple[int, int]) -> None: + def entangle(self, qubits: tuple[int, int]) -> None: """Connect graph nodes. Parameters ---------- - edge : tuple of int + qubits : tuple of int (control, target) qubit indices """ @@ -402,14 +402,14 @@ def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: """ @abstractmethod - def evolve_single(self, op: Matrix, i: int) -> None: + def evolve_single(self, op: Matrix, qubit: int) -> None: """Apply a single-qubit operation. Parameters ---------- op : numpy.ndarray 2*2 matrix - i : int + qubit : int qubit index """ @@ -682,6 +682,14 @@ def measure( _DenseStateT_co = TypeVar("_DenseStateT_co", bound="DenseState", covariant=True) +class DenseStateBackendKwargs(TypedDict, total=False): + """Keyword arguments for initializing a `DenseStateBackend`.""" + + node_index: NodeIndex + branch_selector: BranchSelector + symbolic: bool + + @dataclass(frozen=True) class DenseStateBackend(Backend[_DenseStateT_co], Generic[_DenseStateT_co]): """ @@ -709,6 +717,8 @@ class DenseStateBackend(Backend[_DenseStateT_co], Generic[_DenseStateT_co]): symbolic : bool, optional If True, support arbitrary objects (typically, symbolic expressions) in matrices. + All parameters are key-word only. + See Also -------- :class:`StatevecBackend`, :class:`DensityMatrixBackend`, :class:`TensorNetworkBackend` @@ -811,7 +821,7 @@ def apply_noise(self, cmd: ApplyNoise) -> None: def apply_single(self, node: int, op: Matrix) -> None: """Apply a single gate to the state.""" index = self.node_index.index(node) - self.state.evolve_single(op=op, i=index) + self.state.evolve_single(op=op, qubit=index) @override def apply_clifford(self, node: int, clifford: Clifford) -> None: diff --git a/graphix/sim/density_matrix.py b/graphix/sim/density_matrix.py index 16a334d29..1f04d0859 100644 --- a/graphix/sim/density_matrix.py +++ b/graphix/sim/density_matrix.py @@ -159,33 +159,33 @@ def add_nodes(self, nqubit: int, data: Data) -> None: self.tensor(dm_to_add) @override - def evolve_single(self, op: Matrix, i: int) -> None: + def evolve_single(self, op: Matrix, qubit: int) -> None: """Single-qubit operation. Parameters ---------- op : np.ndarray 2*2 matrix. - i : int + qubit : int Index of qubit to apply operator. """ - assert i >= 0 - assert i < self.nqubit + assert qubit >= 0 + assert qubit < self.nqubit if op.shape != (2, 2): raise ValueError("op must be 2*2 matrix.") rho_tensor = self.rho.reshape((2,) * self.nqubit * 2) - rho_tensor = tensordot(tensordot(op, rho_tensor, axes=(1, i)), op.conj().T, axes=(i + self.nqubit, 0)) - rho_tensor = np.moveaxis(rho_tensor, (0, -1), (i, i + self.nqubit)) + rho_tensor = tensordot(tensordot(op, rho_tensor, axes=(1, qubit)), op.conj().T, axes=(qubit + self.nqubit, 0)) + rho_tensor = np.moveaxis(rho_tensor, (0, -1), (qubit, qubit + self.nqubit)) self.rho = rho_tensor.reshape((2**self.nqubit, 2**self.nqubit)) @override - def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: + def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: """Multi-qubit operation. Args: op (np.array): 2^n*2^n matrix - qargs (list of ints): target qubits' indexes + qubits (list of ints): target qubits' indexes """ d = op.shape # check it is a matrix. @@ -203,12 +203,12 @@ def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: raise ValueError("Incorrect operator dimension: not consistent with qubits.") nqb_op = int(nqb_op) - if nqb_op != len(qargs): + if nqb_op != len(qubits): raise ValueError("The dimension of the operator doesn't match the number of targets.") - if not all(0 <= i < self.nqubit for i in qargs): + if not all(0 <= i < self.nqubit for i in qubits): raise ValueError("Incorrect target indices.") - if len(set(qargs)) != nqb_op: + if len(set(qubits)) != nqb_op: raise ValueError("A repeated target qubit index is not possible.") op_tensor = op.reshape((2,) * 2 * nqb_op) @@ -216,31 +216,31 @@ def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: rho_tensor = self.rho.reshape((2,) * self.nqubit * 2) rho_tensor = tensordot( - tensordot(op_tensor, rho_tensor, axes=(tuple(nqb_op + i for i in range(len(qargs))), tuple(qargs))), + tensordot(op_tensor, rho_tensor, axes=(tuple(nqb_op + i for i in range(len(qubits))), tuple(qubits))), op.conj().T.reshape((2,) * 2 * nqb_op), - axes=(tuple(i + self.nqubit for i in qargs), tuple(i for i in range(len(qargs)))), + axes=(tuple(i + self.nqubit for i in qubits), tuple(i for i in range(len(qubits)))), ) rho_tensor = np.moveaxis( rho_tensor, - list(range(len(qargs))) + [-i for i in range(1, len(qargs) + 1)], - list(qargs) + [i + self.nqubit for i in reversed(list(qargs))], + list(range(len(qubits))) + [-i for i in range(1, len(qubits) + 1)], + list(qubits) + [i + self.nqubit for i in reversed(list(qubits))], ) self.rho = rho_tensor.reshape((2**self.nqubit, 2**self.nqubit)) @override - def expectation_single(self, op: Matrix, loc: int) -> complex: + def expectation_single(self, op: Matrix, qubit: int) -> complex: """Return the expectation value of single-qubit operator. Args: op (np.array): 2*2 Hermite operator - loc (int): Index of qubit on which to apply operator. + qubit (int): Index of qubit on which to apply operator. Returns ------- complex: expectation value (real for hermitian ops!). """ - if not (0 <= loc < self.nqubit): - raise ValueError(f"Wrong target qubit {loc}. Must between 0 and {self.nqubit - 1}.") + if not (0 <= qubit < self.nqubit): + raise ValueError(f"Wrong target qubit {qubit}. Must between 0 and {self.nqubit - 1}.") if op.shape != (2, 2): raise ValueError("op must be 2x2 matrix.") @@ -250,8 +250,8 @@ def expectation_single(self, op: Matrix, loc: int) -> complex: nqubit = self.nqubit rho_tensor: Matrix = st1.rho.reshape((2,) * nqubit * 2) - rho_tensor = tensordot(op, rho_tensor, axes=((1,), (loc,))) - rho_tensor = np.moveaxis(rho_tensor, 0, loc) + rho_tensor = tensordot(op, rho_tensor, axes=((1,), (qubit,))) + rho_tensor = np.moveaxis(rho_tensor, 0, qubit) # complex() needed with mypy strict mode (no-any-return) return complex(np.trace(rho_tensor.reshape((2**nqubit, 2**nqubit)))) @@ -295,15 +295,15 @@ def swap(self, qubits: tuple[int, int]) -> None: """ self.evolve(SWAP_TENSOR.reshape(4, 4), qubits) - def entangle(self, edge: tuple[int, int]) -> None: + def entangle(self, qubits: tuple[int, int]) -> None: """Connect graph nodes. Parameters ---------- - edge : (int, int) or [int, int] + qubits : (int, int) or [int, int] (control, target) qubit indices. """ - self.evolve(CZ_TENSOR.reshape(4, 4), edge) + self.evolve(CZ_TENSOR.reshape(4, 4), qubits) def normalize(self) -> None: """Normalize density matrix.""" @@ -319,9 +319,9 @@ def normalize(self) -> None: rho_c /= np.trace(rho_c) @override - def remove_qubit(self, qarg: int) -> None: + def remove_qubit(self, qubit: int) -> None: """Remove a qubit.""" - self.ptrace(qarg) + self.ptrace(qubit) self.normalize() def ptrace(self, qargs: Collection[int] | int) -> None: diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 51492be99..1f1e38b6c 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -16,13 +16,16 @@ from typing_extensions import override from graphix.parameter import ExpressionOrSupportsComplex -from graphix.sim.base_backend import DenseState, DenseStateBackend, Matrix +from graphix.sim.base_backend import DenseState, DenseStateBackend, DenseStateBackendKwargs, Matrix from graphix.states import BasicStates, State if TYPE_CHECKING: from collections.abc import Callable, Sequence from typing import Any, Literal, Self, TypeAlias, TypeVar + # Unpack introduced in Python 3.12 + from typing_extensions import Unpack + from graphix.sim.data import Data _ENCODING = Literal["LSB", "MSB"] @@ -250,65 +253,65 @@ def add_nodes(self, nqubit: int, data: Data) -> None: self.tensor(sv_to_add) @override - def entangle(self, edge: tuple[int, int]) -> None: + def entangle(self, qubits: tuple[int, int]) -> None: """Connect graph nodes. Parameters ---------- - edge : tuple of int + qubits : tuple of int (control, target) qubit indices """ kernel = _entangle_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _entangle_jit - kernel(self.psi, self.nqubit, *edge) + kernel(self.psi, self.nqubit, *qubits) @override - def evolve_single(self, op: Matrix, i: int) -> None: + def evolve_single(self, op: Matrix, qubit: int) -> None: """Apply a single-qubit operation. Parameters ---------- op : numpy.ndarray 2*2 matrix - i : int + q : int qubit index """ - self._check_bounds(i) + self._check_bounds(qubit) kernel = _evolve_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _evolve_single_jit # We cast to np.complex128 to match numba signature. - kernel(self.psi, op.astype(np.complex128), self.nqubit, i) + kernel(self.psi, op.astype(np.complex128), self.nqubit, qubit) @override - def expectation_single(self, op: Matrix, loc: int) -> complex: + def expectation_single(self, op: Matrix, qubit: int) -> complex: """Return the expectation value of single-qubit operator. Parameters ---------- op : numpy.ndarray 2*2 operator - loc : int + qubit : int target qubit index Returns ------- complex : expectation value. """ - self._check_bounds(loc) + self._check_bounds(qubit) kernel = _expectation_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _expectation_single_jit # We cast to np.complex128 to match numba signature. - return kernel(self.psi, op.astype(np.complex128), self.nqubit, loc) + return kernel(self.psi, op.astype(np.complex128), self.nqubit, qubit) @override - def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: + def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: """Apply a multi-qubit operation. Parameters ---------- op : numpy.ndarray 2^n*2^n matrix - qargs : list of int + qubits : list of int target qubits' indices """ - nq = len(qargs) + nq = len(qubits) # treat op as a tensor with nq output + nq input legs op_t = op.reshape((2,) * (nq * 2)).astype(np.complex128, copy=False) psi_t = self.flatten().reshape((2,) * self.nqubit).astype(np.complex128, copy=False) @@ -316,23 +319,23 @@ def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: psi_idx = np.array(range(self.nqubit)) out_idx = np.array(range(self.nqubit, self.nqubit + nq)) # fresh labels - op_idx = np.concatenate((out_idx, qargs)) + op_idx = np.concatenate((out_idx, qubits)) # result subscripts: same as psi but modified indices (qargs) replaced by out labels res_idx = psi_idx.copy() - for i, s in enumerate(qargs): + for i, s in enumerate(qubits): res_idx[s] = out_idx[i] self.psi[: self.size_valid_psi] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) - def expectation_value(self, op: Matrix, qargs: Sequence[int]) -> complex: + def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: """Return the expectation value of multi-qubit operator. Parameters ---------- op : numpy.ndarray 2^n*2^n operator - qargs : list of int + qubits : list of int target qubit indices Returns @@ -340,11 +343,11 @@ def expectation_value(self, op: Matrix, qargs: Sequence[int]) -> complex: complex : expectation value """ sv = deepcopy(self) - sv.evolve(op, qargs) + sv.evolve(op, qubits) return complex(np.dot(self.flatten().conjugate(), sv.flatten())) @override - def remove_qubit(self, qarg: int) -> None: + def remove_qubit(self, qubit: int) -> None: r"""Remove a separable qubit from the system and assemble a statevector for remaining qubits. This results in the same result as partial trace, if the qubit *qarg* is separable from the rest. @@ -380,11 +383,11 @@ def remove_qubit(self, qarg: int) -> None: Parameters ---------- - qarg : int + qubit : int qubit index """ - self._check_bounds(qarg) - self._nqubit = _remove_qubit_jit(self.psi, self.nqubit, qarg, atol=1e-10) + self._check_bounds(qubit) + self._nqubit = _remove_qubit_jit(self.psi, self.nqubit, qubit, atol=1e-10) @override def swap(self, qubits: tuple[int, int]) -> None: @@ -410,14 +413,14 @@ def tensor(self, other: Statevec) -> None: _tensor_jit(self.psi, other.psi, self.nqubit, other.nqubit) self._nqubit += other.nqubit - def _check_bounds(self, i: int) -> None: + def _check_bounds(self, qubit: int) -> None: """Check if qubit index is valid. This check is necessary because there is no bounds checking in Numba. See https://numba.pydata.org/numba-doc/dev/reference/pysemantics.html#bounds-checking """ - if not 0 <= i < self.nqubit: - raise IndexError(f"Qubit index {i} out of range [0, {self.nqubit})") + if not 0 <= qubit < self.nqubit: + raise IndexError(f"Qubit index {qubit} out of range [0, {self.nqubit})") def fidelity(self, other: Statevec) -> float: r"""Calculate the fidelity against another statevector. @@ -562,7 +565,6 @@ def _to_dict_map( return {_format_encoding(self.nqubit, i, encoding): amp for i, amp in zip(i_vals, amp_vals, strict=True)} -# TODO: type **kwargs with Unpack @dataclass(frozen=True) class StatevectorBackend(DenseStateBackend[Statevec]): """MBQC state vector backend simulator based on 10.48550/arXiv.2506.08142.""" @@ -570,7 +572,9 @@ class StatevectorBackend(DenseStateBackend[Statevec]): state: Statevec = dataclasses.field(init=True, default_factory=lambda: Statevec(nqubit=0)) @classmethod - def with_capacity(cls, max_qubits: int, state: Statevec | None = None, **kwargs) -> Self: + def with_capacity( + cls, max_qubits: int, state: Statevec | None = None, **kwargs: Unpack[DenseStateBackendKwargs] + ) -> Self: """Initialize the backend with the required capacity to perform the simulation. Parameters diff --git a/graphix/simulator.py b/graphix/simulator.py index e81439ebc..12a64b9a7 100644 --- a/graphix/simulator.py +++ b/graphix/simulator.py @@ -356,7 +356,7 @@ def __init__( graph_prep: str, optional [Tensor network backend only] Strategy for preparing the graph state. See :class:`TensorNetworkBackend`. symbolic : bool, optional - [State vector and density matrix backends only] If True, support arbitrary objects (typically, symbolic expressions) in measurement angles. + [Density matrix backend only] If True, support arbitrary objects (typically, symbolic expressions) in measurement angles. stacklevel : int, optional Stack level to use for warnings. Defaults to 1, meaning that warnings are reported at this function's call site. @@ -531,7 +531,7 @@ def _initialize_backend( graph_prep: str, optional [Tensor network backend only] Strategy for preparing the graph state. See :class:`TensorNetworkBackend`. symbolic : bool, optional - [State vector and density matrix backends only] If True, support arbitrary objects (typically, symbolic expressions) in measurement angles. + [Density matrix backend only] If True, support arbitrary objects (typically, symbolic expressions) in measurement angles. Returns ------- @@ -562,7 +562,12 @@ def _initialize_backend( case "statevector": if noise_model is not None: raise ValueError("`noise_model` cannot be specified for state vector backend.") - return StatevectorBackend(branch_selector=branch_selector, symbolic=symbolic) + if symbolic: + raise ValueError( + "Statevector backend does not support `symbolic` simulation. Consider using backend in `graphix-symbolic` plugin." + ) + nqubits = pattern.max_space() + return StatevectorBackend.with_capacity(nqubits, branch_selector=branch_selector) case "densitymatrix": if noise_model is None: warnings.warn( diff --git a/tests/test_statevec.py b/tests/test_statevec.py index 547d3d807..b8cab8e8a 100644 --- a/tests/test_statevec.py +++ b/tests/test_statevec.py @@ -8,13 +8,16 @@ import pytest from numpy.random import Generator +from graphix.branch_selector import ConstBranchSelector from graphix.clifford import Clifford +from graphix.instruction import Instruction from graphix.measurements import Measurement from graphix.ops import Ops from graphix.pauli import Pauli from graphix.random_objects import rand_unit from graphix.sim.statevec import Statevec, StatevectorBackend from graphix.states import BasicStates +from graphix.transpiler import Circuit if TYPE_CHECKING: from collections.abc import Mapping @@ -417,6 +420,36 @@ def test_to_prob_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) assert np.isclose(dict_ref[ket], amp2.real) assert np.isclose(0, amp2.imag) + def test_simulation_identity(self, fx_rng: Generator) -> None: + nqubits = 3 + qc = Circuit(nqubits) + angle_1 = 2 * fx_rng.random() + angle_2 = 2 * fx_rng.random() + qc.extend( + [ + Instruction.H(0), + Instruction.CNOT(0, 1), + Instruction.CNOT(1, 2), + Instruction.RZZ(0, 1, angle_1), + Instruction.RY(2, angle_2), + ] + ) + qc.extend( + [ + Instruction.RZZ(0, 1, -angle_1), + Instruction.RY(2, -angle_2), + Instruction.CNOT(1, 2), + Instruction.CNOT(0, 1), + Instruction.H(0), + ] + ) + pattern = qc.transpile().pattern + data = generate_rnd_data(fx_rng, nqubits) + sv = Statevec(data=data) + sv_test = pattern.simulate_pattern(backend="statevector", input_state=sv, rng=fx_rng) + + assert sv_test.isclose(sv) + class TestStatevectorBackend: @pytest.mark.parametrize( @@ -449,6 +482,31 @@ def test_init_capacity(self, n_nodes: int, fx_rng: Generator) -> None: assert backend.state.isclose(sv) assert backend.state.max_qubits == max(n_nodes, capacity) + def test_init_branch_selector(self) -> None: + max_qubits = 5 + sv = Statevec(nqubit=3) + bs = ConstBranchSelector(result=0) + + backend = StatevectorBackend.with_capacity(max_qubits, sv, branch_selector=bs) + + assert backend.branch_selector is bs + assert backend.state.isclose(sv) + assert backend.state.max_qubits == 5 + + def test_init_branch_selector_kw(self) -> None: + sv = Statevec(nqubit=3) + bs = ConstBranchSelector(result=0) + + with pytest.raises(TypeError): + # Branch selector is keyword only (enforced by dataclass sentinel) + StatevectorBackend(sv, bs) # type: ignore[misc, arg-type] + + backend = StatevectorBackend(sv, branch_selector=bs) + + assert backend.branch_selector is bs + assert backend.state.isclose(sv) + assert backend.state.max_qubits == 3 + @pytest.mark.parametrize( ("clifford"), Clifford, @@ -557,271 +615,3 @@ def test_deterministic_measure_with_coin(self, fx_bg: PCG64, jumps: int) -> None result = backend.measure(node=node_to_measure, measurement=measurement, rng=rng) assert result == expected_result assert list(backend.node_index) == list(range(1, n_neighbors + 1)) - - -# class TestStatevecLegacy: -# """Tests in this class compare the result against the existing statevector simulator in Graphix. They are not self-contained.""" - -# N_JUMPS = 3 - -# @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) -# def test_entangle(self, fx_bg: PCG64, jumps: int) -> None: -# rng = Generator(fx_bg.jumped(jumps)) -# nqubits = 5 -# sv_test = Statevec(generate_rnd_data(rng, nqubits)) -# sv_ref = SVLegacy(data=sv_test.flatten()) -# edge: tuple[int, int] = tuple(rng.choice(range(nqubits), size=2, replace=False)) -# for sv in [sv_test, sv_ref]: -# sv.entangle(edge) - -# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) - -# @pytest.mark.parametrize("jumps", range(1, N_JUMPS)) -# def test_swap(self, fx_bg: PCG64, jumps: int) -> None: -# rng = Generator(fx_bg.jumped(jumps)) -# nqubits = 5 -# sv_test = Statevec(generate_rnd_data(rng, nqubits)) -# sv_ref = SVLegacy(data=sv_test.flatten()) -# edge: tuple[int, int] = tuple(rng.choice(range(nqubits), size=2, replace=False)) -# for sv in [sv_test, sv_ref]: -# sv.swap(edge) - -# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) - -# def test_evolve_single(self, fx_rng: Generator) -> None: -# nqubits = 5 -# for clifford in Clifford: -# sv_test = Statevec(generate_rnd_data(fx_rng, nqubits)) -# sv_ref = SVLegacy(data=sv_test.flatten()) -# qubit = int(fx_rng.integers(0, nqubits)) -# for sv in [sv_test, sv_ref]: -# sv.evolve_single(clifford.matrix, qubit) -# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) - -# def test_expectation_single(self, fx_rng: Generator) -> None: -# nqubits = 5 -# for clifford in Clifford: -# sv_test = Statevec(generate_rnd_data(fx_rng, nqubits)) -# sv_ref = SVLegacy(data=sv_test.flatten()) -# qubit = int(fx_rng.integers(0, nqubits)) - -# val_test = sv_test.expectation_single(clifford.matrix, qubit) -# val_ref = sv_ref.expectation_single(clifford.matrix, qubit) - -# assert math.isclose(val_test.real, val_ref.real, abs_tol=1e-12) -# assert math.isclose(val_test.imag, val_ref.imag, abs_tol=1e-12) - -# def test_add_nodes(self, fx_rng: Generator) -> None: - -# max_qubits = 5 -# sv_test = Statevec(nqubit=0, max_qubits=max_qubits) -# sv_ref = SVLegacy(nqubit=0) - -# for _ in range(max_qubits): # Add a node at each iteration -# data = generate_rnd_data(fx_rng, nqubits=1) -# sv_test.add_nodes(1, data) -# sv_ref.add_nodes(1, data) - -# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) - -# @pytest.mark.parametrize( -# "projector", [np.array([[1, 0], [0, 0]], dtype=np.complex128), np.array([[0, 0], [0, 1]], dtype=np.complex128)] -# ) -# def test_remove_nodes(self, fx_rng: Generator, projector: npt.NDArray[np.complex128]) -> None: - -# nqubits = 5 -# sv_test = Statevec(generate_rnd_data(fx_rng, nqubits)) -# sv_ref = SVLegacy(data=sv_test.flatten()) -# q = 0 -# for _ in range(nqubits - 1): # Remove a node at each iteration -# sv_test.evolve_single(projector, q) -# sv_test.remove_qubit(q) -# sv_ref.evolve_single(projector, q) -# sv_ref.remove_qubit(q) - -# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) - - -# @pytest.mark.parametrize("jumps", range(1, 6)) -# def test_pattern_simulator(fx_bg: PCG64, jumps: int) -> None: -# rng = Generator(fx_bg.jumped(jumps)) - -# nqubits = 5 - -# pattern = rand_circuit(nqubits, depth=5, rng=rng).transpile().pattern -# pattern.remove_pauli_measurements() - -# backend = StatevectorBackend.with_capacity(pattern.max_space()) -# sv_test = pattern.simulate_pattern(backend=backend, rng=rng) -# sv_ref = pattern.simulate_pattern(backend=SBLegacy(), rng=rng) - -# assert sv_ref.isclose(SVLegacy(data=sv_test.flatten())) - - -# from __future__ import annotations - -# import functools -# from typing import TYPE_CHECKING - -# import numpy as np -# import pytest - -# from graphix.fundamentals import ANGLE_PI, Plane -# from graphix.pattern import Pattern -# from graphix.sim.statevec import Statevec, _norm_numeric -# from graphix.states import BasicStates, PlanarState - -# if TYPE_CHECKING: -# from collections.abc import Mapping -# from typing import Literal - -# from numpy.random import Generator - -# _ENCODING = Literal["LSB", "MSB"] - - -# class TestStatevec: -# """Test for Statevec class. Particularly new constructor.""" - -# # test initializing one qubit in plus state -# def test_default_success(self) -> None: -# vec = Statevec(nqubit=1) -# assert np.allclose(vec.psi, np.array([1, 1] / np.sqrt(2))) -# assert len(vec.dims()) == 1 - -# def test_basicstates_success(self) -> None: -# # minus -# vec = Statevec(nqubit=1, data=BasicStates.MINUS) -# assert np.allclose(vec.psi, np.array([1, -1] / np.sqrt(2))) -# assert len(vec.dims()) == 1 - -# # zero -# vec = Statevec(nqubit=1, data=BasicStates.ZERO) -# assert np.allclose(vec.psi, np.array([1, 0]), rtol=0, atol=1e-15) -# assert len(vec.dims()) == 1 - -# # one -# vec = Statevec(nqubit=1, data=BasicStates.ONE) -# assert np.allclose(vec.psi, np.array([0, 1]), rtol=0, atol=1e-15) -# assert len(vec.dims()) == 1 - -# # plus_i -# vec = Statevec(nqubit=1, data=BasicStates.PLUS_I) -# assert np.allclose(vec.psi, np.array([1, 1j] / np.sqrt(2))) -# assert len(vec.dims()) == 1 - -# # minus_i -# vec = Statevec(nqubit=1, data=BasicStates.MINUS_I) -# assert np.allclose(vec.psi, np.array([1, -1j] / np.sqrt(2))) -# assert len(vec.dims()) == 1 - -# # even more tests? -# def test_default_tensor_success(self, fx_rng: Generator) -> None: -# nqb = int(fx_rng.integers(2, 5)) -# print(f"nqb is {nqb}") -# vec = Statevec(nqubit=nqb) -# assert np.allclose(vec.psi, np.ones((2,) * nqb) / (np.sqrt(2)) ** nqb) -# assert len(vec.dims()) == nqb - -# vec = Statevec(nqubit=nqb, data=BasicStates.MINUS_I) -# sv_list = [BasicStates.MINUS_I.to_statevector() for _ in range(nqb)] -# sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) -# assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) -# assert len(vec.dims()) == nqb - -# # tensor of same state -# rand_angle = fx_rng.random() * 2 * ANGLE_PI -# rand_plane = fx_rng.choice(np.array(Plane)) -# state = PlanarState(rand_plane, rand_angle) -# vec = Statevec(nqubit=nqb, data=state) -# sv_list = [state.to_statevector() for _ in range(nqb)] -# sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) -# assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) -# assert len(vec.dims()) == nqb - -# # tensor of different states -# rand_angles = fx_rng.random(nqb) * 2 * ANGLE_PI -# rand_planes = fx_rng.choice(np.array(Plane), nqb) -# states = [PlanarState(plane=i, angle=j) for i, j in zip(rand_planes, rand_angles, strict=True)] -# vec = Statevec(nqubit=nqb, data=states) -# sv_list = [state.to_statevector() for state in states] -# sv = functools.reduce(lambda a, b: np.kron(a, b).astype(np.complex128, copy=False), sv_list) -# assert np.allclose(vec.psi, sv.reshape((2,) * nqb)) -# assert len(vec.dims()) == nqb - -# def test_data_success(self, fx_rng: Generator) -> None: -# nqb = fx_rng.integers(2, 5) -# length = 2**nqb -# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) -# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) -# vec = Statevec(data=rand_vec) -# assert np.allclose(vec.psi, rand_vec.reshape((2,) * nqb)) -# assert len(vec.dims()) == nqb - -# # fail: incorrect len -# def test_data_dim_fail(self, fx_rng: Generator) -> None: -# length = 5 -# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) -# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) -# with pytest.raises(ValueError): -# _vec = Statevec(data=rand_vec) - -# # fail: with less qubit than number of qubits inferred from a correct state vect -# def test_data_dim_fail_mismatch(self, fx_rng: Generator) -> None: -# nqb = 3 -# rand_vec = fx_rng.random(2**nqb) + 1j * fx_rng.random(2**nqb) -# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) -# with pytest.raises(ValueError): -# _vec = Statevec(nqubit=2, data=rand_vec) - -# # fail: not normalized -# def test_data_norm_fail(self, fx_rng: Generator) -> None: -# nqb = fx_rng.integers(2, 5) -# length = 2**nqb -# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) -# with pytest.raises(ValueError): -# _vec = Statevec(data=rand_vec) - -# def test_defaults_to_one(self) -> None: -# vec = Statevec() -# assert len(vec.dims()) == 1 - -# # try copying Statevec input -# def test_copy_success(self, fx_rng: Generator) -> None: -# nqb = fx_rng.integers(2, 5) -# length = 2**nqb -# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) -# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) -# test_vec = Statevec(data=rand_vec) -# # try to copy it -# vec = Statevec(data=test_vec) - -# assert np.allclose(vec.psi, test_vec.psi) -# assert len(vec.dims()) == len(test_vec.dims()) - -# # try calling with incorrect number of qubits compared to inferred one -# def test_copy_fail(self, fx_rng: Generator) -> None: -# nqb = int(fx_rng.integers(2, 5)) -# length = 1 << nqb -# rand_vec = fx_rng.random(length) + 1j * fx_rng.random(length) -# rand_vec /= np.sqrt(np.sum(np.abs(rand_vec) ** 2)) -# test_vec = Statevec(data=rand_vec) - -# with pytest.raises(ValueError): -# _vec = Statevec(nqubit=length - 1, data=test_vec) - -# def test_nqubits(self) -> None: -# for i in [1, 2, 5]: -# sv = Statevec(nqubit=i) -# assert sv.nqubit == i - -# def test_nqubits_pattern(self) -> None: -# p = Pattern(input_nodes=[0, 1, 2]) -# sv = p.simulate_pattern(backend="statevector") -# assert sv.nqubit == 3 - - -# def test_normalize() -> None: -# statevec = Statevec(nqubit=1, data=BasicStates.PLUS) -# statevec.remove_qubit(0) -# assert _norm_numeric(statevec.psi.astype(np.complex128, copy=False)) == 1 From 32a830b5a77ada0960953f6aadac4edbf7a0f3b8 Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 26 May 2026 18:35:44 +0200 Subject: [PATCH 06/25] Save statevec.py file --- graphix/sim/statevec.py | 1 - 1 file changed, 1 deletion(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 1f1e38b6c..e0638cf6a 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -46,7 +46,6 @@ """This constant determines the number of qubits above which matrix operations are multi-threaded. For lower counts, the overhead does not compensate parallelization.""" -# TODO: Use q for function parameters class Statevec(DenseState): """Statevector object. From 1693dbec90fefdc43f0f454d50363a8888833039 Mon Sep 17 00:00:00 2001 From: matulni Date: Wed, 27 May 2026 16:21:39 +0200 Subject: [PATCH 07/25] Up docs --- graphix/sim/statevec.py | 269 ++++++++++++++++++++++++++++++---------- 1 file changed, 201 insertions(+), 68 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index e0638cf6a..3d2397c9e 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -1,4 +1,7 @@ -"""MBQC state vector backend simulator based on 10.48550/arXiv.2506.08142.""" +"""Numba JIT-compiled MBQC statevector backend simulator based on Ref. [1]. + +[1] McGuffin, M. J., Robert J-M., and Ikeda K. "How to Write a Simulator for Quantum Circuits from Scratch: A Tutorial.", 2025 (arXiv:2506.08142). +""" from __future__ import annotations @@ -43,7 +46,9 @@ NUM_QUBIT_PARALLEL = 15 -"""This constant determines the number of qubits above which matrix operations are multi-threaded. For lower counts, the overhead does not compensate parallelization.""" +"""This constant determines the number of qubits above which matrix operations +are multi-threaded. For lower counts, the overhead does not compensate parallelization. +This number was determined empirically and it may be platform dependent.""" class Statevec(DenseState): @@ -51,15 +56,36 @@ class Statevec(DenseState): Attributes ---------- - psi : numpy.ndarray of numpy.complex128 + psi : npt.NDArray[np.complex128] Complex-valued 1-dimensional array representing the quantum statevector. - Throughout the simulation ``psi`` has constant size ``2**max_qubits``. Only the first ``2**nqubit`` complex values have meaning. + Only the first ``2**nqubit`` complex values have meaning. _max_qubits : int - Maximum Hilbert space size allowed for internal computations. It determines the size of ``psi``. For circuit simulations, it corresponds to the number of qubits, while for pattern simulations it corresponds to the pattern's maximum space. + Maximum Hilbert space size allowed for internal computations. It determines + the size of ``psi``. For circuit simulations, it corresponds to the number + of qubits, while for pattern simulations it corresponds to the pattern's + maximum space. The method :meth:`Statevec.ensure_capacity` allows to increase + this number. _nqubit : int Number of active qubits at any given time. + + Notes + ----- + The internal representation of the quantum state is guaranteed to be + normalized after initialization, and it is assumed to remain normalized + thereafter. + + Using :meth:`evolve_single`, :meth:`expectation_single`, :meth:`evolve`, + or :meth:`expectation_value` with non-unitary operators does not preserve + the norm of the statevector and may lead to unexpected behavior. + + In pattern simulation, node measurements call :meth:`evolve_single` with + a projector (a non-unitary operator). However, the measured qubit is + immediately removed via :meth:`remove_qubit`, which restores the unit + norm of the internal quantum state. + See :meth:`graphix.sim.base_backend.DenseStateBackend.measure` for additional + details. """ psi: npt.NDArray[np.complex128] @@ -67,14 +93,24 @@ class Statevec(DenseState): _nqubit: int def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max_qubits: int | None = None) -> None: - """Initialize statevector objects. + """Initialize a statevector object. - See :class:`graphix.sim.statevec.Statevec` for additional information. + `data` can be: + - a single :class:`graphix.states.State` (classical description of a quantum state) + - an iterable of :class:`graphix.states.State` objects + - an iterable of scalars (a :math:`2^n` numerical statevector) + - a single :class:`graphix.statevec.Statevec` + + If ``nqubit`` is not provided, it is inferred from ``data``. + If ``max_qubits`` is not provided, it is set to match the provided or inferred ``nqubit``. + If only one :class:`graphix.states.State` is provided and ``nqubit`` is a valid integer, the statevector is initialized in the tensor product state. + If a ``graphix.statevec.Statevec`` is provided, a copy is returned. + Consistency between provided ``nqubit``, ``max_qubits`` and ``data`` is checked. Parameters ---------- data : Data, optional - Input data to prepare the state. Can be a classical description or a numerical input, defaults to `graphix.states.BasicStates.PLUS` + Input data to prepare the state. Can be a classical description or a numerical input, defaults to `graphix.states.BasicStates.PLUS`. nqubit : int | None, optional Number of qubits to prepare. If ``None`` (default), it's inferred from ``data``. max_qubits : int | None, optional. @@ -83,7 +119,7 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max Raises ------ ValueError - If `max_qubits` is smaller than `nqubit` or the number of qubits inferred from ``data``. + If ``nqubit``, ``max_qubits`` or ``data`` are not consistent with each other. """ if nqubit is not None and nqubit < 0: raise ValueError("`nqubit` must be a non-negative integer.") @@ -103,7 +139,7 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max if max_qubits is not None: if max_qubits < data.max_qubits: raise ValueError( - f"`max_qubits` can't be smaller than the capacity of input state: {max_qubits} < {data.max_qubits}" + f"`max_qubits` can't be smaller than the capacity of input state: {max_qubits} < {data.max_qubits}." ) self.ensure_capacity(max_qubits) return @@ -120,11 +156,11 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max elif isinstance(data, Iterable): input_list = list(data) else: - raise TypeError(f"Incorrect type for data: {type(data)}") + raise TypeError(f"Incorrect type for data: {type(data)}.") if len(input_list) == 0: if nqubit is not None and nqubit != 0: - raise ValueError("nqubit is not null but input state is empty.") + raise ValueError("`nqubit` is not null but input state is empty.") nqubit = 0 psi = np.array([1], dtype=np.complex128) @@ -153,21 +189,23 @@ def state_to_statevector( inferred_nqubit = length.bit_length() - 1 if nqubit is None: if length & (length - 1): - raise ValueError(f"Length of input data is not a power of two: {length}") + raise ValueError(f"Length of input data is not a power of two: {length}.") nqubit = inferred_nqubit elif nqubit != inferred_nqubit: - raise ValueError(f"Mismatch between nqubit and inferred nqubit: {nqubit} != {inferred_nqubit}") + raise ValueError(f"Mismatch between nqubit and inferred nqubit: {nqubit} != {inferred_nqubit}.") psi = np.array(input_list, dtype=np.complex128) if not np.isclose(np.linalg.norm(psi), 1.0): - raise ValueError("Input state is not normalized") + raise ValueError("Input state is not normalized.") else: - raise TypeError(f"First element of data has type {type(input_list[0])} whereas Number or State is expected") + raise TypeError( + f"First element of data has type {type(input_list[0])} whereas Number or State is expected." + ) if max_qubits is not None: if max_qubits < nqubit: raise ValueError( - f"`max_qubits` can't be smaller than the length of input state: {max_qubits} < {nqubit}" + f"`max_qubits` can't be smaller than the length of input state: {max_qubits} < {nqubit}." ) else: max_qubits = nqubit @@ -234,7 +272,7 @@ def add_nodes(self, nqubit: int, data: Data) -> None: nqubit : int The number of qubits to add to the state vector. - data : Data, optional + data : Data The state in which to initialize the newly added nodes. - If a single basic state is provided, all new nodes are initialized in that state. @@ -253,26 +291,27 @@ def add_nodes(self, nqubit: int, data: Data) -> None: @override def entangle(self, qubits: tuple[int, int]) -> None: - """Connect graph nodes. + """Apply a CZ gate on two qubits. Parameters ---------- - qubits : tuple of int - (control, target) qubit indices + qubits : tuple[int, int] + (control, target) qubit indices. """ kernel = _entangle_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _entangle_jit kernel(self.psi, self.nqubit, *qubits) @override def evolve_single(self, op: Matrix, qubit: int) -> None: - """Apply a single-qubit operation. + """Apply a single-qubit operator. Parameters ---------- - op : numpy.ndarray - 2*2 matrix - q : int - qubit index + op : npt.NDArray[np.complex128] + Complex-valued matrix of shape :math:`(2, 2)` representing + the operator to apply. + qubit : int + Target qubit index. """ self._check_bounds(qubit) kernel = _evolve_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _evolve_single_jit @@ -281,18 +320,24 @@ def evolve_single(self, op: Matrix, qubit: int) -> None: @override def expectation_single(self, op: Matrix, qubit: int) -> complex: - """Return the expectation value of single-qubit operator. + """Return the expectation value of a single-qubit operator. Parameters ---------- - op : numpy.ndarray - 2*2 operator + op : npt.NDArray[np.complex128] + Complex-valued matrix of shape :math:`(2, 2)` representing + the operator to measure. qubit : int - target qubit index + Target qubit index. Returns ------- - complex : expectation value. + complex + Expectation value. + + Notes + ----- + This method assumes that quantum state stored in ``self.psi`` is normalized. See the class docstring for details. """ self._check_bounds(qubit) kernel = _expectation_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _expectation_single_jit @@ -301,14 +346,19 @@ def expectation_single(self, op: Matrix, qubit: int) -> complex: @override def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: - """Apply a multi-qubit operation. + r"""Apply a multi-qubit operator. Parameters ---------- - op : numpy.ndarray - 2^n*2^n matrix - qubits : list of int - target qubits' indices + op : npt.NDArray[np.complex128] + Complex-valued matrix of shape :math:`(2^n, 2^n)` representing + the operator to apply. + qubits : Sequence[int] + Target qubit indices. + + Notes + ----- + This method is a fallback for circuit simulation and it's not required for pattern simulation. It does not have an efficient JIT-compiled implementation. """ nq = len(qubits) # treat op as a tensor with nq output + nq input legs @@ -328,18 +378,19 @@ def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: self.psi[: self.size_valid_psi] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: - """Return the expectation value of multi-qubit operator. + """Return the expectation value of a multi-qubit operator. Parameters ---------- - op : numpy.ndarray - 2^n*2^n operator - qubits : list of int - target qubit indices + op : npt.NDArray[np.complex128] + Complex-valued matrix of shape :math:`(2^n, 2^n)` representing + the operator to measure. + qubits : Sequence[int] + Target qubit indices. - Returns - ------- - complex : expectation value + Notes + ----- + This method assumes that quantum state stored in ``self.psi`` is normalized. See the class docstring for details. """ sv = deepcopy(self) sv.evolve(op, qubits) @@ -347,9 +398,9 @@ def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: @override def remove_qubit(self, qubit: int) -> None: - r"""Remove a separable qubit from the system and assemble a statevector for remaining qubits. + r"""Remove a separable qubit from the system and assemble the statevector of the remaining qubits. - This results in the same result as partial trace, if the qubit *qarg* is separable from the rest. + This is equivalent to the partial trace if ``qubit`` corresponds to a separable qubit. For a statevector :math:`\ket{\psi} = \sum c_i \ket{i}` with sum taken over :math:`i \in [ 0 \dots 00,\ 0\dots 01,\ \dots,\ @@ -369,33 +420,32 @@ def remove_qubit(self, qubit: int) -> None: \ket{1 \dots 1_{\mathrm{k-1}}1_{\mathrm{k+1}} \dots 11}, \end{align} - (after normalization) for :math:`k =` qarg. If the :math:`k` th qubit is in :math:`\ket{1}` state, - above will return zero amplitudes; in such a case the returned state will be the one above with - :math:`0_{\mathrm{k}}` replaced with :math:`1_{\mathrm{k}}` . + (after normalization) for :math:`k =` ``qubit``. If the :math:`k` th qubit is in the :math:`\ket{1}` state, all the amplitudes above will be zero. + In that case the returned state will be the one above with + :math:`0_{\mathrm{k}}` replaced with :math:`1_{\mathrm{k}}`. .. warning:: - This method assumes the qubit with index *qarg* to be separable from the rest, + This method assumes the qubit ``qarg`` to be separable from the rest, and is implemented as a significantly faster alternative for partial trace to be used after single-qubit measurements. - Care needs to be taken when using this method. - Checks for separability will be implemented soon as an option. + Separability is not checked. Parameters ---------- qubit : int - qubit index + Target qubit index. """ self._check_bounds(qubit) self._nqubit = _remove_qubit_jit(self.psi, self.nqubit, qubit, atol=1e-10) @override def swap(self, qubits: tuple[int, int]) -> None: - """Swap qubits. + """Apply SWAP gate between two qubits. Parameters ---------- - qubits : tuple of int - (control, target) qubit indices + qubits : tuple[int, int] + (control, target) qubit indices. """ _swap_jit(self.psi, self.nqubit, *qubits) @@ -408,6 +458,10 @@ def tensor(self, other: Statevec) -> None: ---------- other : :class:`graphix.sim.statevec.Statevec` Statevector to be tensored with ``self``. + + Notes + ----- + This method is used internally by :meth:`add_nodes`. """ _tensor_jit(self.psi, other.psi, self.nqubit, other.nqubit) self._nqubit += other.nqubit @@ -417,6 +471,15 @@ def _check_bounds(self, qubit: int) -> None: This check is necessary because there is no bounds checking in Numba. See https://numba.pydata.org/numba-doc/dev/reference/pysemantics.html#bounds-checking + + Parameters + ---------- + qubit : int + Target qubit index. + + Raises + ------ + IndexError """ if not 0 <= qubit < self.nqubit: raise IndexError(f"Qubit index {qubit} out of range [0, {self.nqubit})") @@ -428,8 +491,8 @@ def fidelity(self, other: Statevec) -> float: Parameters ---------- - other : :class:`Statevec` - statevector to compare with + other : :class:`graphix.sim.statevec.Statevec` + Statevector to compare with. Returns ------- @@ -446,12 +509,12 @@ def isclose(self, other: Statevec, *, rtol: float = 1e-09, atol: float = 0.0) -> Parameters ---------- - other : :class:`Statevec` - statevector to compare with + other : :class:`graphix.sim.statevec.Statevec` + Statevector to compare with. rtol : float - relative tolerance for :func:`math.isclose` + Relative tolerance for :func:`math.isclose`. atol : float - absolute tolerance for :func:`math.isclose` + Absolute tolerance for :func:`math.isclose`. Returns ------- @@ -566,20 +629,67 @@ def _to_dict_map( @dataclass(frozen=True) class StatevectorBackend(DenseStateBackend[Statevec]): - """MBQC state vector backend simulator based on 10.48550/arXiv.2506.08142.""" + """Numba JIT-compiled MBQC statevector backend simulator based on Ref. [1]. + + See Also + -------- + graphix.sim.base_backend.DenseStateBackend + Base class describing available parameters and shared behavior. + + Notes + ----- + By default, the backend is initialized with a 0-dimensional statevector + (a scalar ``1``) and ``max_qubits = 0``. + + The internal state representation can be expanded using + ``StatevectorBackend.add_nodes``, but this is inefficient since it + requires copying the full quantum state array. + + To preallocate memory for a fixed system size, use + :meth:`StatevectorBackend.with_capacity`. + + References + ---------- + [1] McGuffin, M. J., Robert J-M., and Ikeda K. "How to Write a Simulator for Quantum Circuits from Scratch: A Tutorial.", 2025 (arXiv:2506.08142). + """ state: Statevec = dataclasses.field(init=True, default_factory=lambda: Statevec(nqubit=0)) + def __post_init__(self) -> None: + """Validate backend configuration. + + Raises + ------ + ValueError + If ``symbolic`` is ``True``, since the statevector backend + does not support symbolic simulation. + """ + if self.symbolic: + raise ValueError( + "Statevector backend does not support `symbolic` simulation. Consider using backend in `graphix-symbolic` plugin." + ) + @classmethod def with_capacity( cls, max_qubits: int, state: Statevec | None = None, **kwargs: Unpack[DenseStateBackendKwargs] ) -> Self: - """Initialize the backend with the required capacity to perform the simulation. + """Initialize the backend with preallocated statevector capacity. Parameters ---------- max_qubits : int - Number of qubits the state vector must support. For pattern simulations this corresponds to ``Pattern.max_space()``. + Maximum number of qubits supported by the statevector. For pattern simulation this corresponds to ``Pattern.max_space()``. + state: Statevec | None = None + Initial backend state. If ``None``, the backend is initialized + with a 0-dimensional statevector (scalar ``1``). + **kwargs + Options for class:`graphix.sim.base_backend.DenseStateBackend`. See + :class:`graphix.sim.base_backend.DenseStateBackendKwargs`. + + Returns + ------- + Self + Backend instance with capacity for up to ``max_qubits`` qubits. """ state_init = ( Statevec(nqubit=0, max_qubits=max_qubits) if state is None else Statevec(state, max_qubits=max_qubits) @@ -594,6 +704,10 @@ def _tensor_jit( nqubit: int, nqubit_other: int, ) -> None: + """Tensor in-place two state vectors. + + This function assumes that ``psi`` has enough capacity to contain the tensor product. + """ size_psi = 1 << nqubit size_other = 1 << nqubit_other # We update the elements of `psi` in-place. @@ -611,7 +725,10 @@ def _tensor_jit( @nb.njit("(c16[::1], int32, int32, int32)") def _swap_jit(psi: npt.NDArray[np.complex128], nqubit: int, q1: int, q2: int) -> None: + """Swap two qubits. + This function is inspired from Ref. [1]. + """ if q1 == q2: return size_sv = 1 << nqubit @@ -632,9 +749,9 @@ def _swap_jit(psi: npt.NDArray[np.complex128], nqubit: int, q1: int, q2: int) -> def _evolve_single(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, q: int) -> None: - r"""Apply a single-qubit operation. + r"""Apply a single-qubit operator. - This function is inspired from 10.48550/arXiv.2506.08142. + This function is inspired from Ref. [1]. """ nblocks = 1 << q size_block = 1 << nqubit - q # 2**(nqubit - q) @@ -663,6 +780,10 @@ def _evolve_single(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex12 def _expectation_single( psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, q: int ) -> complex: + """Compute expectation value of single-qubit operator. + + This function applies ``op`` on ``psi`` in the same way as :func:`_evolve_single`. + """ nblocks = 1 << q size_block = 1 << nqubit - q size_half_block = ( @@ -695,6 +816,10 @@ def _expectation_single( def _entangle(psi: npt.NDArray[np.complex128], nqubit: int, control: int, target: int) -> None: + """Apply CZ gate on two qubits. + + This function is inspired from Ref. [1]. + """ size_sv = 1 << nqubit mask_control = 1 << nqubit - 1 - control mask_target = 1 << nqubit - 1 - target @@ -717,6 +842,11 @@ def _remove_qubit_jit( q: int, atol: float, ) -> int: + """Remove qubit. + + Argument ``atol`` controls the tolerance below which norm of statevector is 0. + See :meth:`Statevec.remove_qubit` for additional details on the implementation. + """ new_nqubit = nqubit - 1 n_blocks = 1 << q @@ -770,7 +900,10 @@ def _remove_qubit_jit( def _format_encoding(nqubit: int, i: int, encoding: _ENCODING) -> str: - """Format the i-th basis vector as a ket. See :meth:`Statevec.to_dict` for additional details.""" + """Format the i-th basis vector as a ket. + + See :meth:`Statevec.to_dict` for additional details. + """ display_width = nqubit output = f"{i:0{display_width}b}" if encoding == "LSB": From 30da4e1b8d33e8834cddb037f74a6ef851b03dd3 Mon Sep 17 00:00:00 2001 From: matulni Date: Wed, 27 May 2026 18:05:35 +0200 Subject: [PATCH 08/25] Add cast_op function --- graphix/sim/base_backend.py | 64 ++- graphix/sim/statevec.py | 63 +- pyright_output.txt | 1072 +++++++++++++++++++++++++++++++++++ 3 files changed, 1160 insertions(+), 39 deletions(-) create mode 100644 pyright_output.txt diff --git a/graphix/sim/base_backend.py b/graphix/sim/base_backend.py index 593feb590..5fedfa181 100644 --- a/graphix/sim/base_backend.py +++ b/graphix/sim/base_backend.py @@ -364,15 +364,14 @@ def flatten(self) -> Matrix: @abstractmethod def add_nodes(self, nqubit: int, data: Data) -> None: - """ - Add nodes (qubits) to the state and initialize them in a specified state. + """Add nodes (qubits) to the state and initialize them in a specified state. Parameters ---------- nqubit : int The number of qubits to add to the state. - data : Data, optional + data : Data The state in which to initialize the newly added nodes. The supported forms of state specification depend on the backend implementation. @@ -381,24 +380,25 @@ def add_nodes(self, nqubit: int, data: Data) -> None: @abstractmethod def entangle(self, qubits: tuple[int, int]) -> None: - """Connect graph nodes. + """Apply a CZ gate on two qubits. Parameters ---------- - qubits : tuple of int - (control, target) qubit indices + qubits : tuple[int, int] + (control, target) qubit indices. """ @abstractmethod - def evolve(self, op: Matrix, qargs: Sequence[int]) -> None: - """Apply a multi-qubit operation. + def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: + """Apply a multi-qubit operator. Parameters ---------- - op : numpy.ndarray - 2^n*2^n matrix - qargs : list of int - target qubits' indices + op : Matrix + Matrix of shape :math:`(2^n, 2^n)` representing + the operator to apply. + qubits : Sequence[int] + Target qubit indices. """ @abstractmethod @@ -407,40 +407,50 @@ def evolve_single(self, op: Matrix, qubit: int) -> None: Parameters ---------- - op : numpy.ndarray - 2*2 matrix + op : Matrix + Matrix of shape :math:`(2, 2)` representing + the operator to apply. qubit : int - qubit index + Target qubit index. """ @abstractmethod - def expectation_single(self, op: Matrix, loc: int) -> complex: - """Return the expectation value of single-qubit operator. + def expectation_single(self, op: Matrix, qubit: int) -> complex: + """Return the expectation value of a single-qubit operator. Parameters ---------- - op : numpy.ndarray - 2*2 operator - loc : int - target qubit index + op : Matrix + Matrix of shape :math:`(2, 2)` representing + the operator to measure. + qubit : int + Target qubit index. Returns ------- - complex : expectation value. + complex + Expectation value. + """ @abstractmethod - def remove_qubit(self, qarg: int) -> None: - """Remove a separable qubit from the system.""" + def remove_qubit(self, qubit: int) -> None: + """Remove a separable qubit from the system. + + Parameters + ---------- + qubit : int + Target qubit index. + """ @abstractmethod def swap(self, qubits: tuple[int, int]) -> None: - """Swap qubits. + """Apply SWAP gate between two qubits. Parameters ---------- - qubits : tuple of int - (control, target) qubit indices + qubits : tuple[int, int] + (control, target) qubit indices. """ def apply_noise(self, qubits: Sequence[int], noise: Noise) -> None: # noqa: ARG002 diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 3d2397c9e..3c6b6ccfc 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -297,7 +297,16 @@ def entangle(self, qubits: tuple[int, int]) -> None: ---------- qubits : tuple[int, int] (control, target) qubit indices. + + Notes + ----- + The JIT kernel switches to a parallel implementation when the + number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ + # `_entangle_jit` is not unsafe if calle on out-of-bound indices but + # we check them for robustness. + for qubit in qubits: + self._check_bounds(qubit) kernel = _entangle_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _entangle_jit kernel(self.psi, self.nqubit, *qubits) @@ -312,11 +321,17 @@ def evolve_single(self, op: Matrix, qubit: int) -> None: the operator to apply. qubit : int Target qubit index. + + Notes + ----- + The JIT kernel switches to a parallel implementation when the + number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ self._check_bounds(qubit) kernel = _evolve_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _evolve_single_jit - # We cast to np.complex128 to match numba signature. - kernel(self.psi, op.astype(np.complex128), self.nqubit, qubit) + # Downcast from Matrix to np.complex128 to match numba signature. + op_as_complex = _cast_op(op) + kernel(self.psi, op_as_complex, self.nqubit, qubit) @override def expectation_single(self, op: Matrix, qubit: int) -> complex: @@ -337,12 +352,16 @@ def expectation_single(self, op: Matrix, qubit: int) -> complex: Notes ----- - This method assumes that quantum state stored in ``self.psi`` is normalized. See the class docstring for details. + - This method assumes that quantum state stored in ``self.psi`` is normalized. See the class docstring for details. + + - The JIT kernel switches to a parallel implementation when the + number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ self._check_bounds(qubit) kernel = _expectation_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _expectation_single_jit - # We cast to np.complex128 to match numba signature. - return kernel(self.psi, op.astype(np.complex128), self.nqubit, qubit) + # Downcast from Matrix to np.complex128 to match numba signature. + op_as_complex = _cast_op(op) + return kernel(self.psi, op_as_complex, self.nqubit, qubit) @override def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: @@ -358,7 +377,9 @@ def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: Notes ----- - This method is a fallback for circuit simulation and it's not required for pattern simulation. It does not have an efficient JIT-compiled implementation. + This method is a fallback for circuit simulation and it's not required + for pattern simulation. It does not have an efficient JIT-compiled + implementation. """ nq = len(qubits) # treat op as a tensor with nq output + nq input legs @@ -390,7 +411,8 @@ def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: Notes ----- - This method assumes that quantum state stored in ``self.psi`` is normalized. See the class docstring for details. + This method assumes that quantum state stored in ``self.psi`` is normalized. + See the class docstring for details. """ sv = deepcopy(self) sv.evolve(op, qubits) @@ -482,7 +504,7 @@ def _check_bounds(self, qubit: int) -> None: IndexError """ if not 0 <= qubit < self.nqubit: - raise IndexError(f"Qubit index {qubit} out of range [0, {self.nqubit})") + raise IndexError(f"Qubit index {qubit} out of range [0, {self.nqubit} -1]") def fidelity(self, other: Statevec) -> float: r"""Calculate the fidelity against another statevector. @@ -771,8 +793,8 @@ def _evolve_single(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex12 psi[i2] = op[1, 0] * psi1 + op[1, 1] * psi2 -_evolve_single_jit: EvolveSingleJit = nb.njit("(c16[::1], c16[:, :], int32, int32)", parallel=False)(_evolve_single) -_evolve_single_jit_parallel: EvolveSingleJit = nb.njit("(c16[::1], c16[:, :], int32, int32)", parallel=True)( +_evolve_single_jit: EvolveSingleJit = nb.njit("(c16[::1], c16[:,:], int32, int32)", parallel=False)(_evolve_single) +_evolve_single_jit_parallel: EvolveSingleJit = nb.njit("(c16[::1], c16[:,:], int32, int32)", parallel=True)( _evolve_single ) @@ -807,11 +829,11 @@ def _expectation_single( return result -_expectation_single_jit: ExpectationSingleJit = nb.njit("c16(c16[::1], c16[:, :], int32, int32)", parallel=False)( +_expectation_single_jit: ExpectationSingleJit = nb.njit("c16(c16[::1], c16[:,:], int32, int32)", parallel=False)( _expectation_single ) _expectation_single_jit_parallel: ExpectationSingleJit = nb.njit( - "c16(c16[::1], c16[:, :], int32, int32)", parallel=True + "c16(c16[::1], c16[:,:], int32, int32)", parallel=True )(_expectation_single) @@ -909,3 +931,20 @@ def _format_encoding(nqubit: int, i: int, encoding: _ENCODING) -> str: if encoding == "LSB": return output[::-1] return output + + +def _cast_op(op: Matrix) -> npt.NDArray[np.complex128]: + if op.dtype == np.object_: + raise TypeError( + "Statevector backend does not support symbolic operators. Consider using backend in `graphix-symbolic` plugin." + ) + # By default, the numba signature c16[:,:] assumes a writeable array. + # Arrays obtained from, e.g., `graphix.clifford.Clifford.H.matrix` or + # `graphix.ops.Ops.X` are not writtable and therefore do not match the + # numba signature. + # Since ``op`` is a 2-by-2 matrix it's probably not worth it to dispatch + # multiple jit kernels (with the appropriate numba signature) + # depending on its WRITEABLE flag to avoid copying. + # https://github.com/numba/numba/issues/4511#issuecomment-527350694 + # https://numba.pydata.org/numba-doc/0.17.0/reference/types.html#numba.types.Array + return op.astype(np.complex128, copy=True) diff --git a/pyright_output.txt b/pyright_output.txt new file mode 100644 index 000000000..2bf456a0b --- /dev/null +++ b/pyright_output.txt @@ -0,0 +1,1072 @@ +/Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:21:29 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:23:29 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:24:30 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:27:30 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:28:30 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:29:30 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/circ_ext/extraction.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/circ_ext/extraction.py:609:5 - information: Type of "measurements" is partially unknown +   Type of "measurements" is "dict[int, Unknown]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:122:5 - information: Type of "s_domain" is partially unknown +   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:123:5 - information: Type of "t_domain" is partially unknown +   Type of "t_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:208:5 - information: Type of "domain" is partially unknown +   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:225:5 - information: Type of "domain" is partially unknown +   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:242:5 - information: Type of "domain" is partially unknown +   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:54:48 - information: Type of "graphs_equal" is partially unknown +   Type of "graphs_equal" is "(graph1: Unknown, graph2: Unknown) -> bool" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:93:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:96:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:9 - information: Type of "v" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:12 - information: Type of "_" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:24 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "sorted" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:102:13 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:103:47 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:105:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:56 - information: Argument type is partially unknown +   Argument corresponds to parameter "node_ids" in function "create_resource_graph" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:68 - information: Argument type is unknown +   Argument corresponds to parameter "root" in function "create_resource_graph" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:125:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:127:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:129:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:142:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:144:12 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1339:5 - information: Type of "ordered_nodes" is partially unknown +   Type of "ordered_nodes" is "frozenset[Unknown | int]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1339:21 - information: Type of "union" is partially unknown +   Type of "union" is "(self: frozenset[Unknown], *s: Iterable[_S@union]) -> frozenset[Unknown | _S@union]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1366:5 - information: Type of "image" is partially unknown +   Type of "image" is "set[Unknown | int]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:116:9 - information: Type of "g_new" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:116:32 - information: Type of "complement" is partially unknown +   Type of "complement" is "_dispatchable[(G: Graph[_Node@complement, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:118:29 - information: Type of "edges" is partially unknown +   Type of "edges" is "Unknown | EdgeView[int, dict[str, Any], dict[str, Any]] | OutEdgeView[int, dict[str, Any], dict[str, Any]]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:118:29 - information: Argument type is partially unknown +   Argument corresponds to parameter "ebunch_to_add" in function "add_edges_from" +   Argument type is "Unknown | EdgeView[int, dict[str, Any], dict[str, Any]] | OutEdgeView[int, dict[str, Any], dict[str, Any]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:517:21 - information: Type of "isolates" is partially unknown +   Type of "isolates" is "_dispatchable[(G: Graph[_Node@isolates, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:517:21 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:321:13 - information: Type of "graphs_equal" is partially unknown +   Type of "graphs_equal" is "(graph1: Unknown, graph2: Unknown) -> bool" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:506:16 - information: Type of "try_from_correction_matrix" is partially unknown +   Type of "try_from_correction_matrix" is "(correction_matrix: CorrectionMatrix[Unknown]) -> (GFlow[Unknown] | None)" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:506:16 - information: Return type, "GFlow[Unknown] | None", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:559:16 - information: Type of "try_from_correction_matrix" is partially unknown +   Type of "try_from_correction_matrix" is "(correction_matrix: CorrectionMatrix[Unknown]) -> (PauliFlow[Unknown] | None)" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:559:16 - information: Return type, "PauliFlow[Unknown] | None", is partially unknown (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/ops.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/ops.py:31:69 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:454:16 - information: Type of "from_measured_nodes_mapping" is partially unknown +   Type of "from_measured_nodes_mapping" is "(og: OpenGraph[Unknown], x_corrections: Mapping[int, AbstractSet[int]] | None = None, z_corrections: Mapping[int, AbstractSet[int]] | None = None) -> XZCorrections[Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:454:16 - information: Return type, "XZCorrections[Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:602:21 - information: Type of "new_s_domain" is partially unknown +   Type of "new_s_domain" is "set[Unknown] | set[int]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:603:21 - information: Type of "new_t_domain" is partially unknown +   Type of "new_t_domain" is "set[Unknown] | set[int]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:345:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:347:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:349:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:350:37 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:607:33 - information: Type of "t_domain" is partially unknown +   Type of "t_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:617:33 - information: Type of "s_domain" is partially unknown +   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:623:29 - information: Type of "s_domain" is partially unknown +   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:836:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:838:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:9 - information: Type of "sort" is partially unknown +   Type of "sort" is "Overload[(*, key: None = None, reverse: bool = False) -> None, (*, key: (Unknown) -> (SupportsDunderLT[Any] | SupportsDunderGT[Any]), reverse: bool = False) -> None]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:32 - information: Type of parameter "n_cmd" is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:39 - information: Type of "node" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:39 - information: Return type of lambda is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:920:16 - information: Return type, "dict[Unknown, Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1192:25 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1194:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1197:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1206:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1207:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1296:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1299:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1300:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1564:9 - information: Type of "measured" is partially unknown +   Type of "measured" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1603:21 - information: Type of "add" is partially unknown +   Type of "add" is "(element: Unknown, /) -> None" (reportUnknownMemberType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:175:33 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:187:29 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:191:29 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:193:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:203:51 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:208:49 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:210:21 - information: Type of "arguments" is partially unknown +   Type of "arguments" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:212:25 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:214:45 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:14:6 - error: Import "pyzx.graph" could not be resolved (reportMissingImports) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:14:24 - information: Type of "Graph" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:6 - error: Import "pyzx.utils" could not be resolved (reportMissingImports) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:24 - information: Type of "EdgeType" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:34 - information: Type of "FractionLike" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:48 - information: Type of "VertexType" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:22:10 - error: Import "pyzx.graph.base" could not be resolved (reportMissingImports) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:22:33 - information: Type of "BaseGraph" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:34:5 - information: Return type is unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:48:5 - information: Type of "g" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:51:9 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:51:30 - information: Type of parameter "ty" is unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:52:9 - information: Type of "verts" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:52:17 - information: Type of "add_vertices" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:53:13 - information: Type of "vert" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:54:13 - information: Type of "set_type" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:56:16 - information: Return type is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:5 - information: Type of "in_verts" is partially unknown +   Type of "in_verts" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:50 - information: Type of "BOUNDARY" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:50 - information: Argument type is unknown +   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:60:5 - information: Type of "set_inputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:60:24 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:5 - information: Type of "body_verts" is partially unknown +   Type of "body_verts" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:46 - information: Type of "Z" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:46 - information: Argument type is unknown +   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:5 - information: Type of "x_meas_verts" is partially unknown +   Type of "x_meas_verts" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:46 - information: Type of "Z" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:46 - information: Argument type is unknown +   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:5 - information: Type of "out_verts" is partially unknown +   Type of "out_verts" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:52 - information: Type of "BOUNDARY" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:52 - information: Argument type is unknown +   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:72:5 - information: Type of "set_outputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:72:25 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:5 - information: Type of "map_to_og" is partially unknown +   Type of "map_to_og" is "dict[Unknown, int]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:22 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__init__" +   Argument type is "zip[tuple[Unknown, int]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "iter1" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:77:5 - information: Type of "map_to_pyzx" is partially unknown +   Type of "map_to_pyzx" is "dict[int, Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:77:29 - information: Type of "i" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:82:9 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:82:37 - information: Argument type is partially unknown +   Argument corresponds to parameter "iter1" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:83:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:84:9 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:84:37 - information: Argument type is partially unknown +   Argument corresponds to parameter "iter1" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:85:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:88:5 - information: Type of "pyzx_edges" is partially unknown +   Type of "pyzx_edges" is "Generator[tuple[Unknown, Unknown], None, None]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:89:5 - information: Type of "add_edges" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:89:29 - information: Type of "HADAMARD" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:95:13 - information: Type of "set_phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:98:19 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:98:45 - information: Argument type is partially unknown +   Argument corresponds to parameter "iter2" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:99:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:99:57 - information: Type of "HADAMARD" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:100:9 - information: Type of "set_phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:102:12 - information: Return type is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:105:20 - information: Type of parameter "x" is unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:112:21 - information: Type of parameter "g" is unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:5 - information: Type of "simplify" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:5 - information: Type of "to_graph_like" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:8 - error: "simplify" is not a known attribute of module "pyzx" (reportAttributeAccessIssue) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:5 - information: Type of "inputs" is partially unknown +   Type of "inputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:19 - information: Type of "inputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:19 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:5 - information: Type of "outputs" is partially unknown +   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:20 - information: Type of "outputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:20 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:5 - information: Type of "g_nx" is partially unknown +   Type of "g_nx" is "Graph[Unknown, Unknown, Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:21 - information: Type of "edges" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:21 - information: Argument type is unknown +   Argument corresponds to parameter "incoming_graph_data" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:138:9 - information: Type of "inp" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:138:16 - information: Type of "inputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:9 - information: Type of "first_nbr" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "i" in function "next" +   Argument type is "SupportsNext[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:31 - information: Type of "neighbors" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:31 - information: Argument type is unknown +   Argument corresponds to parameter "object" in function "iter" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:140:9 - information: Type of "et" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:140:14 - information: Type of "edge_type" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:142:18 - information: Type of "SIMPLE" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:143:13 - information: Type of "remove_node" is partially unknown +   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:143:30 - information: Argument type is unknown +   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:144:13 - information: Type of "inputs" is partially unknown +   Type of "inputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:144:56 - information: Type of "i" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:146:9 - information: Type of "out" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:146:16 - information: Type of "outputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:9 - information: Type of "first_nbr" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "i" in function "next" +   Argument type is "SupportsNext[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:31 - information: Type of "neighbors" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:31 - information: Argument type is unknown +   Argument corresponds to parameter "object" in function "iter" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:148:9 - information: Type of "et" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:148:14 - information: Type of "edge_type" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:150:18 - information: Type of "SIMPLE" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:151:13 - information: Type of "remove_node" is partially unknown +   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:151:30 - information: Argument type is unknown +   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:152:13 - information: Type of "outputs" is partially unknown +   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:152:57 - information: Type of "o" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:5 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:18 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:18 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__init__" +   Argument type is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:158:9 - information: Type of "v" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:9 - information: Type of "nbrs" is partially unknown +   Type of "nbrs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:21 - information: Type of "neighbors" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:21 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:163:16 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:164:67 - information: Type of "phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:164:67 - information: Argument type is unknown +   Argument corresponds to parameter "x" in function "_checked_float" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:165:13 - information: Type of "remove_node" is partially unknown +   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:165:30 - information: Argument type is unknown +   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:5 - information: Type of "next_id" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:19 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:19 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "max" +   Argument type is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:171:9 - information: Type of "out" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:172:12 - information: Type of "phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:175:9 - information: Type of "add_edges_from" is partially unknown +   Type of "add_edges_from" is "(ebunch_to_add: Iterable[tuple[Unknown, Unknown] | tuple[Unknown, Unknown, Unknown]], **attr: Any) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:178:9 - information: Type of "outputs" is partially unknown +   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:178:55 - information: Type of "o" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:179:9 - information: Type of "next_id" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:182:9 - information: Type of "v" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:182:14 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:188:58 - information: Type of "phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:188:58 - information: Argument type is unknown +   Argument corresponds to parameter "x" in function "_checked_float" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:22 - information: Argument type is partially unknown +   Argument corresponds to parameter "graph" in function "__init__" +   Argument type is "Graph[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:28 - information: Argument type is partially unknown +   Argument corresponds to parameter "input_nodes" in function "__init__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:36 - information: Argument type is partially unknown +   Argument corresponds to parameter "output_nodes" in function "__init__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:152:5 - information: Type of "kraus_list" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:152:62 - information: Argument type is unknown +   Argument corresponds to parameter "a" in function "inv" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:154:52 - information: Argument type is unknown +   Argument corresponds to parameter "operator" in function "__init__" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:13 - information: Type of "node" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:26 - information: Type of "isolates" is partially unknown +   Type of "isolates" is "_dispatchable[(G: Graph[_Node@isolates, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:26 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:502:35 - information: Argument type is unknown +   Argument corresponds to parameter "u" in function "_remove_node" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:42:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:44:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:45:35 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:183:9 - error: Method "evolve" overrides class "DenseState" in an incompatible manner +   Parameter 3 name mismatch: base parameter is named "qargs", override parameter is named "qubits" (reportIncompatibleMethodOverride) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:231:9 - error: Method "expectation_single" overrides class "DenseState" in an incompatible manner +   Parameter 3 name mismatch: base parameter is named "loc", override parameter is named "qubit" (reportIncompatibleMethodOverride) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:322:9 - error: Method "remove_qubit" overrides class "DenseState" in an incompatible manner +   Parameter 2 name mismatch: base parameter is named "qarg", override parameter is named "qubit" (reportIncompatibleMethodOverride) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:35 - information: Argument type is partially unknown +   Argument corresponds to parameter "pyfunc" in function "__init__" +   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:42 - information: Type of parameter "value" is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:49 - information: Return type of lambda is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:64 - information: Argument type is unknown +   Argument corresponds to parameter "value" in function "subs" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:35 - information: Argument type is partially unknown +   Argument corresponds to parameter "pyfunc" in function "__init__" +   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:42 - information: Type of parameter "value" is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:49 - information: Return type of lambda is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:68 - information: Argument type is unknown +   Argument corresponds to parameter "value" in function "xreplace" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:151:34 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:151:73 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:155:13 - information: Type of "input_list" is partially unknown +   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:157:13 - information: Type of "input_list" is partially unknown +   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:161:16 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:168:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:17 - information: Type of parameter "s" is partially unknown +   Parameter type is "State | Unknown | Iterable[Unknown]" (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:28 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:67 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:183:46 - information: Type of "s" is partially unknown +   Type of "s" is "State | Unknown | Iterable[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:188:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:202:56 - information: Argument type is partially unknown +   Argument corresponds to parameter "o" in function "__init__" +   Argument type is "Unknown | Iterable[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:337:9 - error: Method "expectation_single" overrides class "DenseState" in an incompatible manner +   Parameter 3 name mismatch: base parameter is named "loc", override parameter is named "qubit" (reportIncompatibleMethodOverride) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:367:9 - error: Method "evolve" overrides class "DenseState" in an incompatible manner +   Parameter 3 name mismatch: base parameter is named "qargs", override parameter is named "qubits" (reportIncompatibleMethodOverride) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:43 - error: No overloads for "einsum" match the provided arguments (reportCallIssue) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:43 - information: Type of "reshape" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:53 - error: Argument of type "ndarray[tuple[int, ...], dtype[complex128]]" cannot be assigned to parameter "subscripts" of type "_ArrayLikeInt_co | str" in function "einsum" +   Type "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to type "_ArrayLikeInt_co | str" +     "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to "str" +     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]" +       "__array__" is an incompatible type +         No overloaded function matches type "() -> ndarray[Any, _DTypeT_co@_SupportsArray]" +     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_NestedSequence[_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]]" +       "__reversed__" is not present +       "count" is not present + ... (reportArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:422:9 - error: Method "remove_qubit" overrides class "DenseState" in an incompatible manner +   Parameter 2 name mismatch: base parameter is named "qarg", override parameter is named "qubit" (reportIncompatibleMethodOverride) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:401:9 - information: Type of "statevec" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:402:28 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:404:16 - information: Return type, "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:404:42 - information: Argument type is partially unknown +   Argument corresponds to parameter "x" in function "norm" +   Argument type is "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:234:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:238:49 - information: Argument type is partially unknown +   Argument corresponds to parameter "new_order" in function "__init__" +   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:238:55 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:495:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:501:41 - information: Argument type is partially unknown +   Argument corresponds to parameter "classical_outputs" in function "__init__" +   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:501:47 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1025:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1028:46 - information: Argument type is partially unknown +   Argument corresponds to parameter "classical_measures" in function "__init__" +   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1028:52 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/utils.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/utils.py:72:5 - information: Type of "m" is partially unknown +   Type of "m" is "ndarray[tuple[Any, ...], dtype[Unknown]]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:310:9 - information: Type of "figure" is partially unknown +   Type of "figure" is "(num: int | str | Figure | SubFigure | None = None, figsize: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, dpi: float | None = None, *, facecolor: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, edgecolor: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, frameon: bool = True, FigureClass: type[Figure] = Figure, clear: bool = False, **kwargs: Unknown) -> Figure" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:333:13 - information: Type of "show" is partially unknown +   Type of "show" is "(...) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:335:13 - information: Type of "savefig" is partially unknown +   Type of "savefig" is "(...) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:379:9 - information: Type of "xlim" is partially unknown +   Type of "xlim" is "(...) -> tuple[float, float]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:380:9 - information: Type of "ylim" is partially unknown +   Type of "ylim" is "(...) -> tuple[float, float]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:412:13 - information: Type of "scatter" is partially unknown +   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:427:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:443:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:444:17 - information: Type of "annotate" is partially unknown +   Type of "annotate" is "(text: str, xy: tuple[float, float], xytext: tuple[float, float] | None = None, xycoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] = "data", textcoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] | None = None, arrowprops: dict[str, Any] | None = None, annotation_clip: bool | None = None, **kwargs: Unknown) -> Annotation" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:486:13 - information: Type of "axvline" is partially unknown +   Type of "axvline" is "(x: float = 0, ymin: float = 0, ymax: float = 1, **kwargs: Unknown) -> Line2D" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:493:13 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:505:9 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:519:13 - information: Type of "annotate" is partially unknown +   Type of "annotate" is "(text: str, xy: tuple[float, float], xytext: tuple[float, float] | None = None, xycoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] = "data", textcoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] | None = None, arrowprops: dict[str, Any] | None = None, annotation_clip: bool | None = None, **kwargs: Unknown) -> Annotation" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:530:9 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:552:13 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:559:13 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:566:9 - information: Type of "scatter" is partially unknown +   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:576:9 - information: Type of "scatter" is partially unknown +   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:587:13 - information: Type of "scatter" is partially unknown +   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:597:9 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:602:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:604:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:605:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:606:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:612:9 - information: Type of "legend" is partially unknown +   Type of "legend" is "(...) -> Legend" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:771:5 - information: Type of "values_union" is partially unknown +   Type of "values_union" is "set[Unknown | int]" (reportUnknownVariableType) +16 errors, 0 warnings, 266 informations +/Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:21:29 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:23:29 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:24:30 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:27:30 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:28:30 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:29:30 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/circ_ext/extraction.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/circ_ext/extraction.py:609:5 - information: Type of "measurements" is partially unknown +   Type of "measurements" is "dict[int, Unknown]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:122:5 - information: Type of "s_domain" is partially unknown +   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:123:5 - information: Type of "t_domain" is partially unknown +   Type of "t_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:208:5 - information: Type of "domain" is partially unknown +   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:225:5 - information: Type of "domain" is partially unknown +   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:242:5 - information: Type of "domain" is partially unknown +   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:54:48 - information: Type of "graphs_equal" is partially unknown +   Type of "graphs_equal" is "(graph1: Unknown, graph2: Unknown) -> bool" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:93:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:96:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:9 - information: Type of "v" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:12 - information: Type of "_" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:24 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "sorted" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:102:13 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:103:47 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:105:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:56 - information: Argument type is partially unknown +   Argument corresponds to parameter "node_ids" in function "create_resource_graph" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:68 - information: Argument type is unknown +   Argument corresponds to parameter "root" in function "create_resource_graph" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:125:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:127:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:129:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:142:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:144:12 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1339:5 - information: Type of "ordered_nodes" is partially unknown +   Type of "ordered_nodes" is "frozenset[Unknown | int]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1339:21 - information: Type of "union" is partially unknown +   Type of "union" is "(self: frozenset[Unknown], *s: Iterable[_S@union]) -> frozenset[Unknown | _S@union]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1366:5 - information: Type of "image" is partially unknown +   Type of "image" is "set[Unknown | int]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:116:9 - information: Type of "g_new" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:116:32 - information: Type of "complement" is partially unknown +   Type of "complement" is "_dispatchable[(G: Graph[_Node@complement, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:118:29 - information: Type of "edges" is partially unknown +   Type of "edges" is "Unknown | EdgeView[int, dict[str, Any], dict[str, Any]] | OutEdgeView[int, dict[str, Any], dict[str, Any]]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:118:29 - information: Argument type is partially unknown +   Argument corresponds to parameter "ebunch_to_add" in function "add_edges_from" +   Argument type is "Unknown | EdgeView[int, dict[str, Any], dict[str, Any]] | OutEdgeView[int, dict[str, Any], dict[str, Any]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:517:21 - information: Type of "isolates" is partially unknown +   Type of "isolates" is "_dispatchable[(G: Graph[_Node@isolates, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:517:21 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:321:13 - information: Type of "graphs_equal" is partially unknown +   Type of "graphs_equal" is "(graph1: Unknown, graph2: Unknown) -> bool" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:506:16 - information: Type of "try_from_correction_matrix" is partially unknown +   Type of "try_from_correction_matrix" is "(correction_matrix: CorrectionMatrix[Unknown]) -> (GFlow[Unknown] | None)" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:506:16 - information: Return type, "GFlow[Unknown] | None", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:559:16 - information: Type of "try_from_correction_matrix" is partially unknown +   Type of "try_from_correction_matrix" is "(correction_matrix: CorrectionMatrix[Unknown]) -> (PauliFlow[Unknown] | None)" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:559:16 - information: Return type, "PauliFlow[Unknown] | None", is partially unknown (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/ops.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/ops.py:31:69 - information: Argument type is partially unknown +   Argument corresponds to parameter "a" in function "asarray" +   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:454:16 - information: Type of "from_measured_nodes_mapping" is partially unknown +   Type of "from_measured_nodes_mapping" is "(og: OpenGraph[Unknown], x_corrections: Mapping[int, AbstractSet[int]] | None = None, z_corrections: Mapping[int, AbstractSet[int]] | None = None) -> XZCorrections[Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:454:16 - information: Return type, "XZCorrections[Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:602:21 - information: Type of "new_s_domain" is partially unknown +   Type of "new_s_domain" is "set[Unknown] | set[int]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:603:21 - information: Type of "new_t_domain" is partially unknown +   Type of "new_t_domain" is "set[Unknown] | set[int]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:345:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:347:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:349:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:350:37 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:607:33 - information: Type of "t_domain" is partially unknown +   Type of "t_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:617:33 - information: Type of "s_domain" is partially unknown +   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:623:29 - information: Type of "s_domain" is partially unknown +   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:836:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:838:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:9 - information: Type of "sort" is partially unknown +   Type of "sort" is "Overload[(*, key: None = None, reverse: bool = False) -> None, (*, key: (Unknown) -> (SupportsDunderLT[Any] | SupportsDunderGT[Any]), reverse: bool = False) -> None]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:32 - information: Type of parameter "n_cmd" is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:39 - information: Type of "node" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:39 - information: Return type of lambda is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:920:16 - information: Return type, "dict[Unknown, Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1192:25 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1194:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1197:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1206:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1207:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1296:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1299:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1300:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1564:9 - information: Type of "measured" is partially unknown +   Type of "measured" is "set[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1603:21 - information: Type of "add" is partially unknown +   Type of "add" is "(element: Unknown, /) -> None" (reportUnknownMemberType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:175:33 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:187:29 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:191:29 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:193:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:203:51 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:208:49 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:210:21 - information: Type of "arguments" is partially unknown +   Type of "arguments" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:212:25 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:214:45 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:14:6 - error: Import "pyzx.graph" could not be resolved (reportMissingImports) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:14:24 - information: Type of "Graph" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:6 - error: Import "pyzx.utils" could not be resolved (reportMissingImports) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:24 - information: Type of "EdgeType" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:34 - information: Type of "FractionLike" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:48 - information: Type of "VertexType" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:22:10 - error: Import "pyzx.graph.base" could not be resolved (reportMissingImports) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:22:33 - information: Type of "BaseGraph" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:34:5 - information: Return type is unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:48:5 - information: Type of "g" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:51:9 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:51:30 - information: Type of parameter "ty" is unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:52:9 - information: Type of "verts" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:52:17 - information: Type of "add_vertices" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:53:13 - information: Type of "vert" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:54:13 - information: Type of "set_type" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:56:16 - information: Return type is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:5 - information: Type of "in_verts" is partially unknown +   Type of "in_verts" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:50 - information: Type of "BOUNDARY" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:50 - information: Argument type is unknown +   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:60:5 - information: Type of "set_inputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:60:24 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:5 - information: Type of "body_verts" is partially unknown +   Type of "body_verts" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:46 - information: Type of "Z" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:46 - information: Argument type is unknown +   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:5 - information: Type of "x_meas_verts" is partially unknown +   Type of "x_meas_verts" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:46 - information: Type of "Z" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:46 - information: Argument type is unknown +   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:5 - information: Type of "out_verts" is partially unknown +   Type of "out_verts" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:52 - information: Type of "BOUNDARY" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:52 - information: Argument type is unknown +   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:72:5 - information: Type of "set_outputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:72:25 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:5 - information: Type of "map_to_og" is partially unknown +   Type of "map_to_og" is "dict[Unknown, int]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:22 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__init__" +   Argument type is "zip[tuple[Unknown, int]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "iter1" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:77:5 - information: Type of "map_to_pyzx" is partially unknown +   Type of "map_to_pyzx" is "dict[int, Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:77:29 - information: Type of "i" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:82:9 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:82:37 - information: Argument type is partially unknown +   Argument corresponds to parameter "iter1" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:83:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:84:9 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:84:37 - information: Argument type is partially unknown +   Argument corresponds to parameter "iter1" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:85:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:88:5 - information: Type of "pyzx_edges" is partially unknown +   Type of "pyzx_edges" is "Generator[tuple[Unknown, Unknown], None, None]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:89:5 - information: Type of "add_edges" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:89:29 - information: Type of "HADAMARD" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:95:13 - information: Type of "set_phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:98:19 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:98:45 - information: Argument type is partially unknown +   Argument corresponds to parameter "iter2" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:99:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:99:57 - information: Type of "HADAMARD" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:100:9 - information: Type of "set_phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:102:12 - information: Return type is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:105:20 - information: Type of parameter "x" is unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:112:21 - information: Type of parameter "g" is unknown (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:5 - information: Type of "simplify" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:5 - information: Type of "to_graph_like" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:8 - error: "simplify" is not a known attribute of module "pyzx" (reportAttributeAccessIssue) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:5 - information: Type of "inputs" is partially unknown +   Type of "inputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:19 - information: Type of "inputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:19 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:5 - information: Type of "outputs" is partially unknown +   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:20 - information: Type of "outputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:20 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:5 - information: Type of "g_nx" is partially unknown +   Type of "g_nx" is "Graph[Unknown, Unknown, Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:21 - information: Type of "edges" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:21 - information: Argument type is unknown +   Argument corresponds to parameter "incoming_graph_data" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:138:9 - information: Type of "inp" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:138:16 - information: Type of "inputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:9 - information: Type of "first_nbr" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "i" in function "next" +   Argument type is "SupportsNext[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:31 - information: Type of "neighbors" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:31 - information: Argument type is unknown +   Argument corresponds to parameter "object" in function "iter" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:140:9 - information: Type of "et" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:140:14 - information: Type of "edge_type" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:142:18 - information: Type of "SIMPLE" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:143:13 - information: Type of "remove_node" is partially unknown +   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:143:30 - information: Argument type is unknown +   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:144:13 - information: Type of "inputs" is partially unknown +   Type of "inputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:144:56 - information: Type of "i" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:146:9 - information: Type of "out" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:146:16 - information: Type of "outputs" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:9 - information: Type of "first_nbr" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "i" in function "next" +   Argument type is "SupportsNext[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:31 - information: Type of "neighbors" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:31 - information: Argument type is unknown +   Argument corresponds to parameter "object" in function "iter" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:148:9 - information: Type of "et" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:148:14 - information: Type of "edge_type" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:150:18 - information: Type of "SIMPLE" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:151:13 - information: Type of "remove_node" is partially unknown +   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:151:30 - information: Argument type is unknown +   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:152:13 - information: Type of "outputs" is partially unknown +   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:152:57 - information: Type of "o" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:5 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:18 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:18 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__init__" +   Argument type is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:158:9 - information: Type of "v" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:9 - information: Type of "nbrs" is partially unknown +   Type of "nbrs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:21 - information: Type of "neighbors" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:21 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:163:16 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:164:67 - information: Type of "phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:164:67 - information: Argument type is unknown +   Argument corresponds to parameter "x" in function "_checked_float" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:165:13 - information: Type of "remove_node" is partially unknown +   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:165:30 - information: Argument type is unknown +   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:5 - information: Type of "next_id" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:19 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:19 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "max" +   Argument type is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:171:9 - information: Type of "out" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:172:12 - information: Type of "phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:175:9 - information: Type of "add_edges_from" is partially unknown +   Type of "add_edges_from" is "(ebunch_to_add: Iterable[tuple[Unknown, Unknown] | tuple[Unknown, Unknown, Unknown]], **attr: Any) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:178:9 - information: Type of "outputs" is partially unknown +   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:178:55 - information: Type of "o" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:179:9 - information: Type of "next_id" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:182:9 - information: Type of "v" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:182:14 - information: Type of "nodes" is partially unknown +   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:188:58 - information: Type of "phase" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:188:58 - information: Argument type is unknown +   Argument corresponds to parameter "x" in function "_checked_float" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:22 - information: Argument type is partially unknown +   Argument corresponds to parameter "graph" in function "__init__" +   Argument type is "Graph[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:28 - information: Argument type is partially unknown +   Argument corresponds to parameter "input_nodes" in function "__init__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:36 - information: Argument type is partially unknown +   Argument corresponds to parameter "output_nodes" in function "__init__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:152:5 - information: Type of "kraus_list" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:152:62 - information: Argument type is unknown +   Argument corresponds to parameter "a" in function "inv" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:154:52 - information: Argument type is unknown +   Argument corresponds to parameter "operator" in function "__init__" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:13 - information: Type of "node" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:26 - information: Type of "isolates" is partially unknown +   Type of "isolates" is "_dispatchable[(G: Graph[_Node@isolates, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:26 - information: Argument type is unknown +   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:502:35 - information: Argument type is unknown +   Argument corresponds to parameter "u" in function "_remove_node" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:42:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:44:17 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:45:35 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "join" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:35 - information: Argument type is partially unknown +   Argument corresponds to parameter "pyfunc" in function "__init__" +   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:42 - information: Type of parameter "value" is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:49 - information: Return type of lambda is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:64 - information: Argument type is unknown +   Argument corresponds to parameter "value" in function "subs" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:35 - information: Argument type is partially unknown +   Argument corresponds to parameter "pyfunc" in function "__init__" +   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:42 - information: Type of parameter "value" is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:49 - information: Return type of lambda is unknown (reportUnknownLambdaType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:68 - information: Argument type is unknown +   Argument corresponds to parameter "value" in function "xreplace" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:151:34 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:151:73 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:155:13 - information: Type of "input_list" is partially unknown +   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:157:13 - information: Type of "input_list" is partially unknown +   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:161:16 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:168:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:17 - information: Type of parameter "s" is partially unknown +   Parameter type is "State | Unknown | Iterable[Unknown]" (reportUnknownParameterType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:28 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:67 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:183:46 - information: Type of "s" is partially unknown +   Type of "s" is "State | Unknown | Iterable[Unknown]" (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:188:26 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:202:56 - information: Argument type is partially unknown +   Argument corresponds to parameter "o" in function "__init__" +   Argument type is "Unknown | Iterable[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:43 - error: No overloads for "einsum" match the provided arguments (reportCallIssue) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:43 - information: Type of "reshape" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:53 - error: Argument of type "ndarray[tuple[int, ...], dtype[complex128]]" cannot be assigned to parameter "subscripts" of type "_ArrayLikeInt_co | str" in function "einsum" +   Type "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to type "_ArrayLikeInt_co | str" +     "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to "str" +     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]" +       "__array__" is an incompatible type +         No overloaded function matches type "() -> ndarray[Any, _DTypeT_co@_SupportsArray]" +     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_NestedSequence[_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]]" +       "__reversed__" is not present +       "count" is not present + ... (reportArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:401:9 - information: Type of "statevec" is unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:402:28 - information: Argument type is partially unknown +   Argument corresponds to parameter "obj" in function "len" +   Argument type is "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:404:16 - information: Return type, "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]", is partially unknown (reportUnknownVariableType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:404:42 - information: Argument type is partially unknown +   Argument corresponds to parameter "x" in function "norm" +   Argument type is "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:234:13 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:238:49 - information: Argument type is partially unknown +   Argument corresponds to parameter "new_order" in function "__init__" +   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:238:55 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:495:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:501:41 - information: Argument type is partially unknown +   Argument corresponds to parameter "classical_outputs" in function "__init__" +   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:501:47 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1025:21 - information: Type of "append" is partially unknown +   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1028:46 - information: Argument type is partially unknown +   Argument corresponds to parameter "classical_measures" in function "__init__" +   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1028:52 - information: Argument type is partially unknown +   Argument corresponds to parameter "iterable" in function "__new__" +   Argument type is "list[Unknown]" (reportUnknownArgumentType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/utils.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/utils.py:72:5 - information: Type of "m" is partially unknown +   Type of "m" is "ndarray[tuple[Any, ...], dtype[Unknown]]" (reportUnknownVariableType) +/Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:310:9 - information: Type of "figure" is partially unknown +   Type of "figure" is "(num: int | str | Figure | SubFigure | None = None, figsize: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, dpi: float | None = None, *, facecolor: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, edgecolor: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, frameon: bool = True, FigureClass: type[Figure] = Figure, clear: bool = False, **kwargs: Unknown) -> Figure" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:333:13 - information: Type of "show" is partially unknown +   Type of "show" is "(...) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:335:13 - information: Type of "savefig" is partially unknown +   Type of "savefig" is "(...) -> None" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:379:9 - information: Type of "xlim" is partially unknown +   Type of "xlim" is "(...) -> tuple[float, float]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:380:9 - information: Type of "ylim" is partially unknown +   Type of "ylim" is "(...) -> tuple[float, float]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:412:13 - information: Type of "scatter" is partially unknown +   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:427:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:443:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:444:17 - information: Type of "annotate" is partially unknown +   Type of "annotate" is "(text: str, xy: tuple[float, float], xytext: tuple[float, float] | None = None, xycoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] = "data", textcoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] | None = None, arrowprops: dict[str, Any] | None = None, annotation_clip: bool | None = None, **kwargs: Unknown) -> Annotation" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:486:13 - information: Type of "axvline" is partially unknown +   Type of "axvline" is "(x: float = 0, ymin: float = 0, ymax: float = 1, **kwargs: Unknown) -> Line2D" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:493:13 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:505:9 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:519:13 - information: Type of "annotate" is partially unknown +   Type of "annotate" is "(text: str, xy: tuple[float, float], xytext: tuple[float, float] | None = None, xycoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] = "data", textcoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] | None = None, arrowprops: dict[str, Any] | None = None, annotation_clip: bool | None = None, **kwargs: Unknown) -> Annotation" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:530:9 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:552:13 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:559:13 - information: Type of "text" is partially unknown +   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:566:9 - information: Type of "scatter" is partially unknown +   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:576:9 - information: Type of "scatter" is partially unknown +   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:587:13 - information: Type of "scatter" is partially unknown +   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:597:9 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:602:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:604:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:605:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:606:17 - information: Type of "plot" is partially unknown +   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:612:9 - information: Type of "legend" is partially unknown +   Type of "legend" is "(...) -> Legend" (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:771:5 - information: Type of "values_union" is partially unknown +   Type of "values_union" is "set[Unknown | int]" (reportUnknownVariableType) +10 errors, 0 warnings, 266 informations From f443d58cf13f9f3c6083da9fb6b4acdd0acadc0b Mon Sep 17 00:00:00 2001 From: matulni Date: Wed, 27 May 2026 18:19:16 +0200 Subject: [PATCH 09/25] Fixing pyright --- graphix/sim/statevec.py | 13 +- pyright_output.txt | 572 ++-------------------------------------- 2 files changed, 22 insertions(+), 563 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 3c6b6ccfc..7400eeefe 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -18,9 +18,10 @@ import numpy.typing as npt from typing_extensions import override +from graphix import states from graphix.parameter import ExpressionOrSupportsComplex from graphix.sim.base_backend import DenseState, DenseStateBackend, DenseStateBackendKwargs, Matrix -from graphix.states import BasicStates, State +from graphix.states import BasicStates if TYPE_CHECKING: from collections.abc import Callable, Sequence @@ -148,8 +149,8 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max # list[states.State] | list[ExpressionOrSupportsComplex] | list[Iterable[ExpressionOrSupportsComplex]] # would be more precise, but given a value X of type Iterable[A] | Iterable[B], # mypy infers that list(X) has type list[A | B] instead of list[A] | list[B]. - input_list: list[State | ExpressionOrSupportsComplex | Iterable[ExpressionOrSupportsComplex]] - if isinstance(data, State): + input_list: list[states.State | ExpressionOrSupportsComplex | Iterable[ExpressionOrSupportsComplex]] + if isinstance(data, states.State): if nqubit is None: nqubit = 1 input_list = [data] * nqubit @@ -164,7 +165,7 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max nqubit = 0 psi = np.array([1], dtype=np.complex128) - elif isinstance(input_list[0], State): + elif isinstance(input_list[0], states.State): length = len(input_list) if nqubit is None: nqubit = length @@ -172,9 +173,9 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max raise ValueError(f"Mismatch between nqubit and length of input state: {nqubit} != {length}.") def state_to_statevector( - s: State | ExpressionOrSupportsComplex | Iterable[ExpressionOrSupportsComplex], + s: states.State | ExpressionOrSupportsComplex | Iterable[ExpressionOrSupportsComplex], ) -> npt.NDArray[np.complex128]: - if not isinstance(s, State): + if not isinstance(s, states.State): raise TypeError("Data should be an homogeneous sequence of states.") return s.to_statevector() diff --git a/pyright_output.txt b/pyright_output.txt index 2bf456a0b..dedfbd25a 100644 --- a/pyright_output.txt +++ b/pyright_output.txt @@ -385,12 +385,6 @@   Argument corresponds to parameter "iterable" in function "join"   Argument type is "list[Unknown]" (reportUnknownArgumentType) /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:183:9 - error: Method "evolve" overrides class "DenseState" in an incompatible manner -   Parameter 3 name mismatch: base parameter is named "qargs", override parameter is named "qubits" (reportIncompatibleMethodOverride) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:231:9 - error: Method "expectation_single" overrides class "DenseState" in an incompatible manner -   Parameter 3 name mismatch: base parameter is named "loc", override parameter is named "qubit" (reportIncompatibleMethodOverride) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:322:9 - error: Method "remove_qubit" overrides class "DenseState" in an incompatible manner -   Parameter 2 name mismatch: base parameter is named "qarg", override parameter is named "qubit" (reportIncompatibleMethodOverride) /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:35 - information: Argument type is partially unknown   Argument corresponds to parameter "pyfunc" in function "__init__"   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) @@ -406,569 +400,33 @@ /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:68 - information: Argument type is unknown   Argument corresponds to parameter "value" in function "xreplace" (reportUnknownArgumentType) /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:151:34 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:151:73 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:155:13 - information: Type of "input_list" is partially unknown + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:152:41 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:152:80 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:156:13 - information: Type of "input_list" is partially unknown   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:157:13 - information: Type of "input_list" is partially unknown + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:158:13 - information: Type of "input_list" is partially unknown   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:161:16 - information: Argument type is partially unknown + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:162:16 - information: Argument type is partially unknown   Argument corresponds to parameter "obj" in function "len"   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:168:26 - information: Argument type is partially unknown + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:169:26 - information: Argument type is partially unknown   Argument corresponds to parameter "obj" in function "len"   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:17 - information: Type of parameter "s" is partially unknown + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:176:17 - information: Type of parameter "s" is partially unknown   Parameter type is "State | Unknown | Iterable[Unknown]" (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:28 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:67 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:183:46 - information: Type of "s" is partially unknown + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:176:35 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:176:74 - error: Variable not allowed in type expression (reportInvalidTypeForm) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:184:46 - information: Type of "s" is partially unknown   Type of "s" is "State | Unknown | Iterable[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:188:26 - information: Argument type is partially unknown + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:189:26 - information: Argument type is partially unknown   Argument corresponds to parameter "obj" in function "len"   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:202:56 - information: Argument type is partially unknown + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:203:56 - information: Argument type is partially unknown   Argument corresponds to parameter "o" in function "__init__"   Argument type is "Unknown | Iterable[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:337:9 - error: Method "expectation_single" overrides class "DenseState" in an incompatible manner -   Parameter 3 name mismatch: base parameter is named "loc", override parameter is named "qubit" (reportIncompatibleMethodOverride) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:367:9 - error: Method "evolve" overrides class "DenseState" in an incompatible manner -   Parameter 3 name mismatch: base parameter is named "qargs", override parameter is named "qubits" (reportIncompatibleMethodOverride) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:43 - error: No overloads for "einsum" match the provided arguments (reportCallIssue) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:43 - information: Type of "reshape" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:53 - error: Argument of type "ndarray[tuple[int, ...], dtype[complex128]]" cannot be assigned to parameter "subscripts" of type "_ArrayLikeInt_co | str" in function "einsum" -   Type "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to type "_ArrayLikeInt_co | str" -     "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to "str" -     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]" -       "__array__" is an incompatible type -         No overloaded function matches type "() -> ndarray[Any, _DTypeT_co@_SupportsArray]" -     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_NestedSequence[_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]]" -       "__reversed__" is not present -       "count" is not present - ... (reportArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:422:9 - error: Method "remove_qubit" overrides class "DenseState" in an incompatible manner -   Parameter 2 name mismatch: base parameter is named "qarg", override parameter is named "qubit" (reportIncompatibleMethodOverride) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:401:9 - information: Type of "statevec" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:402:28 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:404:16 - information: Return type, "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:404:42 - information: Argument type is partially unknown -   Argument corresponds to parameter "x" in function "norm" -   Argument type is "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:234:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:238:49 - information: Argument type is partially unknown -   Argument corresponds to parameter "new_order" in function "__init__" -   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:238:55 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:495:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:501:41 - information: Argument type is partially unknown -   Argument corresponds to parameter "classical_outputs" in function "__init__" -   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:501:47 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1025:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1028:46 - information: Argument type is partially unknown -   Argument corresponds to parameter "classical_measures" in function "__init__" -   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1028:52 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/utils.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/utils.py:72:5 - information: Type of "m" is partially unknown -   Type of "m" is "ndarray[tuple[Any, ...], dtype[Unknown]]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:310:9 - information: Type of "figure" is partially unknown -   Type of "figure" is "(num: int | str | Figure | SubFigure | None = None, figsize: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, dpi: float | None = None, *, facecolor: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, edgecolor: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, frameon: bool = True, FigureClass: type[Figure] = Figure, clear: bool = False, **kwargs: Unknown) -> Figure" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:333:13 - information: Type of "show" is partially unknown -   Type of "show" is "(...) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:335:13 - information: Type of "savefig" is partially unknown -   Type of "savefig" is "(...) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:379:9 - information: Type of "xlim" is partially unknown -   Type of "xlim" is "(...) -> tuple[float, float]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:380:9 - information: Type of "ylim" is partially unknown -   Type of "ylim" is "(...) -> tuple[float, float]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:412:13 - information: Type of "scatter" is partially unknown -   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:427:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:443:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:444:17 - information: Type of "annotate" is partially unknown -   Type of "annotate" is "(text: str, xy: tuple[float, float], xytext: tuple[float, float] | None = None, xycoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] = "data", textcoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] | None = None, arrowprops: dict[str, Any] | None = None, annotation_clip: bool | None = None, **kwargs: Unknown) -> Annotation" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:486:13 - information: Type of "axvline" is partially unknown -   Type of "axvline" is "(x: float = 0, ymin: float = 0, ymax: float = 1, **kwargs: Unknown) -> Line2D" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:493:13 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:505:9 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:519:13 - information: Type of "annotate" is partially unknown -   Type of "annotate" is "(text: str, xy: tuple[float, float], xytext: tuple[float, float] | None = None, xycoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] = "data", textcoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] | None = None, arrowprops: dict[str, Any] | None = None, annotation_clip: bool | None = None, **kwargs: Unknown) -> Annotation" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:530:9 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:552:13 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:559:13 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:566:9 - information: Type of "scatter" is partially unknown -   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:576:9 - information: Type of "scatter" is partially unknown -   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:587:13 - information: Type of "scatter" is partially unknown -   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:597:9 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:602:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:604:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:605:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:606:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:612:9 - information: Type of "legend" is partially unknown -   Type of "legend" is "(...) -> Legend" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:771:5 - information: Type of "values_union" is partially unknown -   Type of "values_union" is "set[Unknown | int]" (reportUnknownVariableType) -16 errors, 0 warnings, 266 informations -/Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:21:29 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:23:29 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:24:30 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:27:30 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:28:30 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:29:30 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/circ_ext/extraction.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/circ_ext/extraction.py:609:5 - information: Type of "measurements" is partially unknown -   Type of "measurements" is "dict[int, Unknown]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:122:5 - information: Type of "s_domain" is partially unknown -   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:123:5 - information: Type of "t_domain" is partially unknown -   Type of "t_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:208:5 - information: Type of "domain" is partially unknown -   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:225:5 - information: Type of "domain" is partially unknown -   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:242:5 - information: Type of "domain" is partially unknown -   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:54:48 - information: Type of "graphs_equal" is partially unknown -   Type of "graphs_equal" is "(graph1: Unknown, graph2: Unknown) -> bool" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:93:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:96:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:9 - information: Type of "v" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:12 - information: Type of "_" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:24 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "sorted" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:102:13 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:103:47 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:105:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:56 - information: Argument type is partially unknown -   Argument corresponds to parameter "node_ids" in function "create_resource_graph" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:68 - information: Argument type is unknown -   Argument corresponds to parameter "root" in function "create_resource_graph" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:125:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:127:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:129:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:142:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:144:12 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1339:5 - information: Type of "ordered_nodes" is partially unknown -   Type of "ordered_nodes" is "frozenset[Unknown | int]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1339:21 - information: Type of "union" is partially unknown -   Type of "union" is "(self: frozenset[Unknown], *s: Iterable[_S@union]) -> frozenset[Unknown | _S@union]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1366:5 - information: Type of "image" is partially unknown -   Type of "image" is "set[Unknown | int]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:116:9 - information: Type of "g_new" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:116:32 - information: Type of "complement" is partially unknown -   Type of "complement" is "_dispatchable[(G: Graph[_Node@complement, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:118:29 - information: Type of "edges" is partially unknown -   Type of "edges" is "Unknown | EdgeView[int, dict[str, Any], dict[str, Any]] | OutEdgeView[int, dict[str, Any], dict[str, Any]]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:118:29 - information: Argument type is partially unknown -   Argument corresponds to parameter "ebunch_to_add" in function "add_edges_from" -   Argument type is "Unknown | EdgeView[int, dict[str, Any], dict[str, Any]] | OutEdgeView[int, dict[str, Any], dict[str, Any]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:517:21 - information: Type of "isolates" is partially unknown -   Type of "isolates" is "_dispatchable[(G: Graph[_Node@isolates, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:517:21 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:321:13 - information: Type of "graphs_equal" is partially unknown -   Type of "graphs_equal" is "(graph1: Unknown, graph2: Unknown) -> bool" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:506:16 - information: Type of "try_from_correction_matrix" is partially unknown -   Type of "try_from_correction_matrix" is "(correction_matrix: CorrectionMatrix[Unknown]) -> (GFlow[Unknown] | None)" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:506:16 - information: Return type, "GFlow[Unknown] | None", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:559:16 - information: Type of "try_from_correction_matrix" is partially unknown -   Type of "try_from_correction_matrix" is "(correction_matrix: CorrectionMatrix[Unknown]) -> (PauliFlow[Unknown] | None)" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:559:16 - information: Return type, "PauliFlow[Unknown] | None", is partially unknown (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/ops.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/ops.py:31:69 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:454:16 - information: Type of "from_measured_nodes_mapping" is partially unknown -   Type of "from_measured_nodes_mapping" is "(og: OpenGraph[Unknown], x_corrections: Mapping[int, AbstractSet[int]] | None = None, z_corrections: Mapping[int, AbstractSet[int]] | None = None) -> XZCorrections[Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:454:16 - information: Return type, "XZCorrections[Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:602:21 - information: Type of "new_s_domain" is partially unknown -   Type of "new_s_domain" is "set[Unknown] | set[int]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:603:21 - information: Type of "new_t_domain" is partially unknown -   Type of "new_t_domain" is "set[Unknown] | set[int]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:345:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:347:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:349:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:350:37 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:607:33 - information: Type of "t_domain" is partially unknown -   Type of "t_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:617:33 - information: Type of "s_domain" is partially unknown -   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:623:29 - information: Type of "s_domain" is partially unknown -   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:836:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:838:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:9 - information: Type of "sort" is partially unknown -   Type of "sort" is "Overload[(*, key: None = None, reverse: bool = False) -> None, (*, key: (Unknown) -> (SupportsDunderLT[Any] | SupportsDunderGT[Any]), reverse: bool = False) -> None]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:32 - information: Type of parameter "n_cmd" is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:39 - information: Type of "node" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:39 - information: Return type of lambda is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:920:16 - information: Return type, "dict[Unknown, Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1192:25 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1194:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1197:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1206:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1207:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1296:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1299:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1300:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1564:9 - information: Type of "measured" is partially unknown -   Type of "measured" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1603:21 - information: Type of "add" is partially unknown -   Type of "add" is "(element: Unknown, /) -> None" (reportUnknownMemberType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:175:33 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:187:29 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:191:29 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:193:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:203:51 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:208:49 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:210:21 - information: Type of "arguments" is partially unknown -   Type of "arguments" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:212:25 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:214:45 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:14:6 - error: Import "pyzx.graph" could not be resolved (reportMissingImports) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:14:24 - information: Type of "Graph" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:6 - error: Import "pyzx.utils" could not be resolved (reportMissingImports) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:24 - information: Type of "EdgeType" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:34 - information: Type of "FractionLike" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:48 - information: Type of "VertexType" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:22:10 - error: Import "pyzx.graph.base" could not be resolved (reportMissingImports) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:22:33 - information: Type of "BaseGraph" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:34:5 - information: Return type is unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:48:5 - information: Type of "g" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:51:9 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:51:30 - information: Type of parameter "ty" is unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:52:9 - information: Type of "verts" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:52:17 - information: Type of "add_vertices" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:53:13 - information: Type of "vert" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:54:13 - information: Type of "set_type" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:56:16 - information: Return type is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:5 - information: Type of "in_verts" is partially unknown -   Type of "in_verts" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:50 - information: Type of "BOUNDARY" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:50 - information: Argument type is unknown -   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:60:5 - information: Type of "set_inputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:60:24 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:5 - information: Type of "body_verts" is partially unknown -   Type of "body_verts" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:46 - information: Type of "Z" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:46 - information: Argument type is unknown -   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:5 - information: Type of "x_meas_verts" is partially unknown -   Type of "x_meas_verts" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:46 - information: Type of "Z" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:46 - information: Argument type is unknown -   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:5 - information: Type of "out_verts" is partially unknown -   Type of "out_verts" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:52 - information: Type of "BOUNDARY" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:52 - information: Argument type is unknown -   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:72:5 - information: Type of "set_outputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:72:25 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:5 - information: Type of "map_to_og" is partially unknown -   Type of "map_to_og" is "dict[Unknown, int]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:22 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__init__" -   Argument type is "zip[tuple[Unknown, int]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "iter1" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:77:5 - information: Type of "map_to_pyzx" is partially unknown -   Type of "map_to_pyzx" is "dict[int, Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:77:29 - information: Type of "i" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:82:9 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:82:37 - information: Argument type is partially unknown -   Argument corresponds to parameter "iter1" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:83:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:84:9 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:84:37 - information: Argument type is partially unknown -   Argument corresponds to parameter "iter1" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:85:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:88:5 - information: Type of "pyzx_edges" is partially unknown -   Type of "pyzx_edges" is "Generator[tuple[Unknown, Unknown], None, None]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:89:5 - information: Type of "add_edges" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:89:29 - information: Type of "HADAMARD" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:95:13 - information: Type of "set_phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:98:19 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:98:45 - information: Argument type is partially unknown -   Argument corresponds to parameter "iter2" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:99:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:99:57 - information: Type of "HADAMARD" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:100:9 - information: Type of "set_phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:102:12 - information: Return type is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:105:20 - information: Type of parameter "x" is unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:112:21 - information: Type of parameter "g" is unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:5 - information: Type of "simplify" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:5 - information: Type of "to_graph_like" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:8 - error: "simplify" is not a known attribute of module "pyzx" (reportAttributeAccessIssue) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:5 - information: Type of "inputs" is partially unknown -   Type of "inputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:19 - information: Type of "inputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:19 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:5 - information: Type of "outputs" is partially unknown -   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:20 - information: Type of "outputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:20 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:5 - information: Type of "g_nx" is partially unknown -   Type of "g_nx" is "Graph[Unknown, Unknown, Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:21 - information: Type of "edges" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:21 - information: Argument type is unknown -   Argument corresponds to parameter "incoming_graph_data" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:138:9 - information: Type of "inp" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:138:16 - information: Type of "inputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:9 - information: Type of "first_nbr" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "i" in function "next" -   Argument type is "SupportsNext[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:31 - information: Type of "neighbors" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:31 - information: Argument type is unknown -   Argument corresponds to parameter "object" in function "iter" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:140:9 - information: Type of "et" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:140:14 - information: Type of "edge_type" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:142:18 - information: Type of "SIMPLE" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:143:13 - information: Type of "remove_node" is partially unknown -   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:143:30 - information: Argument type is unknown -   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:144:13 - information: Type of "inputs" is partially unknown -   Type of "inputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:144:56 - information: Type of "i" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:146:9 - information: Type of "out" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:146:16 - information: Type of "outputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:9 - information: Type of "first_nbr" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "i" in function "next" -   Argument type is "SupportsNext[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:31 - information: Type of "neighbors" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:31 - information: Argument type is unknown -   Argument corresponds to parameter "object" in function "iter" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:148:9 - information: Type of "et" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:148:14 - information: Type of "edge_type" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:150:18 - information: Type of "SIMPLE" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:151:13 - information: Type of "remove_node" is partially unknown -   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:151:30 - information: Argument type is unknown -   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:152:13 - information: Type of "outputs" is partially unknown -   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:152:57 - information: Type of "o" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:5 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:18 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:18 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__init__" -   Argument type is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:158:9 - information: Type of "v" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:9 - information: Type of "nbrs" is partially unknown -   Type of "nbrs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:21 - information: Type of "neighbors" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:21 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:163:16 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:164:67 - information: Type of "phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:164:67 - information: Argument type is unknown -   Argument corresponds to parameter "x" in function "_checked_float" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:165:13 - information: Type of "remove_node" is partially unknown -   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:165:30 - information: Argument type is unknown -   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:5 - information: Type of "next_id" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:19 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:19 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "max" -   Argument type is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:171:9 - information: Type of "out" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:172:12 - information: Type of "phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:175:9 - information: Type of "add_edges_from" is partially unknown -   Type of "add_edges_from" is "(ebunch_to_add: Iterable[tuple[Unknown, Unknown] | tuple[Unknown, Unknown, Unknown]], **attr: Any) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:178:9 - information: Type of "outputs" is partially unknown -   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:178:55 - information: Type of "o" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:179:9 - information: Type of "next_id" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:182:9 - information: Type of "v" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:182:14 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:188:58 - information: Type of "phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:188:58 - information: Argument type is unknown -   Argument corresponds to parameter "x" in function "_checked_float" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:22 - information: Argument type is partially unknown -   Argument corresponds to parameter "graph" in function "__init__" -   Argument type is "Graph[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:28 - information: Argument type is partially unknown -   Argument corresponds to parameter "input_nodes" in function "__init__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:36 - information: Argument type is partially unknown -   Argument corresponds to parameter "output_nodes" in function "__init__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:152:5 - information: Type of "kraus_list" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:152:62 - information: Argument type is unknown -   Argument corresponds to parameter "a" in function "inv" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:154:52 - information: Argument type is unknown -   Argument corresponds to parameter "operator" in function "__init__" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:13 - information: Type of "node" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:26 - information: Type of "isolates" is partially unknown -   Type of "isolates" is "_dispatchable[(G: Graph[_Node@isolates, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:26 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:502:35 - information: Argument type is unknown -   Argument corresponds to parameter "u" in function "_remove_node" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:42:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:44:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:45:35 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:35 - information: Argument type is partially unknown -   Argument corresponds to parameter "pyfunc" in function "__init__" -   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:42 - information: Type of parameter "value" is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:49 - information: Return type of lambda is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:64 - information: Argument type is unknown -   Argument corresponds to parameter "value" in function "subs" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:35 - information: Argument type is partially unknown -   Argument corresponds to parameter "pyfunc" in function "__init__" -   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:42 - information: Type of parameter "value" is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:49 - information: Return type of lambda is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:68 - information: Argument type is unknown -   Argument corresponds to parameter "value" in function "xreplace" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:151:34 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:151:73 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:155:13 - information: Type of "input_list" is partially unknown -   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:157:13 - information: Type of "input_list" is partially unknown -   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:161:16 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:168:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:17 - information: Type of parameter "s" is partially unknown -   Parameter type is "State | Unknown | Iterable[Unknown]" (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:28 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:175:67 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:183:46 - information: Type of "s" is partially unknown -   Type of "s" is "State | Unknown | Iterable[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:188:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:202:56 - information: Argument type is partially unknown -   Argument corresponds to parameter "o" in function "__init__" -   Argument type is "Unknown | Iterable[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:43 - error: No overloads for "einsum" match the provided arguments (reportCallIssue) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:43 - information: Type of "reshape" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:399:53 - error: Argument of type "ndarray[tuple[int, ...], dtype[complex128]]" cannot be assigned to parameter "subscripts" of type "_ArrayLikeInt_co | str" in function "einsum" + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:400:43 - error: No overloads for "einsum" match the provided arguments (reportCallIssue) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:400:43 - information: Type of "reshape" is unknown (reportUnknownMemberType) + /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:400:53 - error: Argument of type "ndarray[tuple[int, ...], dtype[complex128]]" cannot be assigned to parameter "subscripts" of type "_ArrayLikeInt_co | str" in function "einsum"   Type "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to type "_ArrayLikeInt_co | str"     "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to "str"     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]" From e36db0dadab52c5b30d002fd8f02b8104e58184a Mon Sep 17 00:00:00 2001 From: matulni Date: Wed, 27 May 2026 18:32:31 +0200 Subject: [PATCH 10/25] Fix typing issues --- graphix/sim/statevec.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 7400eeefe..c20640939 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -19,7 +19,6 @@ from typing_extensions import override from graphix import states -from graphix.parameter import ExpressionOrSupportsComplex from graphix.sim.base_backend import DenseState, DenseStateBackend, DenseStateBackendKwargs, Matrix from graphix.states import BasicStates @@ -30,13 +29,12 @@ # Unpack introduced in Python 3.12 from typing_extensions import Unpack + from graphix.parameter import ExpressionOrSupportsComplex from graphix.sim.data import Data _ENCODING = Literal["LSB", "MSB"] _ScalarT = TypeVar("_ScalarT", bound=np.generic[Any]) - from graphix.parameter import ExpressionOrSupportsComplex - EvolveSingleJit: TypeAlias = Callable[ [npt.NDArray[np.complex128], npt.NDArray[np.complex128], int, int], None ] # type introduced in 3.12 @@ -397,7 +395,7 @@ def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: for i, s in enumerate(qubits): res_idx[s] = out_idx[i] - self.psi[: self.size_valid_psi] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) + self.psi[: self.size_valid_psi] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) # type: ignore[arg-type] # https://github.com/numpy/numpy/issues/31513 def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: """Return the expectation value of a multi-qubit operator. From 23064452da5cbec27349ea047c32bb307df7e10e Mon Sep 17 00:00:00 2001 From: matulni Date: Thu, 28 May 2026 09:01:27 +0200 Subject: [PATCH 11/25] Remove dummy file --- pyright_output.txt | 530 --------------------------------------------- 1 file changed, 530 deletions(-) delete mode 100644 pyright_output.txt diff --git a/pyright_output.txt b/pyright_output.txt deleted file mode 100644 index dedfbd25a..000000000 --- a/pyright_output.txt +++ /dev/null @@ -1,530 +0,0 @@ -/Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:21:29 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:23:29 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:24:30 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:27:30 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:28:30 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/_db.py:29:30 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/circ_ext/extraction.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/circ_ext/extraction.py:609:5 - information: Type of "measurements" is partially unknown -   Type of "measurements" is "dict[int, Unknown]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:122:5 - information: Type of "s_domain" is partially unknown -   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:123:5 - information: Type of "t_domain" is partially unknown -   Type of "t_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:208:5 - information: Type of "domain" is partially unknown -   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:225:5 - information: Type of "domain" is partially unknown -   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/command.py:242:5 - information: Type of "domain" is partially unknown -   Type of "domain" is "set[Unknown]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:54:48 - information: Type of "graphs_equal" is partially unknown -   Type of "graphs_equal" is "(graph1: Unknown, graph2: Unknown) -> bool" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:93:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:96:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:9 - information: Type of "v" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:12 - information: Type of "_" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:100:24 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "sorted" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:102:13 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:103:47 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:105:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:56 - information: Argument type is partially unknown -   Argument corresponds to parameter "node_ids" in function "create_resource_graph" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:108:68 - information: Argument type is unknown -   Argument corresponds to parameter "root" in function "create_resource_graph" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:125:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:127:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:129:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:142:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/extraction.py:144:12 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1339:5 - information: Type of "ordered_nodes" is partially unknown -   Type of "ordered_nodes" is "frozenset[Unknown | int]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1339:21 - information: Type of "union" is partially unknown -   Type of "union" is "(self: frozenset[Unknown], *s: Iterable[_S@union]) -> frozenset[Unknown | _S@union]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/flow/core.py:1366:5 - information: Type of "image" is partially unknown -   Type of "image" is "set[Unknown | int]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:116:9 - information: Type of "g_new" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:116:32 - information: Type of "complement" is partially unknown -   Type of "complement" is "_dispatchable[(G: Graph[_Node@complement, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:118:29 - information: Type of "edges" is partially unknown -   Type of "edges" is "Unknown | EdgeView[int, dict[str, Any], dict[str, Any]] | OutEdgeView[int, dict[str, Any], dict[str, Any]]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:118:29 - information: Argument type is partially unknown -   Argument corresponds to parameter "ebunch_to_add" in function "add_edges_from" -   Argument type is "Unknown | EdgeView[int, dict[str, Any], dict[str, Any]] | OutEdgeView[int, dict[str, Any], dict[str, Any]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:517:21 - information: Type of "isolates" is partially unknown -   Type of "isolates" is "_dispatchable[(G: Graph[_Node@isolates, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/graphsim.py:517:21 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:321:13 - information: Type of "graphs_equal" is partially unknown -   Type of "graphs_equal" is "(graph1: Unknown, graph2: Unknown) -> bool" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:506:16 - information: Type of "try_from_correction_matrix" is partially unknown -   Type of "try_from_correction_matrix" is "(correction_matrix: CorrectionMatrix[Unknown]) -> (GFlow[Unknown] | None)" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:506:16 - information: Return type, "GFlow[Unknown] | None", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:559:16 - information: Type of "try_from_correction_matrix" is partially unknown -   Type of "try_from_correction_matrix" is "(correction_matrix: CorrectionMatrix[Unknown]) -> (PauliFlow[Unknown] | None)" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/opengraph.py:559:16 - information: Return type, "PauliFlow[Unknown] | None", is partially unknown (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/ops.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/ops.py:31:69 - information: Argument type is partially unknown -   Argument corresponds to parameter "a" in function "asarray" -   Argument type is "list[list[Unknown]]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:454:16 - information: Type of "from_measured_nodes_mapping" is partially unknown -   Type of "from_measured_nodes_mapping" is "(og: OpenGraph[Unknown], x_corrections: Mapping[int, AbstractSet[int]] | None = None, z_corrections: Mapping[int, AbstractSet[int]] | None = None) -> XZCorrections[Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:454:16 - information: Return type, "XZCorrections[Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:602:21 - information: Type of "new_s_domain" is partially unknown -   Type of "new_s_domain" is "set[Unknown] | set[int]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/optimization.py:603:21 - information: Type of "new_t_domain" is partially unknown -   Type of "new_t_domain" is "set[Unknown] | set[int]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:345:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:347:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:349:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:350:37 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:607:33 - information: Type of "t_domain" is partially unknown -   Type of "t_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:617:33 - information: Type of "s_domain" is partially unknown -   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:623:29 - information: Type of "s_domain" is partially unknown -   Type of "s_domain" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:836:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:838:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:9 - information: Type of "sort" is partially unknown -   Type of "sort" is "Overload[(*, key: None = None, reverse: bool = False) -> None, (*, key: (Unknown) -> (SupportsDunderLT[Any] | SupportsDunderGT[Any]), reverse: bool = False) -> None]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:32 - information: Type of parameter "n_cmd" is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:39 - information: Type of "node" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:839:39 - information: Return type of lambda is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:920:16 - information: Return type, "dict[Unknown, Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1192:25 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1194:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1197:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1206:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1207:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1296:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1299:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1300:16 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1564:9 - information: Type of "measured" is partially unknown -   Type of "measured" is "set[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pattern.py:1603:21 - information: Type of "add" is partially unknown -   Type of "add" is "(element: Unknown, /) -> None" (reportUnknownMemberType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:175:33 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:187:29 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:191:29 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:193:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:203:51 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:208:49 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:210:21 - information: Type of "arguments" is partially unknown -   Type of "arguments" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:212:25 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pretty_print.py:214:45 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:14:6 - error: Import "pyzx.graph" could not be resolved (reportMissingImports) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:14:24 - information: Type of "Graph" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:6 - error: Import "pyzx.utils" could not be resolved (reportMissingImports) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:24 - information: Type of "EdgeType" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:34 - information: Type of "FractionLike" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:15:48 - information: Type of "VertexType" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:22:10 - error: Import "pyzx.graph.base" could not be resolved (reportMissingImports) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:22:33 - information: Type of "BaseGraph" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:34:5 - information: Return type is unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:48:5 - information: Type of "g" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:51:9 - information: Return type, "list[Unknown]", is partially unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:51:30 - information: Type of parameter "ty" is unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:52:9 - information: Type of "verts" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:52:17 - information: Type of "add_vertices" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:53:13 - information: Type of "vert" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:54:13 - information: Type of "set_type" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:56:16 - information: Return type is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:5 - information: Type of "in_verts" is partially unknown -   Type of "in_verts" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:50 - information: Type of "BOUNDARY" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:59:50 - information: Argument type is unknown -   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:60:5 - information: Type of "set_inputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:60:24 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:5 - information: Type of "body_verts" is partially unknown -   Type of "body_verts" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:46 - information: Type of "Z" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:63:46 - information: Argument type is unknown -   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:5 - information: Type of "x_meas_verts" is partially unknown -   Type of "x_meas_verts" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:46 - information: Type of "Z" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:69:46 - information: Argument type is unknown -   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:5 - information: Type of "out_verts" is partially unknown -   Type of "out_verts" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:52 - information: Type of "BOUNDARY" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:71:52 - information: Argument type is unknown -   Argument corresponds to parameter "ty" in function "add_vertices" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:72:5 - information: Type of "set_outputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:72:25 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:5 - information: Type of "map_to_og" is partially unknown -   Type of "map_to_og" is "dict[Unknown, int]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:22 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__init__" -   Argument type is "zip[tuple[Unknown, int]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:76:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "iter1" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:77:5 - information: Type of "map_to_pyzx" is partially unknown -   Type of "map_to_pyzx" is "dict[int, Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:77:29 - information: Type of "i" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:82:9 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:82:37 - information: Argument type is partially unknown -   Argument corresponds to parameter "iter1" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:83:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:84:9 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:84:37 - information: Argument type is partially unknown -   Argument corresponds to parameter "iter1" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:85:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:88:5 - information: Type of "pyzx_edges" is partially unknown -   Type of "pyzx_edges" is "Generator[tuple[Unknown, Unknown], None, None]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:89:5 - information: Type of "add_edges" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:89:29 - information: Type of "HADAMARD" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:95:13 - information: Type of "set_phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:98:19 - information: Type of "pyzx_index" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:98:45 - information: Argument type is partially unknown -   Argument corresponds to parameter "iter2" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:99:9 - information: Type of "add_edge" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:99:57 - information: Type of "HADAMARD" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:100:9 - information: Type of "set_phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:102:12 - information: Return type is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:105:20 - information: Type of parameter "x" is unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:112:21 - information: Type of parameter "g" is unknown (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:5 - information: Type of "simplify" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:5 - information: Type of "to_graph_like" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:128:8 - error: "simplify" is not a known attribute of module "pyzx" (reportAttributeAccessIssue) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:5 - information: Type of "inputs" is partially unknown -   Type of "inputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:19 - information: Type of "inputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:131:19 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:5 - information: Type of "outputs" is partially unknown -   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:20 - information: Type of "outputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:132:20 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:5 - information: Type of "g_nx" is partially unknown -   Type of "g_nx" is "Graph[Unknown, Unknown, Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:21 - information: Type of "edges" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:134:21 - information: Argument type is unknown -   Argument corresponds to parameter "incoming_graph_data" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:138:9 - information: Type of "inp" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:138:16 - information: Type of "inputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:9 - information: Type of "first_nbr" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "i" in function "next" -   Argument type is "SupportsNext[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:31 - information: Type of "neighbors" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:139:31 - information: Argument type is unknown -   Argument corresponds to parameter "object" in function "iter" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:140:9 - information: Type of "et" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:140:14 - information: Type of "edge_type" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:142:18 - information: Type of "SIMPLE" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:143:13 - information: Type of "remove_node" is partially unknown -   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:143:30 - information: Argument type is unknown -   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:144:13 - information: Type of "inputs" is partially unknown -   Type of "inputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:144:56 - information: Type of "i" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:146:9 - information: Type of "out" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:146:16 - information: Type of "outputs" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:9 - information: Type of "first_nbr" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "i" in function "next" -   Argument type is "SupportsNext[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:31 - information: Type of "neighbors" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:147:31 - information: Argument type is unknown -   Argument corresponds to parameter "object" in function "iter" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:148:9 - information: Type of "et" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:148:14 - information: Type of "edge_type" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:150:18 - information: Type of "SIMPLE" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:151:13 - information: Type of "remove_node" is partially unknown -   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:151:30 - information: Argument type is unknown -   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:152:13 - information: Type of "outputs" is partially unknown -   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:152:57 - information: Type of "o" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:5 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:18 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:157:18 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__init__" -   Argument type is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:158:9 - information: Type of "v" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:9 - information: Type of "nbrs" is partially unknown -   Type of "nbrs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:21 - information: Type of "neighbors" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:162:21 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:163:16 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:164:67 - information: Type of "phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:164:67 - information: Argument type is unknown -   Argument corresponds to parameter "x" in function "_checked_float" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:165:13 - information: Type of "remove_node" is partially unknown -   Type of "remove_node" is "(n: Unknown) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:165:30 - information: Argument type is unknown -   Argument corresponds to parameter "n" in function "remove_node" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:5 - information: Type of "next_id" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:19 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:167:19 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "max" -   Argument type is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:171:9 - information: Type of "out" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:172:12 - information: Type of "phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:175:9 - information: Type of "add_edges_from" is partially unknown -   Type of "add_edges_from" is "(ebunch_to_add: Iterable[tuple[Unknown, Unknown] | tuple[Unknown, Unknown, Unknown]], **attr: Any) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:178:9 - information: Type of "outputs" is partially unknown -   Type of "outputs" is "list[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:178:55 - information: Type of "o" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:179:9 - information: Type of "next_id" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:182:9 - information: Type of "v" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:182:14 - information: Type of "nodes" is partially unknown -   Type of "nodes" is "NodeView[Unknown, Unknown, Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:188:58 - information: Type of "phase" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:188:58 - information: Argument type is unknown -   Argument corresponds to parameter "x" in function "_checked_float" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:22 - information: Argument type is partially unknown -   Argument corresponds to parameter "graph" in function "__init__" -   Argument type is "Graph[Unknown, Unknown, Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:28 - information: Argument type is partially unknown -   Argument corresponds to parameter "input_nodes" in function "__init__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/pyzx.py:190:36 - information: Argument type is partially unknown -   Argument corresponds to parameter "output_nodes" in function "__init__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:152:5 - information: Type of "kraus_list" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:152:62 - information: Argument type is unknown -   Argument corresponds to parameter "a" in function "inv" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/random_objects.py:154:52 - information: Argument type is unknown -   Argument corresponds to parameter "operator" in function "__init__" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:13 - information: Type of "node" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:26 - information: Type of "isolates" is partially unknown -   Type of "isolates" is "_dispatchable[(G: Graph[_Node@isolates, dict[str, Any], dict[str, Any]]), Unknown]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:498:26 - information: Argument type is unknown -   Argument corresponds to parameter "iterable" in function "__init__" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/remove_pauli_measurements.py:502:35 - information: Argument type is unknown -   Argument corresponds to parameter "u" in function "_remove_node" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:42:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:44:17 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/repr_mixins.py:45:35 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "join" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:35 - information: Argument type is partially unknown -   Argument corresponds to parameter "pyfunc" in function "__init__" -   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:42 - information: Type of parameter "value" is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:49 - information: Return type of lambda is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:424:64 - information: Argument type is unknown -   Argument corresponds to parameter "value" in function "subs" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:35 - information: Argument type is partially unknown -   Argument corresponds to parameter "pyfunc" in function "__init__" -   Argument type is "(value: Unknown) -> Unknown" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:42 - information: Type of parameter "value" is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:49 - information: Return type of lambda is unknown (reportUnknownLambdaType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/density_matrix.py:430:68 - information: Argument type is unknown -   Argument corresponds to parameter "value" in function "xreplace" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:152:41 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:152:80 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:156:13 - information: Type of "input_list" is partially unknown -   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:158:13 - information: Type of "input_list" is partially unknown -   Type of "input_list" is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:162:16 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:169:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:176:17 - information: Type of parameter "s" is partially unknown -   Parameter type is "State | Unknown | Iterable[Unknown]" (reportUnknownParameterType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:176:35 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:176:74 - error: Variable not allowed in type expression (reportInvalidTypeForm) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:184:46 - information: Type of "s" is partially unknown -   Type of "s" is "State | Unknown | Iterable[Unknown]" (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:189:26 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "list[State | Unknown | Iterable[Unknown]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:203:56 - information: Argument type is partially unknown -   Argument corresponds to parameter "o" in function "__init__" -   Argument type is "Unknown | Iterable[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:400:43 - error: No overloads for "einsum" match the provided arguments (reportCallIssue) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:400:43 - information: Type of "reshape" is unknown (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/statevec.py:400:53 - error: Argument of type "ndarray[tuple[int, ...], dtype[complex128]]" cannot be assigned to parameter "subscripts" of type "_ArrayLikeInt_co | str" in function "einsum" -   Type "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to type "_ArrayLikeInt_co | str" -     "ndarray[tuple[int, ...], dtype[complex128]]" is not assignable to "str" -     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]" -       "__array__" is an incompatible type -         No overloaded function matches type "() -> ndarray[Any, _DTypeT_co@_SupportsArray]" -     "ndarray[tuple[int, ...], dtype[complex128]]" is incompatible with protocol "_NestedSequence[_SupportsArray[dtype[numpy.bool[builtins.bool] | integer[Any]]]]" -       "__reversed__" is not present -       "count" is not present - ... (reportArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:401:9 - information: Type of "statevec" is unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:402:28 - information: Argument type is partially unknown -   Argument corresponds to parameter "obj" in function "len" -   Argument type is "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:404:16 - information: Return type, "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]", is partially unknown (reportUnknownVariableType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/sim/tensornet.py:404:42 - information: Argument type is partially unknown -   Argument corresponds to parameter "x" in function "norm" -   Argument type is "Unknown | ndarray[tuple[Any, ...], dtype[complex128]]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:234:13 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:238:49 - information: Argument type is partially unknown -   Argument corresponds to parameter "new_order" in function "__init__" -   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/space_minimization.py:238:55 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:495:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:501:41 - information: Argument type is partially unknown -   Argument corresponds to parameter "classical_outputs" in function "__init__" -   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:501:47 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1025:21 - information: Type of "append" is partially unknown -   Type of "append" is "(object: Unknown, /) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1028:46 - information: Argument type is partially unknown -   Argument corresponds to parameter "classical_measures" in function "__init__" -   Argument type is "tuple[Unknown, ...]" (reportUnknownArgumentType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/transpiler.py:1028:52 - information: Argument type is partially unknown -   Argument corresponds to parameter "iterable" in function "__new__" -   Argument type is "list[Unknown]" (reportUnknownArgumentType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/utils.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/utils.py:72:5 - information: Type of "m" is partially unknown -   Type of "m" is "ndarray[tuple[Any, ...], dtype[Unknown]]" (reportUnknownVariableType) -/Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:310:9 - information: Type of "figure" is partially unknown -   Type of "figure" is "(num: int | str | Figure | SubFigure | None = None, figsize: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, dpi: float | None = None, *, facecolor: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, edgecolor: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, frameon: bool = True, FigureClass: type[Figure] = Figure, clear: bool = False, **kwargs: Unknown) -> Figure" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:333:13 - information: Type of "show" is partially unknown -   Type of "show" is "(...) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:335:13 - information: Type of "savefig" is partially unknown -   Type of "savefig" is "(...) -> None" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:379:9 - information: Type of "xlim" is partially unknown -   Type of "xlim" is "(...) -> tuple[float, float]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:380:9 - information: Type of "ylim" is partially unknown -   Type of "ylim" is "(...) -> tuple[float, float]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:412:13 - information: Type of "scatter" is partially unknown -   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:427:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:443:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:444:17 - information: Type of "annotate" is partially unknown -   Type of "annotate" is "(text: str, xy: tuple[float, float], xytext: tuple[float, float] | None = None, xycoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] = "data", textcoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] | None = None, arrowprops: dict[str, Any] | None = None, annotation_clip: bool | None = None, **kwargs: Unknown) -> Annotation" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:486:13 - information: Type of "axvline" is partially unknown -   Type of "axvline" is "(x: float = 0, ymin: float = 0, ymax: float = 1, **kwargs: Unknown) -> Line2D" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:493:13 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:505:9 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:519:13 - information: Type of "annotate" is partially unknown -   Type of "annotate" is "(text: str, xy: tuple[float, float], xytext: tuple[float, float] | None = None, xycoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] = "data", textcoords: str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)) | tuple[str | Artist | Transform | ((RendererBase) -> (Bbox | Transform)), str | Artist | Transform | ((RendererBase) -> (Bbox | Transform))] | None = None, arrowprops: dict[str, Any] | None = None, annotation_clip: bool | None = None, **kwargs: Unknown) -> Annotation" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:530:9 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:552:13 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:559:13 - information: Type of "text" is partially unknown -   Type of "text" is "(x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs: Unknown) -> Text" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:566:9 - information: Type of "scatter" is partially unknown -   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:576:9 - information: Type of "scatter" is partially unknown -   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:587:13 - information: Type of "scatter" is partially unknown -   Type of "scatter" is "(x: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], y: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], s: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None = None, c: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | tuple[float, float, float] | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | None = None, marker: str | Path | MarkerStyle | None = None, cmap: str | Colormap | None = None, norm: str | Normalize | None = None, vmin: float | None = None, vmax: float | None = None, alpha: float | None = None, linewidths: float | Sequence[float] | None = None, *, edgecolors: tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float] | Sequence[tuple[float, float, float] | str | tuple[float, float, float, float] | tuple[tuple[float, float, float] | str, float] | tuple[tuple[float, float, float, float], float]] | None = None, colorizer: Colorizer | None = None, plotnonfinite: bool = False, data: Unknown | None = None, **kwargs: Unknown) -> PathCollection" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:597:9 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:602:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:604:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:605:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:606:17 - information: Type of "plot" is partially unknown -   Type of "plot" is "(*args: float | Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], scalex: bool = True, scaley: bool = True, data: Unknown | None = None, **kwargs: Unknown) -> list[Line2D]" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:612:9 - information: Type of "legend" is partially unknown -   Type of "legend" is "(...) -> Legend" (reportUnknownMemberType) - /Users/muldemol/QAT/projects/graphix/graphix/graphix/visualization.py:771:5 - information: Type of "values_union" is partially unknown -   Type of "values_union" is "set[Unknown | int]" (reportUnknownVariableType) -10 errors, 0 warnings, 266 informations From c5002b11d83c8c443ee84cdd66e3b43301d0ad4b Mon Sep 17 00:00:00 2001 From: matulni Date: Thu, 28 May 2026 09:49:13 +0200 Subject: [PATCH 12/25] Up rev dep branch for graphix-symbolic --- noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 65419b640..641d9c6fe 100644 --- a/noxfile.py +++ b/noxfile.py @@ -113,7 +113,7 @@ class ReverseDependency: ReverseDependency( "https://github.com/thierry-martinez/graphix-stim-backend", branch="fix/graphix_498_remove_pauli" ), - ReverseDependency("https://github.com/TeamGraphix/graphix-symbolic"), + ReverseDependency("https://github.com/matulni/graphix-symbolic", branch="backend"), ReverseDependency("https://github.com/TeamGraphix/graphix-qasm-parser"), ReverseDependency( "https://github.com/thierry-martinez/veriphix", From 756e4250e2d6b6801b009599f3fc57a61b67ff39 Mon Sep 17 00:00:00 2001 From: matulni Date: Thu, 28 May 2026 10:56:59 +0200 Subject: [PATCH 13/25] Initialize backend with capacity in circuit simulator --- graphix/transpiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphix/transpiler.py b/graphix/transpiler.py index 1c4015d88..33a076bbd 100644 --- a/graphix/transpiler.py +++ b/graphix/transpiler.py @@ -970,7 +970,7 @@ def simulate_statevector( if branch_selector is None: branch_selector = RandomBranchSelector() - backend = StatevectorBackend(branch_selector=branch_selector) + backend = StatevectorBackend.with_capacity(self.width, branch_selector=branch_selector) if input_state is None: backend.add_nodes(range(self.width)) else: From 7b25e9cca8897ccbec39203b9d5a02cdda38c212 Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 29 May 2026 09:57:16 +0200 Subject: [PATCH 14/25] Add new function to simulate default N commands --- graphix/sim/statevec.py | 47 +++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index c20640939..491f99df7 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -282,11 +282,17 @@ def add_nodes(self, nqubit: int, data: Data) -> None: Notes ----- - This method can extend the size of ``self.psi`` for convenience, but this requires allocating a full new array. + - This method can extend the size of ``self.psi`` for convenience, but this requires allocating a full new array. + - The implementation of this method does not support a parallelized kernel because data is read and written on the same array. """ self.ensure_capacity(required_qubits=self.nqubit + nqubit) - sv_to_add = Statevec(nqubit=nqubit, data=data) - self.tensor(sv_to_add) + if nqubit == 1 and data is BasicStates.PLUS: + # Simulating standard N commands falls in this branch. + _add_default_node_jit(self.psi, self.nqubit) + self._nqubit += 1 + else: + sv_to_add = Statevec(nqubit=nqubit, data=data) + self.tensor(sv_to_add) @override def entangle(self, qubits: tuple[int, int]) -> None: @@ -455,6 +461,10 @@ def remove_qubit(self, qubit: int) -> None: ---------- qubit : int Target qubit index. + + Notes + ----- + The implementation of this method does not support a parallelized kernel because data is read and written on the same array. """ self._check_bounds(qubit) self._nqubit = _remove_qubit_jit(self.psi, self.nqubit, qubit, atol=1e-10) @@ -734,16 +744,39 @@ def _tensor_jit( # We update the elements of `psi` in-place. # This requires starting the update for the last element of the new psi, `size_psi * size_other - 1` k = size_psi * size_other - 1 - sp_m1 = size_psi - 1 - so_m1 = size_other - 1 + max_psi_idx = size_psi - 1 + max_other_idx = size_other - 1 for i in range(size_psi): - alpha_old = psi[sp_m1 - i] + alpha_old = psi[max_psi_idx - i] for j in range(size_other): - psi[k] = alpha_old * psi_other[so_m1 - j] + psi[k] = alpha_old * psi_other[max_other_idx - j] k -= 1 +@nb.njit("(c16[::1], int32)") +def _add_default_node_jit( + psi: npt.NDArray[np.complex128], + nqubit: int, +) -> None: + r"""Tensor in-place a one-qubit |+> state. + + This function follows the same logic as :func:`_tensor_jit` but is specialized to ``psi_other`` being a :math:`(1, 1)/\sqrt{2}` state. + """ + read_idx = (1 << nqubit) - 1 # 2**nqubit - 1 + write_idx = (1 << nqubit + 1) - 1 # 2**(nqubit + 1) -1 + amp = 1 / np.sqrt(2) + + while read_idx >= 0: + v = amp * psi[read_idx] + + psi[write_idx] = v + psi[write_idx - 1] = v + + read_idx -= 1 + write_idx -= 2 + + @nb.njit("(c16[::1], int32, int32, int32)") def _swap_jit(psi: npt.NDArray[np.complex128], nqubit: int, q1: int, q2: int) -> None: """Swap two qubits. From 3f7c2f932c8b27562085c6821ea932310add415a Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 29 May 2026 11:33:56 +0200 Subject: [PATCH 15/25] Fix docs --- docs/source/tutorial.rst | 4 ++-- examples/deutsch_jozsa.py | 2 +- examples/qaoa.py | 2 +- examples/rotation.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst index a828719e7..c5e75a9b0 100644 --- a/docs/source/tutorial.rst +++ b/docs/source/tutorial.rst @@ -304,7 +304,7 @@ With the noise model written, we can simulate it. dm_result = simulator.run() ->>> print(dm_result.fidelity(out_state.psi.flatten())) +>>> print(dm_result.fidelity(out_state.flatten())) 0.9718678141724848 We can plot the results from the model, @@ -318,7 +318,7 @@ We can plot the results from the model, for i in range(10): simulator = PatternSimulator(pattern, backend="densitymatrix", noise_model=NoisyGraphState(p_z=err_arr[i])) dm_result = simulator.run() - fidelity[i] = dm_result.fidelity(out_state.psi.flatten()) + fidelity[i] = dm_result.fidelity(out_state.flatten()) plt.semilogx(err_arr, fidelity, "o:") plt.xlabel("dephasing error of qubit preparation") diff --git a/examples/deutsch_jozsa.py b/examples/deutsch_jozsa.py index 68a032846..aaf7c085b 100644 --- a/examples/deutsch_jozsa.py +++ b/examples/deutsch_jozsa.py @@ -91,6 +91,6 @@ out_state = pattern.simulate_pattern() state = circuit.simulate_statevector().statevec -print("overlap of states: ", np.abs(np.dot(state.psi.flatten().conjugate(), out_state.psi.flatten()))) +print("overlap of states: ", np.abs(np.dot(state.flatten().conjugate(), out_state.flatten()))) # %% diff --git a/examples/qaoa.py b/examples/qaoa.py index f0f2c1a42..a4a54ac67 100644 --- a/examples/qaoa.py +++ b/examples/qaoa.py @@ -48,7 +48,7 @@ out_state = pattern.simulate_pattern() state = circuit.simulate_statevector().statevec -print("overlap of states: ", np.abs(np.dot(state.psi.flatten().conjugate(), out_state.psi.flatten()))) +print("overlap of states: ", np.abs(np.dot(state.flatten().conjugate(), out_state.flatten()))) # sphinx_gallery_thumbnail_number = 2 # %% diff --git a/examples/rotation.py b/examples/rotation.py index 0de287855..44a1c1621 100644 --- a/examples/rotation.py +++ b/examples/rotation.py @@ -77,7 +77,7 @@ state = Statevec(nqubit=2, data=BasicStates.ZERO) # starts with |0> states state.evolve_single(Ops.rx(theta[0]), 0) state.evolve_single(Ops.rx(theta[1]), 1) -print("overlap of states: ", np.abs(np.dot(state.psi.flatten().conjugate(), out_state.psi.flatten()))) +print("overlap of states: ", np.abs(np.dot(state.flatten().conjugate(), out_state.flatten()))) # %% # Now let us compile more complex pattern and inspect the graph using the visualization tool. From 04cac99165f8ee878e8e3a501d2e48431173e263 Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 29 May 2026 11:50:33 +0200 Subject: [PATCH 16/25] Fix docstrings --- graphix/sim/statevec.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 491f99df7..52f55c841 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -103,13 +103,13 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max If ``nqubit`` is not provided, it is inferred from ``data``. If ``max_qubits`` is not provided, it is set to match the provided or inferred ``nqubit``. If only one :class:`graphix.states.State` is provided and ``nqubit`` is a valid integer, the statevector is initialized in the tensor product state. - If a ``graphix.statevec.Statevec`` is provided, a copy is returned. + If a class:`graphix.statevec.Statevec` is provided, a copy is returned. Consistency between provided ``nqubit``, ``max_qubits`` and ``data`` is checked. Parameters ---------- data : Data, optional - Input data to prepare the state. Can be a classical description or a numerical input, defaults to `graphix.states.BasicStates.PLUS`. + Input data to prepare the state. Can be a classical description or a numerical input, defaults to class:`graphix.states.BasicStates.PLUS`. nqubit : int | None, optional Number of qubits to prepare. If ``None`` (default), it's inferred from ``data``. max_qubits : int | None, optional. @@ -358,7 +358,6 @@ def expectation_single(self, op: Matrix, qubit: int) -> complex: Notes ----- - This method assumes that quantum state stored in ``self.psi`` is normalized. See the class docstring for details. - - The JIT kernel switches to a parallel implementation when the number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ @@ -714,7 +713,7 @@ def with_capacity( Initial backend state. If ``None``, the backend is initialized with a 0-dimensional statevector (scalar ``1``). **kwargs - Options for class:`graphix.sim.base_backend.DenseStateBackend`. See + Options for :class:`graphix.sim.base_backend.DenseStateBackend`. See :class:`graphix.sim.base_backend.DenseStateBackendKwargs`. Returns From 02118d29859cbefd75c8d5e42da50516c77d1de4 Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 29 May 2026 11:55:34 +0200 Subject: [PATCH 17/25] Fix docs agains --- graphix/sim/statevec.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 52f55c841..10fdf03b0 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -98,12 +98,12 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max - a single :class:`graphix.states.State` (classical description of a quantum state) - an iterable of :class:`graphix.states.State` objects - an iterable of scalars (a :math:`2^n` numerical statevector) - - a single :class:`graphix.statevec.Statevec` + - a single :class:`graphix.sim.statevec.Statevec` If ``nqubit`` is not provided, it is inferred from ``data``. If ``max_qubits`` is not provided, it is set to match the provided or inferred ``nqubit``. If only one :class:`graphix.states.State` is provided and ``nqubit`` is a valid integer, the statevector is initialized in the tensor product state. - If a class:`graphix.statevec.Statevec` is provided, a copy is returned. + If a class:`graphix.sim.statevec.Statevec` is provided, a copy is returned. Consistency between provided ``nqubit``, ``max_qubits`` and ``data`` is checked. Parameters @@ -358,8 +358,7 @@ def expectation_single(self, op: Matrix, qubit: int) -> complex: Notes ----- - This method assumes that quantum state stored in ``self.psi`` is normalized. See the class docstring for details. - - The JIT kernel switches to a parallel implementation when the - number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). + - The JIT kernel switches to a parallel implementation when the number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ self._check_bounds(qubit) kernel = _expectation_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _expectation_single_jit From 5abfaf0d49e2248a660ec2c874cb10760572bdb4 Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 29 May 2026 12:43:12 +0200 Subject: [PATCH 18/25] Fix docs AGAIN --- graphix/sim/statevec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 10fdf03b0..4fb41db8a 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -109,7 +109,7 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max Parameters ---------- data : Data, optional - Input data to prepare the state. Can be a classical description or a numerical input, defaults to class:`graphix.states.BasicStates.PLUS`. + Input data to prepare the state. Can be a classical description or a numerical input, defaults to :class:`graphix.states.BasicStates.PLUS`. nqubit : int | None, optional Number of qubits to prepare. If ``None`` (default), it's inferred from ``data``. max_qubits : int | None, optional. From 38b0c11d8e65b4d2b50b4e7d4eb436a1075f603a Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 29 May 2026 15:59:34 +0200 Subject: [PATCH 19/25] Update to new API --- graphix/transpiler.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/graphix/transpiler.py b/graphix/transpiler.py index 7859d3f0f..e4fd98ee0 100644 --- a/graphix/transpiler.py +++ b/graphix/transpiler.py @@ -1019,7 +1019,7 @@ def simulate_statevector( result : :class:`SimulateResult` output state of the statevector simulation and results of classical measures. """ - _backend = _initialize_backend(backend, branch_selector) + _backend = _initialize_backend(backend, branch_selector, self.width) if input_state is None: _backend.add_nodes(range(self.width)) @@ -1207,6 +1207,7 @@ def transpile_swaps(circuit: Circuit) -> TranspileSwapsResult: def _initialize_backend( backend: StatevectorBackend | Literal["statevector"], branch_selector: BranchSelector | None, + width: int, ) -> StatevectorBackend: ... @@ -1214,6 +1215,7 @@ def _initialize_backend( def _initialize_backend( backend: DensityMatrixBackend | Literal["densitymatrix"], branch_selector: BranchSelector | None, + width: int, ) -> DensityMatrixBackend: ... @@ -1221,12 +1223,14 @@ def _initialize_backend( def _initialize_backend( backend: DenseStateBackend[_DenseStateT_co], branch_selector: BranchSelector | None, + width: int, ) -> DenseStateBackend[_DenseStateT_co]: ... def _initialize_backend( backend: DenseStateBackend[_DenseStateT_co] | _DenseStateBackendLiteral, branch_selector: BranchSelector | None, + width: int, ) -> _BuiltinDenseStateBackend | DenseStateBackend[_DenseStateT_co]: """Initialize backend for circuit simulation. @@ -1236,6 +1240,9 @@ def _initialize_backend( Simulation backend branch_selector: :class:`BranchSelector` Branch selector used for measurements. Can only be specified if ``backend`` is not an already instantiated :class:`Backend` object. If ``None``, it defaults to :class:`RandomBranchSelector`. + width : int + Number of qubits in circuit. It is required to initialize the :class:`StatevectorBackend` with the appropriate + capacity. Returns ------- @@ -1252,7 +1259,7 @@ def _initialize_backend( match backend: case "statevector": - return StatevectorBackend(branch_selector=branch_selector) + return StatevectorBackend.with_capacity(width, branch_selector=branch_selector) case "densitymatrix": return DensityMatrixBackend(branch_selector=branch_selector) case _: From 512eaa5f59ead1f2e5b060c3f4d4f07032da671b Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 29 May 2026 16:15:27 +0200 Subject: [PATCH 20/25] Make psi a property --- graphix/sim/statevec.py | 56 +++++++++++++++++++++++------------------ tests/test_statevec.py | 2 +- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 4fb41db8a..ccc24a494 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -59,6 +59,9 @@ class Statevec(DenseState): Complex-valued 1-dimensional array representing the quantum statevector. Only the first ``2**nqubit`` complex values have meaning. + _nqubit : int + Number of active qubits at any given time. + _max_qubits : int Maximum Hilbert space size allowed for internal computations. It determines the size of ``psi``. For circuit simulations, it corresponds to the number @@ -66,9 +69,6 @@ class Statevec(DenseState): maximum space. The method :meth:`Statevec.ensure_capacity` allows to increase this number. - _nqubit : int - Number of active qubits at any given time. - Notes ----- The internal representation of the quantum state is guaranteed to be @@ -87,9 +87,9 @@ class Statevec(DenseState): details. """ - psi: npt.NDArray[np.complex128] - _max_qubits: int + _psi: npt.NDArray[np.complex128] _nqubit: int + _max_qubits: int def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max_qubits: int | None = None) -> None: """Initialize a statevector object. @@ -131,7 +131,7 @@ def __init__(self, data: Data = BasicStates.PLUS, nqubit: int | None = None, max raise ValueError( f"Inconsistent parameters between nqubit = {nqubit} and the inferred number of qubit = {len(data.flatten())}." ) - self.psi = data.psi.copy() + self._psi = data._psi.copy() self._max_qubits = data.max_qubits self._nqubit = data.nqubit @@ -209,16 +209,24 @@ def state_to_statevector( else: max_qubits = nqubit - self.psi = psi + self._psi = psi self._max_qubits = nqubit # bootstrap for self.ensure_capacity self._nqubit = nqubit - self.ensure_capacity(max_qubits) # may extend both self.psi and self._max_qubits + self.ensure_capacity(max_qubits) # may extend both self._psi and self._max_qubits def __str__(self) -> str: """Return a string description.""" sv = self.psi return f"Statevec object with statevector {sv} and length {len(sv)}." + @property + def psi(self) -> npt.NDArray[np.complex128]: + """Return a view of the meaningful elements in ``self._psi``. + + These are the first ``2**self.nqubit`` elements. + """ + return self._psi[: self.size_valid_psi] + # Note that `@property` must appear before `@override` for pyright @property @override @@ -233,7 +241,7 @@ def max_qubits(self) -> int: @property def size_valid_psi(self) -> int: - """Return the number of meaningful elements in ``self.psi``.""" + """Return the number of meaningful elements in ``self._psi``.""" return 1 << self.nqubit # 2**self.nqubit def ensure_capacity(self, required_qubits: int) -> None: @@ -245,11 +253,11 @@ def ensure_capacity(self, required_qubits: int) -> None: ---------- required_qubits : int Minimum number of qubits the state vector must support. If expansion - is needed, ``self.psi`` is extended to size ``2**required_qubits``. + is needed, ``self._psi`` is extended to size ``2**required_qubits``. """ if required_qubits > self.max_qubits: - offset = (1 << required_qubits) - len(self.psi) - self.psi = np.concatenate([self.psi, np.empty(offset, dtype=self.psi.dtype)]) + offset = (1 << required_qubits) - len(self._psi) + self._psi = np.concatenate([self._psi, np.empty(offset, dtype=self._psi.dtype)]) self._max_qubits = required_qubits @override @@ -258,7 +266,7 @@ def flatten(self) -> Matrix: A view of only the first ``2**self.nqubit`` elements of ``self.psi`` is returned. """ - return self.psi[: self.size_valid_psi] + return self.psi @override def add_nodes(self, nqubit: int, data: Data) -> None: @@ -282,13 +290,13 @@ def add_nodes(self, nqubit: int, data: Data) -> None: Notes ----- - - This method can extend the size of ``self.psi`` for convenience, but this requires allocating a full new array. + - This method can extend the size of ``self._psi`` for convenience, but this requires allocating a full new array. - The implementation of this method does not support a parallelized kernel because data is read and written on the same array. """ self.ensure_capacity(required_qubits=self.nqubit + nqubit) if nqubit == 1 and data is BasicStates.PLUS: # Simulating standard N commands falls in this branch. - _add_default_node_jit(self.psi, self.nqubit) + _add_default_node_jit(self._psi, self.nqubit) self._nqubit += 1 else: sv_to_add = Statevec(nqubit=nqubit, data=data) @@ -313,7 +321,7 @@ def entangle(self, qubits: tuple[int, int]) -> None: for qubit in qubits: self._check_bounds(qubit) kernel = _entangle_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _entangle_jit - kernel(self.psi, self.nqubit, *qubits) + kernel(self._psi, self.nqubit, *qubits) @override def evolve_single(self, op: Matrix, qubit: int) -> None: @@ -336,7 +344,7 @@ def evolve_single(self, op: Matrix, qubit: int) -> None: kernel = _evolve_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _evolve_single_jit # Downcast from Matrix to np.complex128 to match numba signature. op_as_complex = _cast_op(op) - kernel(self.psi, op_as_complex, self.nqubit, qubit) + kernel(self._psi, op_as_complex, self.nqubit, qubit) @override def expectation_single(self, op: Matrix, qubit: int) -> complex: @@ -357,14 +365,14 @@ def expectation_single(self, op: Matrix, qubit: int) -> complex: Notes ----- - - This method assumes that quantum state stored in ``self.psi`` is normalized. See the class docstring for details. + - This method assumes that quantum state represented by ``self.psi`` is normalized. See the class docstring for details. - The JIT kernel switches to a parallel implementation when the number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ self._check_bounds(qubit) kernel = _expectation_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _expectation_single_jit # Downcast from Matrix to np.complex128 to match numba signature. op_as_complex = _cast_op(op) - return kernel(self.psi, op_as_complex, self.nqubit, qubit) + return kernel(self._psi, op_as_complex, self.nqubit, qubit) @override def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: @@ -399,7 +407,7 @@ def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: for i, s in enumerate(qubits): res_idx[s] = out_idx[i] - self.psi[: self.size_valid_psi] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) # type: ignore[arg-type] # https://github.com/numpy/numpy/issues/31513 + self._psi[: self.size_valid_psi] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) # type: ignore[arg-type] # https://github.com/numpy/numpy/issues/31513 def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: """Return the expectation value of a multi-qubit operator. @@ -414,7 +422,7 @@ def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: Notes ----- - This method assumes that quantum state stored in ``self.psi`` is normalized. + This method assumes that quantum state represented by ``self.psi`` is normalized. See the class docstring for details. """ sv = deepcopy(self) @@ -465,7 +473,7 @@ def remove_qubit(self, qubit: int) -> None: The implementation of this method does not support a parallelized kernel because data is read and written on the same array. """ self._check_bounds(qubit) - self._nqubit = _remove_qubit_jit(self.psi, self.nqubit, qubit, atol=1e-10) + self._nqubit = _remove_qubit_jit(self._psi, self.nqubit, qubit, atol=1e-10) @override def swap(self, qubits: tuple[int, int]) -> None: @@ -476,7 +484,7 @@ def swap(self, qubits: tuple[int, int]) -> None: qubits : tuple[int, int] (control, target) qubit indices. """ - _swap_jit(self.psi, self.nqubit, *qubits) + _swap_jit(self._psi, self.nqubit, *qubits) def tensor(self, other: Statevec) -> None: r"""Tensor product state with other qubits. @@ -492,7 +500,7 @@ def tensor(self, other: Statevec) -> None: ----- This method is used internally by :meth:`add_nodes`. """ - _tensor_jit(self.psi, other.psi, self.nqubit, other.nqubit) + _tensor_jit(self._psi, other.psi, self.nqubit, other.nqubit) self._nqubit += other.nqubit def _check_bounds(self, qubit: int) -> None: diff --git a/tests/test_statevec.py b/tests/test_statevec.py index b8cab8e8a..ae5a0e3a0 100644 --- a/tests/test_statevec.py +++ b/tests/test_statevec.py @@ -69,7 +69,7 @@ def test_init_preallocation(self) -> None: assert np.allclose(sv.flatten(), np.array([1, 0, 1, 0]) / np.sqrt(2)) assert sv.nqubit == nqubit assert sv.max_qubits == max_qubits - assert len(sv.psi) == 2**max_qubits + assert len(sv._psi) == 2**max_qubits @pytest.mark.parametrize("nqubit", range(5)) def test_init_statevec(self, fx_rng: Generator, nqubit: int) -> None: From 95198f133f34e01727f665cbf315bd67fd5584be Mon Sep 17 00:00:00 2001 From: matulni Date: Fri, 29 May 2026 16:15:27 +0200 Subject: [PATCH 21/25] Make psi a property --- graphix/sim/statevec.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index ccc24a494..0463546b4 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -55,7 +55,7 @@ class Statevec(DenseState): Attributes ---------- - psi : npt.NDArray[np.complex128] + _psi : npt.NDArray[np.complex128] Complex-valued 1-dimensional array representing the quantum statevector. Only the first ``2**nqubit`` complex values have meaning. @@ -64,7 +64,7 @@ class Statevec(DenseState): _max_qubits : int Maximum Hilbert space size allowed for internal computations. It determines - the size of ``psi``. For circuit simulations, it corresponds to the number + the size of ``self._psi``. For circuit simulations, it corresponds to the number of qubits, while for pattern simulations it corresponds to the pattern's maximum space. The method :meth:`Statevec.ensure_capacity` allows to increase this number. @@ -225,7 +225,8 @@ def psi(self) -> npt.NDArray[np.complex128]: These are the first ``2**self.nqubit`` elements. """ - return self._psi[: self.size_valid_psi] + size_valid_psi = 1 << self.nqubit # 2**self.nqubit + return self._psi[:size_valid_psi] # Note that `@property` must appear before `@override` for pyright @property @@ -239,11 +240,6 @@ def max_qubits(self) -> int: """Return the preallocated number of qubits.""" return self._max_qubits - @property - def size_valid_psi(self) -> int: - """Return the number of meaningful elements in ``self._psi``.""" - return 1 << self.nqubit # 2**self.nqubit - def ensure_capacity(self, required_qubits: int) -> None: """Extend the state vector if the required qubit capacity exceeds the current one. @@ -407,7 +403,7 @@ def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: for i, s in enumerate(qubits): res_idx[s] = out_idx[i] - self._psi[: self.size_valid_psi] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) # type: ignore[arg-type] # https://github.com/numpy/numpy/issues/31513 + self._psi[: len(self.psi)] = np.einsum(op_t, op_idx, psi_t, psi_idx, res_idx).reshape(1 << self.nqubit) # type: ignore[arg-type] # https://github.com/numpy/numpy/issues/31513 def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: """Return the expectation value of a multi-qubit operator. From d0b85ef65fcb46cddcada9f7e014da4d5bc2a91d Mon Sep 17 00:00:00 2001 From: matulni Date: Sun, 31 May 2026 01:29:31 +0200 Subject: [PATCH 22/25] Improve remove_qubit and make parallel dispatch inside compiled functions --- graphix/sim/statevec.py | 307 +++++++++++++++++++++++++--------------- 1 file changed, 193 insertions(+), 114 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 0463546b4..1b40d1d62 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -24,7 +24,7 @@ if TYPE_CHECKING: from collections.abc import Callable, Sequence - from typing import Any, Literal, Self, TypeAlias, TypeVar + from typing import Any, Literal, Self, TypeVar # Unpack introduced in Python 3.12 from typing_extensions import Unpack @@ -35,14 +35,6 @@ _ENCODING = Literal["LSB", "MSB"] _ScalarT = TypeVar("_ScalarT", bound=np.generic[Any]) - EvolveSingleJit: TypeAlias = Callable[ - [npt.NDArray[np.complex128], npt.NDArray[np.complex128], int, int], None - ] # type introduced in 3.12 - ExpectationSingleJit: TypeAlias = Callable[ # type introduced in 3.12 - [npt.NDArray[np.complex128], npt.NDArray[np.complex128], int, int], complex - ] - EntangleJit: TypeAlias = Callable[[npt.NDArray[np.complex128], int, int, int], None] # type introduced in 3.12 - NUM_QUBIT_PARALLEL = 15 """This constant determines the number of qubits above which matrix operations @@ -286,8 +278,7 @@ def add_nodes(self, nqubit: int, data: Data) -> None: Notes ----- - - This method can extend the size of ``self._psi`` for convenience, but this requires allocating a full new array. - - The implementation of this method does not support a parallelized kernel because data is read and written on the same array. + This method can extend the size of ``self._psi`` for convenience, but this requires allocating a full new array. """ self.ensure_capacity(required_qubits=self.nqubit + nqubit) if nqubit == 1 and data is BasicStates.PLUS: @@ -306,18 +297,12 @@ def entangle(self, qubits: tuple[int, int]) -> None: ---------- qubits : tuple[int, int] (control, target) qubit indices. - - Notes - ----- - The JIT kernel switches to a parallel implementation when the - number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ # `_entangle_jit` is not unsafe if calle on out-of-bound indices but # we check them for robustness. for qubit in qubits: self._check_bounds(qubit) - kernel = _entangle_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _entangle_jit - kernel(self._psi, self.nqubit, *qubits) + _entangle_jit(self._psi, self.nqubit, *qubits) @override def evolve_single(self, op: Matrix, qubit: int) -> None: @@ -330,17 +315,11 @@ def evolve_single(self, op: Matrix, qubit: int) -> None: the operator to apply. qubit : int Target qubit index. - - Notes - ----- - The JIT kernel switches to a parallel implementation when the - number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ self._check_bounds(qubit) - kernel = _evolve_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _evolve_single_jit # Downcast from Matrix to np.complex128 to match numba signature. op_as_complex = _cast_op(op) - kernel(self._psi, op_as_complex, self.nqubit, qubit) + _evolve_single_jit(self._psi, op_as_complex, self.nqubit, qubit) @override def expectation_single(self, op: Matrix, qubit: int) -> complex: @@ -361,14 +340,12 @@ def expectation_single(self, op: Matrix, qubit: int) -> complex: Notes ----- - - This method assumes that quantum state represented by ``self.psi`` is normalized. See the class docstring for details. - - The JIT kernel switches to a parallel implementation when the number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). + This method assumes that quantum state represented by ``self.psi`` is normalized. See the class docstring for details. """ self._check_bounds(qubit) - kernel = _expectation_single_jit_parallel if self.nqubit > NUM_QUBIT_PARALLEL else _expectation_single_jit # Downcast from Matrix to np.complex128 to match numba signature. op_as_complex = _cast_op(op) - return kernel(self._psi, op_as_complex, self.nqubit, qubit) + return _expectation_single_jit(self._psi, op_as_complex, self.nqubit, qubit) @override def evolve(self, op: Matrix, qubits: Sequence[int]) -> None: @@ -660,6 +637,18 @@ def _to_dict_map( return {_format_encoding(self.nqubit, i, encoding): amp for i, amp in zip(i_vals, amp_vals, strict=True)} +def _format_encoding(nqubit: int, i: int, encoding: _ENCODING) -> str: + """Format the i-th basis vector as a ket. + + See :meth:`Statevec.to_dict` for additional details. + """ + display_width = nqubit + output = f"{i:0{display_width}b}" + if encoding == "LSB": + return output[::-1] + return output + + @dataclass(frozen=True) class StatevectorBackend(DenseStateBackend[Statevec]): """Numba JIT-compiled MBQC statevector backend simulator based on Ref. [1]. @@ -804,10 +793,26 @@ def _swap_jit(psi: npt.NDArray[np.complex128], nqubit: int, q1: int, q2: int) -> psi[j], psi[i] = psi[i], psi[j] -def _evolve_single(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, q: int) -> None: +@nb.njit("(c16[::1], c16[:,:], int32, int32, int32)") +def _compute_op_psi( + psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, offset: int, size_half_block: int +) -> None: + i1 = b0 + offset + i2 = i1 + size_half_block + psi1 = psi[i1] + psi2 = psi[i2] + psi[i1] = op[0, 0] * psi1 + op[0, 1] * psi2 + psi[i2] = op[1, 0] * psi1 + op[1, 1] * psi2 + + +@nb.njit("(c16[::1], c16[:,:], int32, int32)", parallel=True) +def _evolve_single_jit(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, q: int) -> None: r"""Apply a single-qubit operator. This function is inspired from Ref. [1]. + + The kernel switches to a parallel implementation when the + number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ nblocks = 1 << q size_block = 1 << nqubit - q # 2**(nqubit - q) @@ -815,30 +820,47 @@ def _evolve_single(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex12 size_block >> 1 ) # Left-to-right tensor product encoding (first qubit corresponds to most significant bit). For right-to-left encoding use `size_half_block = 1 << i` - for b in nb.prange(nblocks): - # WARNING: setting `b0 += size_block` may result in a race condition if `parallel=True` - b0 = size_block * b - for offset in range(size_half_block): - i1 = b0 | offset - i2 = i1 | size_half_block - psi1 = psi[i1] - psi2 = psi[i2] - psi[i1] = op[0, 0] * psi1 + op[0, 1] * psi2 - psi[i2] = op[1, 0] * psi1 + op[1, 1] * psi2 + if nqubit > NUM_QUBIT_PARALLEL: + if nblocks > 1: + for b in nb.prange(nblocks): + # WARNING: setting `b0 += size_block` may result in a race condition if parallel loop. + b0 = size_block * b + for offset in range(size_half_block): + _compute_op_psi(psi, op, b0, offset, size_half_block) + else: + for offset in nb.prange(size_half_block): + _compute_op_psi(psi, op, 0, offset, size_half_block) + else: + b0 = 0 + for _ in range(nblocks): + for offset in range(size_half_block): + _compute_op_psi(psi, op, b0, offset, size_half_block) + b0 += size_block -_evolve_single_jit: EvolveSingleJit = nb.njit("(c16[::1], c16[:,:], int32, int32)", parallel=False)(_evolve_single) -_evolve_single_jit_parallel: EvolveSingleJit = nb.njit("(c16[::1], c16[:,:], int32, int32)", parallel=True)( - _evolve_single -) +@nb.njit("c16(c16[::1], c16[:,:], int32, int32, int32)") +def _compute_psic_op_psi( + psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, offset: int, size_half_block: int +) -> complex: + i1 = b0 + offset + i2 = i1 + size_half_block + psi1 = psi[i1] + psi2 = psi[i2] + b1 = op[0, 0] * psi1 + op[0, 1] * psi2 + b2 = op[1, 0] * psi1 + op[1, 1] * psi2 + return psi1.conjugate() * b1 + psi2.conjugate() * b2 # type: ignore[no-any-return] -def _expectation_single( +@nb.njit("c16(c16[::1], c16[:,:], int32, int32)", parallel=True) +def _expectation_single_jit( psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, q: int ) -> complex: """Compute expectation value of single-qubit operator. This function applies ``op`` on ``psi`` in the same way as :func:`_evolve_single`. + + The kernel switches to a parallel implementation when the + number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ nblocks = 1 << q size_block = 1 << nqubit - q @@ -848,33 +870,34 @@ def _expectation_single( result = 0.0 + 0.0j - for b in nb.prange(nblocks): - # WARNING: setting `b0 += size_block` may result in a race condition if `parallel=True` - b0 = b << nqubit - q - for offset in range(size_half_block): - i1 = b0 | offset - i2 = i1 | size_half_block - psi1 = psi[i1] - psi2 = psi[i2] - b1 = op[0, 0] * psi1 + op[0, 1] * psi2 - b2 = op[1, 0] * psi1 + op[1, 1] * psi2 - result += psi1.conjugate() * b1 + psi2.conjugate() * b2 + if nqubit > NUM_QUBIT_PARALLEL: + if nblocks > 1: + for b in nb.prange(nblocks): + # WARNING: setting `b0 += size_block` may result in a race condition if parallel loop. + b0 = size_block * b + for offset in range(size_half_block): + result += _compute_psic_op_psi(psi, op, b0, offset, size_half_block) + else: + for offset in nb.prange(size_half_block): + result += _compute_psic_op_psi(psi, op, 0, offset, size_half_block) + else: + b0 = 0 + for _ in range(nblocks): + for offset in range(size_half_block): + result += _compute_psic_op_psi(psi, op, b0, offset, size_half_block) + b0 += size_block return result -_expectation_single_jit: ExpectationSingleJit = nb.njit("c16(c16[::1], c16[:,:], int32, int32)", parallel=False)( - _expectation_single -) -_expectation_single_jit_parallel: ExpectationSingleJit = nb.njit( - "c16(c16[::1], c16[:,:], int32, int32)", parallel=True -)(_expectation_single) - - -def _entangle(psi: npt.NDArray[np.complex128], nqubit: int, control: int, target: int) -> None: +@nb.njit("(c16[::1], int32, int32, int32)", parallel=True) +def _entangle_jit(psi: npt.NDArray[np.complex128], nqubit: int, control: int, target: int) -> None: """Apply CZ gate on two qubits. This function is inspired from Ref. [1]. + + The kernel switches to a parallel implementation when the + number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ size_sv = 1 << nqubit mask_control = 1 << nqubit - 1 - control @@ -882,16 +905,109 @@ def _entangle(psi: npt.NDArray[np.complex128], nqubit: int, control: int, target mask = mask_control | mask_target # `mask` is an integer number whose binary representation has 1s at positions `control` and `target` and 0s elsewhere. - for i in nb.prange(size_sv): - if mask & i == mask: - psi[i] = -psi[i] + if nqubit > NUM_QUBIT_PARALLEL: + for i in nb.prange(size_sv): + if mask & i == mask: + psi[i] = -psi[i] + else: + for i in range(size_sv): + if mask & i == mask: + psi[i] = -psi[i] + + +@nb.njit("f8(c16[::1], int32, int32)") +def _compute_a2( + psi: npt.NDArray[np.complex128], + b0: int, + j: int, +) -> float: + a = psi[b0 + j] + a_re = a.real + a_im = a.imag + return a_re * a_re + a_im * a_im # type: ignore[no-any-return] + + +@nb.njit("f8(c16[::1], int32, int32, int32, int32, int32)", parallel=True) +def _compute_norm( + psi: npt.NDArray[np.complex128], + nqubit: int, + n_blocks: int, + size_block: int, + size_half_block: int, + shift: int, +) -> float: + """Compute the norm of psi. + + The kernel switches to a parallel implementation when the + number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). + """ + norm2 = 0.0 + if nqubit > NUM_QUBIT_PARALLEL: + if n_blocks > 1: + for b in nb.prange(n_blocks): + b0 = b * size_block + shift + for j in range(size_half_block): + norm2 += _compute_a2(psi, b0, j) + else: + for j in nb.prange(size_half_block): + norm2 += _compute_a2(psi, shift, j) + else: + for b in range(n_blocks): + b0 = b * size_block + shift + for j in range(size_half_block): + norm2 += _compute_a2(psi, b0, j) + return norm2 + +@nb.njit("void(c16[::1], int32, int32, int32, int32, f8)") +def _scale_psi_kernel( + psi: npt.NDArray[np.complex128], + n_blocks: int, + size_block: int, + size_half_block: int, + shift: int, + inv_norm: float, +) -> None: + """Update ``psi`` with selected and normalized elements. -_entangle_jit: EntangleJit = nb.njit("(c16[::1], int32, int32, int32)", parallel=False)(_entangle) -_entangle_jit_parallel: EntangleJit = nb.njit("(c16[::1], int32, int32, int32)", parallel=True)(_entangle) + The implementation of this function does not support a parallelized + kernel because data is read and written on the same array. + """ + b0 = shift + k = 0 + for _ in range(n_blocks): + for j in range(size_half_block): + psi[k] = psi[b0 + j] * inv_norm + k += 1 + b0 += size_block -@nb.njit("int32(c16[::1], int32, int32, f8)", parallel=False) +@nb.njit("void(c16[::1], int32, int32, int32, int32, f8)") +def _scale_psi( + psi: npt.NDArray[np.complex128], + n_blocks: int, + size_block: int, + size_half_block: int, + shift: int, + inv_norm: float, +) -> None: + """Update ``psi`` with selected and normalized elements.""" + # If the inner loop in `_scale_psi_kernel` has too few elements + # it introduces some overhead and it's best to unroll it. + # Numba can do that only if ``size_half_block`` is a constant at + # compile time, so we dispatch the relevant cases. + # We observe speed improvements of up to 10%. + if size_block == 2: + _scale_psi_kernel(psi, n_blocks, 2, 1, shift, inv_norm) + elif size_block == 4: + _scale_psi_kernel(psi, n_blocks, 4, 2, shift, inv_norm) + elif size_block == 8: + _scale_psi_kernel(psi, n_blocks, 8, 4, shift, inv_norm) + else: + _scale_psi_kernel(psi, n_blocks, size_block, size_half_block, shift, inv_norm) + + +@nb.njit("int32(c16[::1], int32, int32, f8)") def _remove_qubit_jit( psi: npt.NDArray[np.complex128], nqubit: int, @@ -902,6 +1018,9 @@ def _remove_qubit_jit( Argument ``atol`` controls the tolerance below which norm of statevector is 0. See :meth:`Statevec.remove_qubit` for additional details on the implementation. + + This implementation benefited from Jérôme Richard's advice. + https://stackoverflow.com/questions/79948374/improving-efficiency-of-numba-jit-function """ new_nqubit = nqubit - 1 @@ -910,63 +1029,23 @@ def _remove_qubit_jit( size_half_block = size_block >> 1 # Compute norm of branch 0 - norm2 = 0.0 shift = 0 - b0 = shift - for _ in range(n_blocks): - # If parallelization, set `b0 = b * size_block + shift` with `b` the loop variable to avoid race condition. - # Parallelization for norm computation is not worth, execution-time controlled by the update loop which can't be parallelized without cache. - for j in range(size_half_block): - a = psi[b0 | j] - a_re = a.real - a_im = a.imag - norm2 += a_re * a_re + a_im * a_im - b0 += size_block + norm2 = _compute_norm(psi, nqubit, n_blocks, size_block, size_half_block, shift) # If norm of branch 0 is 0, compute norm of branch 1 and set shift to branch 1 if norm2 <= atol: - norm2 = 0.0 shift = size_half_block - b0 = shift - for _ in range(n_blocks): - for j in range(size_half_block): - a = psi[b0 | j] - a_re = a.real - a_im = a.imag - norm2 += a_re * a_re + a_im * a_im - b0 += size_block + norm2 = _compute_norm(psi, nqubit, n_blocks, size_block, size_half_block, shift) if norm2 <= atol: raise RuntimeError(f"Attempted to remove qubit {q} from 0-norm statevector.") - b0 = shift - k = 0 inv_norm = 1.0 / math.sqrt(norm2) - - # Update `psi` with selected and normalized elements. - for _ in range(n_blocks): - for j in range(size_half_block): - psi[k] = ( - psi[b0 | j] * inv_norm - ) # b0 | j equivalent to b0 + j because the active bits of b0 and j don't overlap. - k += 1 - b0 += size_block + _scale_psi(psi, n_blocks, size_block, size_half_block, shift, inv_norm) return new_nqubit -def _format_encoding(nqubit: int, i: int, encoding: _ENCODING) -> str: - """Format the i-th basis vector as a ket. - - See :meth:`Statevec.to_dict` for additional details. - """ - display_width = nqubit - output = f"{i:0{display_width}b}" - if encoding == "LSB": - return output[::-1] - return output - - def _cast_op(op: Matrix) -> npt.NDArray[np.complex128]: if op.dtype == np.object_: raise TypeError( From 16483a6662e1c904221638f3e541d8c5c9531f6c Mon Sep 17 00:00:00 2001 From: matulni Date: Mon, 1 Jun 2026 09:58:25 +0200 Subject: [PATCH 23/25] Mod docs --- graphix/sim/statevec.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 1b40d1d62..47f4998ef 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -37,7 +37,7 @@ NUM_QUBIT_PARALLEL = 15 -"""This constant determines the number of qubits above which matrix operations +"""This compilation constant determines the number of qubits above which matrix operations are multi-threaded. For lower counts, the overhead does not compensate parallelization. This number was determined empirically and it may be platform dependent.""" @@ -235,7 +235,8 @@ def max_qubits(self) -> int: def ensure_capacity(self, required_qubits: int) -> None: """Extend the state vector if the required qubit capacity exceeds the current one. - Does nothing if ``required_qubits <= self.max_qubits``. + It copies the full vector state if ``required_qubits > self.max_qubits``, + otherwise does nothing. Parameters ---------- @@ -252,7 +253,7 @@ def ensure_capacity(self, required_qubits: int) -> None: def flatten(self) -> Matrix: """Return flattened state. - A view of only the first ``2**self.nqubit`` elements of ``self.psi`` is returned. + A view of only the first ``2**self.nqubit`` elements of ``self._psi`` is returned. """ return self.psi @@ -298,7 +299,7 @@ def entangle(self, qubits: tuple[int, int]) -> None: qubits : tuple[int, int] (control, target) qubit indices. """ - # `_entangle_jit` is not unsafe if calle on out-of-bound indices but + # `_entangle_jit` is not unsafe if called on out-of-bound indices but # we check them for robustness. for qubit in qubits: self._check_bounds(qubit) @@ -317,7 +318,7 @@ def evolve_single(self, op: Matrix, qubit: int) -> None: Target qubit index. """ self._check_bounds(qubit) - # Downcast from Matrix to np.complex128 to match numba signature. + # Downcast from Matrix to npt.NDArray[np.complex128] to match numba signature. op_as_complex = _cast_op(op) _evolve_single_jit(self._psi, op_as_complex, self.nqubit, qubit) @@ -340,10 +341,11 @@ def expectation_single(self, op: Matrix, qubit: int) -> complex: Notes ----- - This method assumes that quantum state represented by ``self.psi`` is normalized. See the class docstring for details. + This method assumes that quantum state represented by ``self.psi`` is normalized. + See the class docstring for details. """ self._check_bounds(qubit) - # Downcast from Matrix to np.complex128 to match numba signature. + # Downcast from Matrix to npt.NDArray[np.complex128] to match numba signature. op_as_complex = _cast_op(op) return _expectation_single_jit(self._psi, op_as_complex, self.nqubit, qubit) @@ -431,19 +433,14 @@ def remove_qubit(self, qubit: int) -> None: :math:`0_{\mathrm{k}}` replaced with :math:`1_{\mathrm{k}}`. .. warning:: - This method assumes the qubit ``qarg`` to be separable from the rest, + This method assumes the qubit ``qubit`` to be separable from the rest, and is implemented as a significantly faster alternative for partial trace to - be used after single-qubit measurements. - Separability is not checked. + be used after single-qubit measurements. Separability is not checked. Parameters ---------- qubit : int Target qubit index. - - Notes - ----- - The implementation of this method does not support a parallelized kernel because data is read and written on the same array. """ self._check_bounds(qubit) self._nqubit = _remove_qubit_jit(self._psi, self.nqubit, qubit, atol=1e-10) @@ -492,7 +489,7 @@ def _check_bounds(self, qubit: int) -> None: IndexError """ if not 0 <= qubit < self.nqubit: - raise IndexError(f"Qubit index {qubit} out of range [0, {self.nqubit} -1]") + raise IndexError(f"Qubit index {qubit} out of range [0, {self.nqubit - 1}]") def fidelity(self, other: Statevec) -> float: r"""Calculate the fidelity against another statevector. @@ -797,6 +794,7 @@ def _swap_jit(psi: npt.NDArray[np.complex128], nqubit: int, q1: int, q2: int) -> def _compute_op_psi( psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, offset: int, size_half_block: int ) -> None: + """Update ``psi`` in place in step of :func:`_evolve_single_jit`.""" i1 = b0 + offset i2 = i1 + size_half_block psi1 = psi[i1] @@ -807,7 +805,7 @@ def _compute_op_psi( @nb.njit("(c16[::1], c16[:,:], int32, int32)", parallel=True) def _evolve_single_jit(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, q: int) -> None: - r"""Apply a single-qubit operator. + """Apply a single-qubit operator. This function is inspired from Ref. [1]. From 3ddc462d01cb0908db7ff6acef3417061c39fb97 Mon Sep 17 00:00:00 2001 From: matulni Date: Mon, 1 Jun 2026 18:08:41 +0200 Subject: [PATCH 24/25] Fuse evolve_single and remove_qubit --- graphix/sim/base_backend.py | 18 ++- graphix/sim/statevec.py | 251 +++++++++++++++++++++++++++++------- tests/test_graphsim.py | 9 +- tests/test_statevec.py | 11 +- 4 files changed, 225 insertions(+), 64 deletions(-) diff --git a/graphix/sim/base_backend.py b/graphix/sim/base_backend.py index 5fedfa181..a211d2c65 100644 --- a/graphix/sim/base_backend.py +++ b/graphix/sim/base_backend.py @@ -777,13 +777,23 @@ def entangle_nodes(self, edge: tuple[int, int]) -> None: def measure( self, node: int, measurement: Measurement, rng: Generator | None = None, *, stacklevel: int = 1 ) -> Outcome: - """Perform measurement of a node and trace out the qubit. + """Measure a node and trace out the corresponding qubit. Parameters ---------- - node: int - measurement: Measurement - rng: Generator, optional + node : int + Index of the node to measure. + measurement : Measurement + Measurement specification defining the measurement plane and angle. + rng : Generator, optional + Random number generator used for probabilistic outcome sampling. + stacklevel : int, default=1 + Stack level passed to the branch selector for warning reporting. + + Returns + ------- + Outcome + Measurement outcome. """ loc = self.node_index.index(node) bloch = measurement.to_bloch() diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index 47f4998ef..dd3400fe8 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -19,16 +19,25 @@ from typing_extensions import override from graphix import states -from graphix.sim.base_backend import DenseState, DenseStateBackend, DenseStateBackendKwargs, Matrix +from graphix.sim.base_backend import ( + DenseState, + DenseStateBackend, + DenseStateBackendKwargs, + Matrix, + _outcome_to_operator_matrix, +) from graphix.states import BasicStates if TYPE_CHECKING: from collections.abc import Callable, Sequence from typing import Any, Literal, Self, TypeVar + from numpy.random import Generator + # Unpack introduced in Python 3.12 from typing_extensions import Unpack + from graphix.measurements import Measurement, Outcome from graphix.parameter import ExpressionOrSupportsComplex from graphix.sim.data import Data @@ -442,8 +451,76 @@ def remove_qubit(self, qubit: int) -> None: qubit : int Target qubit index. """ + raise NotImplementedError("This method is deprecated. See :meth:`self.project_qubit`.") + + def project_qubit(self, op: Matrix, qubit: int) -> None: + r"""Project-out a qubit from the system and assemble the statevector of the remaining qubits. + + This method evolves the statevector with ``op`` and removes ``qubit``. It assumes that after the application of ``op``, ``qubit`` is a separable qubit. + + Let :math:`\ket{\psi} = P \ket{\psi} = \sum c_i \ket{i}` be the statevector after the application of the projector ``op``, with sum taken over + :math:`i \in [ 0 \dots 00,\ 0\dots 01,\ \dots,\ + 1 \dots 11 ]`, this method returns + + .. math:: + \begin{align} + \ket{\psi}' =& + c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 00} + \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 00} \\ + & + c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 01} + \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 01} \\ + & + c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 10} + \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 10} \\ + & + \dots \\ + & + c_{1 \dots 1_{\mathrm{k-1}}0_{\mathrm{k}}1_{\mathrm{k+1}} \dots 11} + \ket{1 \dots 1_{\mathrm{k-1}}1_{\mathrm{k+1}} \dots 11}, + \end{align} + + (after normalization) for :math:`k =` ``qubit``. If the :math:`k` th qubit is in the :math:`\ket{1}` state, all the amplitudes above will be zero. + In that case the returned state will be the one above with + :math:`0_{\mathrm{k}}` replaced with :math:`1_{\mathrm{k}}`. + + .. warning:: + This method assumes that ``op`` is a projector, and therefore that ``qubit`` is a separable ``qubit`` after applying ``op``. It is + implemented as a significantly faster alternative for partial trace to + be used after single-qubit measurements. Separability is not checked. + + Parameters + ---------- + op : npt.NDArray[np.complex128] + Complex-valued matrix of shape :math:`(2, 2)` representing + the projector to apply. + qubit : int + Target qubit index. + + Notes + ----- + This method combines :meth:`evolve_single` and :meth:`remove_qubit`. + + First, the relevant entries of ``self.psi`` are partitioned into two + disjoint subvectors. The partition depends on the value of ``q``. For a + three-qubit statevector ``[a0, a1, a2, a3, a4, a5, a6, a7]``: + + :: + + q = 0: sv0 = [a0, a1, a2, a3], sv1 = [a4, a5, a6, a7] + q = 1: sv0 = [a0, a1, a4, a5], sv1 = [a2, a3, a6, a7] + q = 2: sv0 = [a0, a2, a4, a6], sv1 = [a1, a3, a5, a7] + + The statevector is then iterated over as in :meth:`evolve_single`, + updating ``self.psi`` in place while computing the norm of each + partition separately. + + If both resulting subvectors have nonzero norm, they are guaranteed to + be identical. The subvector ``sv0`` is normalized and written to the first + ``2**(nqubit - 1)`` entries of ``self.psi``. + + If exactly one subvector has nonzero norm, that subvector is selected. + If both have zero norm, a ``RuntimeError`` is raised. + """ self._check_bounds(qubit) - self._nqubit = _remove_qubit_jit(self._psi, self.nqubit, qubit, atol=1e-10) + op_as_complex = _cast_op(op) + self._nqubit = _project_qubit_jit(self._psi, op_as_complex, self.nqubit, qubit, atol=1e-10) @override def swap(self, qubits: tuple[int, int]) -> None: @@ -715,6 +792,57 @@ def with_capacity( ) return cls(state_init, **kwargs) + @override + def measure( + self, node: int, measurement: Measurement, rng: Generator | None = None, *, stacklevel: int = 1 + ) -> Outcome: + """Measure a node and trace out the corresponding qubit. + + This method differs from :meth:`DenseStateBackend.measure` in that it calls + ``self.state.project_qubit`` instead of ``self.state.evolve_single`` and + ``self.state.remove_qubit``. This allows to measure the node in one less pass + over ``self.state.psi``. + + Parameters + ---------- + node : int + Index of the node to measure. + measurement : Measurement + Measurement specification defining the measurement plane and angle. + rng : Generator, optional + Random number generator used for probabilistic outcome sampling. + stacklevel : int, default=1 + Stack level passed to the branch selector for warning reporting. + + Returns + ------- + Outcome + Measurement outcome. + """ + loc = self.node_index.index(node) + bloch = measurement.to_bloch() + vec = bloch.plane.polar(bloch.angle) + # op_mat0 may contain the matrix operator associated with the outcome 0, + # but the value is computed lazily, i.e., only if needed. + op_mat0 = None + + def compute_op_mat0() -> Matrix: + nonlocal op_mat0 + if op_mat0 is None: + op_mat0 = _outcome_to_operator_matrix(vec, 0, symbolic=False) + return op_mat0 + + def f_expectation0() -> float: + exp_val = self.state.expectation_single(compute_op_mat0(), loc) + assert math.isclose(exp_val.imag, 0, abs_tol=1e-10) + return exp_val.real + + outcome = self.branch_selector.measure(node, f_expectation0, rng, stacklevel=stacklevel + 1) + op_mat = _outcome_to_operator_matrix(vec, 1, symbolic=False) if outcome else compute_op_mat0() + self.state.project_qubit(op_mat, loc) + self.node_index.remove(node) + return outcome + @nb.njit("(c16[::1], c16[::1], int32, int32)") def _tensor_jit( @@ -792,10 +920,10 @@ def _swap_jit(psi: npt.NDArray[np.complex128], nqubit: int, q1: int, q2: int) -> @nb.njit("(c16[::1], c16[:,:], int32, int32, int32)") def _compute_op_psi( - psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, offset: int, size_half_block: int + psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, j: int, size_half_block: int ) -> None: """Update ``psi`` in place in step of :func:`_evolve_single_jit`.""" - i1 = b0 + offset + i1 = b0 + j i2 = i1 + size_half_block psi1 = psi[i1] psi2 = psi[i2] @@ -823,24 +951,24 @@ def _evolve_single_jit(psi: npt.NDArray[np.complex128], op: npt.NDArray[np.compl for b in nb.prange(nblocks): # WARNING: setting `b0 += size_block` may result in a race condition if parallel loop. b0 = size_block * b - for offset in range(size_half_block): - _compute_op_psi(psi, op, b0, offset, size_half_block) + for j in range(size_half_block): + _compute_op_psi(psi, op, b0, j, size_half_block) else: - for offset in nb.prange(size_half_block): - _compute_op_psi(psi, op, 0, offset, size_half_block) + for j in nb.prange(size_half_block): + _compute_op_psi(psi, op, 0, j, size_half_block) else: b0 = 0 for _ in range(nblocks): - for offset in range(size_half_block): - _compute_op_psi(psi, op, b0, offset, size_half_block) + for j in range(size_half_block): + _compute_op_psi(psi, op, b0, j, size_half_block) b0 += size_block @nb.njit("c16(c16[::1], c16[:,:], int32, int32, int32)") def _compute_psic_op_psi( - psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, offset: int, size_half_block: int + psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, j: int, size_half_block: int ) -> complex: - i1 = b0 + offset + i1 = b0 + j i2 = i1 + size_half_block psi1 = psi[i1] psi2 = psi[i2] @@ -862,9 +990,7 @@ def _expectation_single_jit( """ nblocks = 1 << q size_block = 1 << nqubit - q - size_half_block = ( - size_block >> 1 - ) # Left-to-right tensor product encoding (first qubit corresponds to most significant bit). For right-to-left encoding use `size_half_block = 1 << i` + size_half_block = size_block >> 1 result = 0.0 + 0.0j @@ -873,16 +999,16 @@ def _expectation_single_jit( for b in nb.prange(nblocks): # WARNING: setting `b0 += size_block` may result in a race condition if parallel loop. b0 = size_block * b - for offset in range(size_half_block): - result += _compute_psic_op_psi(psi, op, b0, offset, size_half_block) + for j in range(size_half_block): + result += _compute_psic_op_psi(psi, op, b0, j, size_half_block) else: - for offset in nb.prange(size_half_block): - result += _compute_psic_op_psi(psi, op, 0, offset, size_half_block) + for j in nb.prange(size_half_block): + result += _compute_psic_op_psi(psi, op, 0, j, size_half_block) else: b0 = 0 for _ in range(nblocks): - for offset in range(size_half_block): - result += _compute_psic_op_psi(psi, op, b0, offset, size_half_block) + for j in range(size_half_block): + result += _compute_psic_op_psi(psi, op, b0, j, size_half_block) b0 += size_block return result @@ -913,48 +1039,71 @@ def _entangle_jit(psi: npt.NDArray[np.complex128], nqubit: int, control: int, ta psi[i] = -psi[i] -@nb.njit("f8(c16[::1], int32, int32)") -def _compute_a2( - psi: npt.NDArray[np.complex128], - b0: int, - j: int, -) -> float: - a = psi[b0 + j] - a_re = a.real - a_im = a.imag - return a_re * a_re + a_im * a_im # type: ignore[no-any-return] +@nb.njit("types.UniTuple(f8, 2)(c16[::1], c16[:,:], int32, int32, int32)") +def _compute_op_psi_a2( + psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, j: int, size_half_block: int +) -> tuple[float, float]: + """Update ``psi`` in place in step of :func:`_compute_norm_and_evolve_single_jit` and compute ``abs(psi)**2`` of updated elements.""" + # WARNING: Updating in-place a two-dimensional np.array for the the norm, e.g., + # `norm2_array[0] += norm2`` + # may result in a race condition. Return a tuple instead!! + i1 = b0 + j + i2 = i1 + size_half_block + psi1 = psi[i1] + psi2 = psi[i2] + a1 = op[0, 0] * psi1 + op[0, 1] * psi2 + a2 = op[1, 0] * psi1 + op[1, 1] * psi2 + psi[i1] = a1 + psi[i2] = a2 + + a1_re = a1.real + a1_im = a1.imag + norm2_1 = a1_re * a1_re + a1_im * a1_im + a2_re = a2.real + a2_im = a2.imag + norm2_2 = a2_re * a2_re + a2_im * a2_im -@nb.njit("f8(c16[::1], int32, int32, int32, int32, int32)", parallel=True) -def _compute_norm( + return norm2_1, norm2_2 + + +@nb.njit("types.UniTuple(f8, 2)(c16[::1], c16[:,:], int32, int32, int32, int32)", parallel=True) +def _compute_norm_and_evolve_single( psi: npt.NDArray[np.complex128], + op: npt.NDArray[np.complex128], nqubit: int, n_blocks: int, size_block: int, size_half_block: int, - shift: int, -) -> float: - """Compute the norm of psi. +) -> tuple[float, float]: + """Evolve the full statevector with ``op`` and compute the norm of ``psi[b0+j]``. The kernel switches to a parallel implementation when the number of qubits exceeds ``NUM_QUBIT_PARALLEL`` (module constant). """ - norm2 = 0.0 + norm2_0 = 0.0 + norm2_1 = 0.0 if nqubit > NUM_QUBIT_PARALLEL: if n_blocks > 1: for b in nb.prange(n_blocks): - b0 = b * size_block + shift + b0 = b * size_block for j in range(size_half_block): - norm2 += _compute_a2(psi, b0, j) + norm2 = _compute_op_psi_a2(psi, op, b0, j, size_half_block) + norm2_0 += norm2[0] + norm2_1 += norm2[1] else: for j in nb.prange(size_half_block): - norm2 += _compute_a2(psi, shift, j) + norm2 = _compute_op_psi_a2(psi, op, 0, j, size_half_block) + norm2_0 += norm2[0] + norm2_1 += norm2[1] else: for b in range(n_blocks): - b0 = b * size_block + shift + b0 = b * size_block for j in range(size_half_block): - norm2 += _compute_a2(psi, b0, j) - return norm2 + norm2 = _compute_op_psi_a2(psi, op, b0, j, size_half_block) + norm2_0 += norm2[0] + norm2_1 += norm2[1] + return norm2_0, norm2_1 @nb.njit("void(c16[::1], int32, int32, int32, int32, f8)") @@ -1005,14 +1154,15 @@ def _scale_psi( _scale_psi_kernel(psi, n_blocks, size_block, size_half_block, shift, inv_norm) -@nb.njit("int32(c16[::1], int32, int32, f8)") -def _remove_qubit_jit( +@nb.njit("int32(c16[::1], c16[:,:], int32, int32, f8)") +def _project_qubit_jit( psi: npt.NDArray[np.complex128], + op: npt.NDArray[np.complex128], nqubit: int, q: int, atol: float, ) -> int: - """Remove qubit. + """Evolve the statevector with ``op`` and remove qubit ``q``. Argument ``atol`` controls the tolerance below which norm of statevector is 0. See :meth:`Statevec.remove_qubit` for additional details on the implementation. @@ -1026,14 +1176,15 @@ def _remove_qubit_jit( size_block = 1 << nqubit - q # 2**(nqubits - q) size_half_block = size_block >> 1 - # Compute norm of branch 0 + # Apply `op` to the full statevector and compute norm of branch 0 shift = 0 - norm2 = _compute_norm(psi, nqubit, n_blocks, size_block, size_half_block, shift) - # If norm of branch 0 is 0, compute norm of branch 1 and set shift to branch 1 + norm2, norm2_1 = _compute_norm_and_evolve_single(psi, op, nqubit, n_blocks, size_block, size_half_block) + + # If norm of branch 0 is 0, we pick norm of branch 1 and set shift to branch 1. if norm2 <= atol: shift = size_half_block - norm2 = _compute_norm(psi, nqubit, n_blocks, size_block, size_half_block, shift) + norm2 = norm2_1 if norm2 <= atol: raise RuntimeError(f"Attempted to remove qubit {q} from 0-norm statevector.") diff --git a/tests/test_graphsim.py b/tests/test_graphsim.py index bc0799b04..a10c636e3 100644 --- a/tests/test_graphsim.py +++ b/tests/test_graphsim.py @@ -83,20 +83,17 @@ def test_fig2(self) -> None: g = GraphState(nodes=np.arange(nqubit), edges=edges) gstate = graph_state_to_statevec(g) g.measure_x(0) - gstate.evolve_single(meas_op(0), 0) # x meas - gstate.remove_qubit(0) + gstate.project_qubit(meas_op(0), 0) # x meas gstate2 = graph_state_to_statevec(g) assert gstate.isclose(gstate2) g.measure_y(1, choice=0) - gstate.evolve_single(meas_op(0.5 * ANGLE_PI), 0) # y meas - gstate.remove_qubit(0) + gstate.project_qubit(meas_op(0.5 * ANGLE_PI), 0) # y meas gstate2 = graph_state_to_statevec(g) assert gstate.isclose(gstate2) g.measure_z(3) - gstate.evolve_single(meas_op(0.5 * ANGLE_PI, plane=Plane.YZ), 1) # z meas - gstate.remove_qubit(1) + gstate.project_qubit(meas_op(0.5 * ANGLE_PI, plane=Plane.YZ), 1) # z meas gstate2 = graph_state_to_statevec(g) assert gstate.isclose(gstate2) diff --git a/tests/test_statevec.py b/tests/test_statevec.py index ae5a0e3a0..c7beb96f0 100644 --- a/tests/test_statevec.py +++ b/tests/test_statevec.py @@ -244,8 +244,11 @@ def test_add_nodes_beyond_max_qubits(self, fx_rng: Generator) -> None: ), ], ) - def test_remove_qubit(self, sv: Statevec, q: int, sv_ref: Statevec) -> None: - sv.remove_qubit(q) + def test_project_qubit(self, sv: Statevec, q: int, sv_ref: Statevec) -> None: + # This test mimics the behavior of former `remove_qubit`. + op = np.eye(2, dtype=np.complex128) + sv.project_qubit(op, q) + assert np.linalg.norm(sv.psi) == pytest.approx(1) assert np.allclose(sv.flatten(), sv_ref.flatten()) @pytest.mark.parametrize( @@ -270,9 +273,9 @@ def test_measurement_into_each_xyz_basis(self, state: PlanarState) -> None: if state is BasicStates.MINUS: # Measurement into |-> results in a 0-norm vector with pytest.raises(RuntimeError): - sv.remove_qubit(k) + sv.project_qubit(m_op, k) else: - sv.remove_qubit(k) + sv.project_qubit(m_op, k) sv2 = Statevec(nqubit=n - 1) assert sv.isclose(sv2) From 7e4b02f79dc7ce39bbbd515a91e82d09f3522f04 Mon Sep 17 00:00:00 2001 From: matulni Date: Tue, 2 Jun 2026 09:35:13 +0200 Subject: [PATCH 25/25] Make project_qubit a method of DenseState --- graphix/sim/base_backend.py | 19 +++++++- graphix/sim/statevec.py | 94 +++---------------------------------- tests/test_statevec.py | 9 ++-- 3 files changed, 29 insertions(+), 93 deletions(-) diff --git a/graphix/sim/base_backend.py b/graphix/sim/base_backend.py index a211d2c65..64fdcbb13 100644 --- a/graphix/sim/base_backend.py +++ b/graphix/sim/base_backend.py @@ -443,6 +443,22 @@ def remove_qubit(self, qubit: int) -> None: Target qubit index. """ + def project_qubit(self, op: Matrix, qubit: int) -> None: + r"""Project out a qubit from the system and assemble the statevector of the remaining qubits. + + This method combines :meth:`evolve_single` and :meth:`remove_qubit`. It evolves the statevector with ``op`` and removes ``qubit``. It assumes that after the application of ``op``, ``qubit`` is a separable qubit. + + Parameters + ---------- + op : npt.NDArray[np.complex128] + Complex-valued matrix of shape :math:`(2, 2)` representing + the projector to apply. + qubit : int + Target qubit index. + """ + self.evolve_single(op, qubit) + self.remove_qubit(qubit) + @abstractmethod def swap(self, qubits: tuple[int, int]) -> None: """Apply SWAP gate between two qubits. @@ -815,9 +831,8 @@ def f_expectation0() -> float: outcome = self.branch_selector.measure(node, f_expectation0, rng, stacklevel=stacklevel + 1) op_mat = _outcome_to_operator_matrix(vec, 1, symbolic=self.symbolic) if outcome else compute_op_mat0() - self.state.evolve_single(op_mat, loc) + self.state.project_qubit(op_mat, loc) self.node_index.remove(node) - self.state.remove_qubit(loc) return outcome @override diff --git a/graphix/sim/statevec.py b/graphix/sim/statevec.py index dd3400fe8..63238ca95 100644 --- a/graphix/sim/statevec.py +++ b/graphix/sim/statevec.py @@ -24,7 +24,6 @@ DenseStateBackend, DenseStateBackendKwargs, Matrix, - _outcome_to_operator_matrix, ) from graphix.states import BasicStates @@ -32,12 +31,9 @@ from collections.abc import Callable, Sequence from typing import Any, Literal, Self, TypeVar - from numpy.random import Generator - # Unpack introduced in Python 3.12 from typing_extensions import Unpack - from graphix.measurements import Measurement, Outcome from graphix.parameter import ExpressionOrSupportsComplex from graphix.sim.data import Data @@ -417,34 +413,7 @@ def expectation_value(self, op: Matrix, qubits: Sequence[int]) -> complex: def remove_qubit(self, qubit: int) -> None: r"""Remove a separable qubit from the system and assemble the statevector of the remaining qubits. - This is equivalent to the partial trace if ``qubit`` corresponds to a separable qubit. - - For a statevector :math:`\ket{\psi} = \sum c_i \ket{i}` with sum taken over - :math:`i \in [ 0 \dots 00,\ 0\dots 01,\ \dots,\ - 1 \dots 11 ]`, this method returns - - .. math:: - \begin{align} - \ket{\psi}' =& - c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 00} - \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 00} \\ - & + c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 01} - \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 01} \\ - & + c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 10} - \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 10} \\ - & + \dots \\ - & + c_{1 \dots 1_{\mathrm{k-1}}0_{\mathrm{k}}1_{\mathrm{k+1}} \dots 11} - \ket{1 \dots 1_{\mathrm{k-1}}1_{\mathrm{k+1}} \dots 11}, - \end{align} - - (after normalization) for :math:`k =` ``qubit``. If the :math:`k` th qubit is in the :math:`\ket{1}` state, all the amplitudes above will be zero. - In that case the returned state will be the one above with - :math:`0_{\mathrm{k}}` replaced with :math:`1_{\mathrm{k}}`. - - .. warning:: - This method assumes the qubit ``qubit`` to be separable from the rest, - and is implemented as a significantly faster alternative for partial trace to - be used after single-qubit measurements. Separability is not checked. + This method is deprecated. See :meth:`self.project_qubit`. Parameters ---------- @@ -454,11 +423,11 @@ def remove_qubit(self, qubit: int) -> None: raise NotImplementedError("This method is deprecated. See :meth:`self.project_qubit`.") def project_qubit(self, op: Matrix, qubit: int) -> None: - r"""Project-out a qubit from the system and assemble the statevector of the remaining qubits. + r"""Project out a qubit from the system and assemble the statevector of the remaining qubits. This method evolves the statevector with ``op`` and removes ``qubit``. It assumes that after the application of ``op``, ``qubit`` is a separable qubit. - Let :math:`\ket{\psi} = P \ket{\psi} = \sum c_i \ket{i}` be the statevector after the application of the projector ``op``, with sum taken over + Let :math:`P \ket{\psi} = \sum c_i \ket{i}` be the statevector after the application of the projector :math:`P` (``op``), with sum taken over :math:`i \in [ 0 \dots 00,\ 0\dots 01,\ \dots,\ 1 \dots 11 ]`, this method returns @@ -792,57 +761,6 @@ def with_capacity( ) return cls(state_init, **kwargs) - @override - def measure( - self, node: int, measurement: Measurement, rng: Generator | None = None, *, stacklevel: int = 1 - ) -> Outcome: - """Measure a node and trace out the corresponding qubit. - - This method differs from :meth:`DenseStateBackend.measure` in that it calls - ``self.state.project_qubit`` instead of ``self.state.evolve_single`` and - ``self.state.remove_qubit``. This allows to measure the node in one less pass - over ``self.state.psi``. - - Parameters - ---------- - node : int - Index of the node to measure. - measurement : Measurement - Measurement specification defining the measurement plane and angle. - rng : Generator, optional - Random number generator used for probabilistic outcome sampling. - stacklevel : int, default=1 - Stack level passed to the branch selector for warning reporting. - - Returns - ------- - Outcome - Measurement outcome. - """ - loc = self.node_index.index(node) - bloch = measurement.to_bloch() - vec = bloch.plane.polar(bloch.angle) - # op_mat0 may contain the matrix operator associated with the outcome 0, - # but the value is computed lazily, i.e., only if needed. - op_mat0 = None - - def compute_op_mat0() -> Matrix: - nonlocal op_mat0 - if op_mat0 is None: - op_mat0 = _outcome_to_operator_matrix(vec, 0, symbolic=False) - return op_mat0 - - def f_expectation0() -> float: - exp_val = self.state.expectation_single(compute_op_mat0(), loc) - assert math.isclose(exp_val.imag, 0, abs_tol=1e-10) - return exp_val.real - - outcome = self.branch_selector.measure(node, f_expectation0, rng, stacklevel=stacklevel + 1) - op_mat = _outcome_to_operator_matrix(vec, 1, symbolic=False) if outcome else compute_op_mat0() - self.state.project_qubit(op_mat, loc) - self.node_index.remove(node) - return outcome - @nb.njit("(c16[::1], c16[::1], int32, int32)") def _tensor_jit( @@ -1043,7 +961,7 @@ def _entangle_jit(psi: npt.NDArray[np.complex128], nqubit: int, control: int, ta def _compute_op_psi_a2( psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], b0: int, j: int, size_half_block: int ) -> tuple[float, float]: - """Update ``psi`` in place in step of :func:`_compute_norm_and_evolve_single_jit` and compute ``abs(psi)**2`` of updated elements.""" + """Update ``psi`` in place in step of :func:`_evolve_single_and_compute_norm_jit` and compute ``abs(psi)**2`` of updated elements.""" # WARNING: Updating in-place a two-dimensional np.array for the the norm, e.g., # `norm2_array[0] += norm2`` # may result in a race condition. Return a tuple instead!! @@ -1068,7 +986,7 @@ def _compute_op_psi_a2( @nb.njit("types.UniTuple(f8, 2)(c16[::1], c16[:,:], int32, int32, int32, int32)", parallel=True) -def _compute_norm_and_evolve_single( +def _evolve_single_and_compute_norm( psi: npt.NDArray[np.complex128], op: npt.NDArray[np.complex128], nqubit: int, @@ -1179,7 +1097,7 @@ def _project_qubit_jit( # Apply `op` to the full statevector and compute norm of branch 0 shift = 0 - norm2, norm2_1 = _compute_norm_and_evolve_single(psi, op, nqubit, n_blocks, size_block, size_half_block) + norm2, norm2_1 = _evolve_single_and_compute_norm(psi, op, nqubit, n_blocks, size_block, size_half_block) # If norm of branch 0 is 0, we pick norm of branch 1 and set shift to branch 1. if norm2 <= atol: diff --git a/tests/test_statevec.py b/tests/test_statevec.py index c7beb96f0..3030250bc 100644 --- a/tests/test_statevec.py +++ b/tests/test_statevec.py @@ -15,7 +15,7 @@ from graphix.ops import Ops from graphix.pauli import Pauli from graphix.random_objects import rand_unit -from graphix.sim.statevec import Statevec, StatevectorBackend +from graphix.sim.statevec import NUM_QUBIT_PARALLEL, Statevec, StatevectorBackend from graphix.states import BasicStates from graphix.transpiler import Circuit @@ -423,8 +423,11 @@ def test_to_prob_dict(self, encoding: _ENCODING, dict_ref: Mapping[str, float]) assert np.isclose(dict_ref[ket], amp2.real) assert np.isclose(0, amp2.imag) - def test_simulation_identity(self, fx_rng: Generator) -> None: - nqubits = 3 + # Run with `nqubits` larger and smaller than ``graphix.sim.statevec.NUM_QUBIT_PARALLEL`` + # to test parallelized and non-parallelized kernels. + # This usually allows to detect race conditions. + @pytest.mark.parametrize("nqubits", [3, NUM_QUBIT_PARALLEL + 1]) + def test_simulation_identity(self, fx_rng: Generator, nqubits: int) -> None: qc = Circuit(nqubits) angle_1 = 2 * fx_rng.random() angle_2 = 2 * fx_rng.random()