File size: 4,500 Bytes
9e551a1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | # Tensor Roll — Recursive CUDA-Q Model Quantizer
# Copyright (C) 2026 SnapKitty Collective
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Real CUDA-Q kernels for the tensor_roll family.
Target: NVIDIA CUDA-Q Python API (>= 0.8). Execute with a simulator
target (``cudaq.set_target("qpp-cpu")``) or on QPU/GPU hardware.
These kernels are NOT executed by the tensor-roll CLI on machines without
the CUDA-Q toolchain (see docs/BOUNDARIES.md). The classical state-vector
simulator in tensor_roll/qsim.py mirrors this family's semantics so the
pipeline is measurable everywhere; every qsim report is labeled
``qsim-classical`` and never claims QPU execution.
Conceptual mapping (classical -> quantum descent):
C = A x B (CUDA GEMM, classical baseline)
TensorRoll(A, B) (dispatch boundary in tensor_roll/core.py)
|- classical region -> CUDA GEMM
-- candidate region -> tensor_roll kernels below -> measurement
-> classical reconstruction
"""
try:
import cudaq
from cudaq import spin
_HAS_CUDAQ = True
except ImportError: # pragma: no cover - toolchain absent on most machines
_HAS_CUDAQ = False
if _HAS_CUDAQ:
@cudaq.kernel
def tensor_roll_encode(qubits: cudaq.qview, angles: list[float]):
"""Angle-encode a tensor block: RY(2*atan(x_i)) per qubit."""
for q in range(qubits.size()):
ry(2.0 * angles[q], qubits[q])
@cudaq.kernel
def tensor_roll_rotate(qubits: cudaq.qview, angles: list[float]):
"""Per-qubit RY rotations (the 'roll' of the register)."""
for q in range(qubits.size()):
ry(angles[q], qubits[q])
@cudaq.kernel
def tensor_roll_entangle(qubits: cudaq.qview):
"""Nearest-neighbour CNOT ladder."""
for q in range(qubits.size() - 1):
x.ctrl(qubits[q], qubits[q + 1])
@cudaq.kernel
def tensor_roll_measure(qubits: cudaq.qview):
"""Measure the full register in the Z basis."""
mz(qubits)
@cudaq.kernel
def tensor_roll_recursive(qubits: cudaq.qview, angles: list[float],
depth: int):
"""Recursive kernel: each level rotates + entangles a shrinking
active qubit subset, then measures it. Implemented iteratively over
levels (CUDA-Q kernels unroll statically); depth selects how many
levels execute."""
n = qubits.size()
for level in range(depth):
# active subset shrinks with depth: n, n-1, ...
for q in range(n):
if q < n - level:
ry(angles[q], qubits[q])
for q in range(n - 1):
if q < n - 1 - level:
x.ctrl(qubits[q], qubits[q + 1])
if level < depth - 1:
# mid-circuit measurement of the outer qubit, then reset
# for the next recursion level
mz(qubits[n - 1 - level])
reset(qubits[n - 1 - level])
mz(qubits)
@cudaq.kernel
def tensor_roll_reconstruct(counts_register: cudaq.qview):
"""Measurement kernel whose counts are classically post-processed
into amplitude estimates (see tensor_roll/qsim.py for the estimator).
Reconstruction itself is classical by construction."""
mz(counts_register)
def run_smoke(n_qubits: int = 4, shots: int = 1024) -> dict:
"""Execute the kernel family on the qpp-cpu simulator target and return
a real invocation summary. Requires the CUDA-Q toolchain."""
if not _HAS_CUDAQ:
raise RuntimeError(
"CUDA-Q toolchain not installed (pip install cudaq). "
"This machine cannot execute these kernels; use the "
"qsim-classical path (tensor-roll qkernel) instead.")
import math
cudaq.set_target("qpp-cpu")
angles = [2.0 * math.atan(0.1 * (i + 1)) for i in range(n_qubits)]
@cudaq.kernel
def _smoke_entry(n_qubits: int, angles: list[float], depth: int):
qubits = cudaq.qvector(n_qubits)
tensor_roll_encode(qubits, angles)
tensor_roll_recursive(qubits, angles, depth)
counts = cudaq.sample(_smoke_entry, n_qubits, angles, 2,
shots_count=shots)
return {"counts": {k: int(v) for k, v in counts.items()},
"shots": shots, "target": cudaq.get_target().name}
if __name__ == "__main__":
try:
print(run_smoke())
except RuntimeError as e:
print(f"unavailable: {e}")
|