Source code for qrisp_cudaq.annotations

# ********************************************************************************
# * Copyright (c) 2026 the Qrisp authors
# *
# * This program and the accompanying materials are made available under the
# * terms of the Eclipse Public License 2.0 which is available at
# * http://www.eclipse.org/legal/epl-2.0.
# *
# * This Source Code may also be made available under the following Secondary
# * Licenses when the conditions for such availability set forth in the Eclipse
# * Public License, v. 2.0 are satisfied: GNU General Public License, version 2
# * with the GNU Classpath Exception which is
# * available at https://www.gnu.org/software/classpath/license.html.
# *
# * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
# ********************************************************************************

"""Define type annotations used by CUDA-Q kernel wrappers."""

import numpy as np


[docs] class FixedShapeNDArray: """Type annotation for a fixed-size numpy array parameter in ``@cudaq_kernel``. Mirrors the role of ``list[float]`` / ``list[int]`` in ``@cudaq.kernel`` but requires an explicit size, because JAX traces with concrete shapes. The decorator uses the element type and size to generate a correctly-typed dummy value for tracing. Use the subscript syntax ``FixedShapeNDArray[dtype, size]`` in annotations, mirroring how Python's generics (e.g. ``list[int]``) are used in type annotations, rather than calling the class directly. Parameters ---------- dtype : type Element type. Supported: ``float``, ``int``, ``bool``. size : int Number of elements. Must match the runtime array length. Examples -------- :: import cudaq import numpy as np from qrisp import * from qrisp_cudaq import cudaq_kernel, FixedShapeNDArray @cudaq_kernel def circuit(angles: FixedShapeNDArray[float, 3]): qv = QuantumFloat(2) ry(angles[0], qv[0]) return measure(qv[0]) angles = np.array([1.57, 0.78, 0.39]) print(cudaq.run(circuit, angles, shots_count=100)) """ #: Maps Python dtype to NumPy dtype and MLIR element type string. _DTYPE_MAP = { float: (np.float64, "f64"), int: (np.int64, "i64"), bool: (np.bool_, "i1"), } def __init__(self, dtype: type, size: int): """Initialize the object.""" if dtype not in self._DTYPE_MAP: raise TypeError( f"FixedShapeNDArray: unsupported dtype '{dtype}'. Supported: {list(self._DTYPE_MAP.keys())}." ) if not isinstance(size, int) or size <= 0: raise ValueError("FixedShapeNDArray: size must be a positive integer.") self.dtype = dtype self.size = size self._np_dtype, self.mlir_elem_type = self._DTYPE_MAP[dtype] def __class_getitem__(cls, params): """Enable ``FixedShapeNDArray[dtype, size]`` subscript syntax. This mirrors how Python's generic types (e.g. ``list[int]``) are written in annotations, so type checkers treat this as a subscripted generic rather than flagging a class instance used directly as an annotation. """ if not isinstance(params, tuple): params = (params,) return cls(*params) def make_dummy(self) -> np.ndarray: """Return a zero-filled NumPy array of the correct dtype and size.""" return np.zeros(self.size, dtype=self._np_dtype) def __repr__(self): """Return a concise representation of the fixed-shape annotation.""" return f"FixedShapeNDArray({self.dtype.__name__}, {self.size})"