// Tensor Roll — Recursive CUDA-Q Model Quantizer // Copyright (C) 2026 SnapKitty Collective // SPDX-License-Identifier: AGPL-3.0-or-later // // Genuine Q# operations for the tensor_roll kernel family. // These mirror cudaq/tensor_roll_kernels.py across the process/IR boundary // documented in docs/BOUNDARIES.md: CUDA-Q kernels emit QIR/MLIR on the // CUDA-Q side; this Q# source is the equivalent family expressed for the // Q# toolchain. There is no direct CUDA-Q <-> Q# linkage — the boundary is // a real serialized artifact (QIR bitcode / measurement-counts JSON), // never an invented API. // // NOTE: not compiled or executed in this repository's test environment // (no Q# toolchain present). Every execution claim in tensor-roll refers // to the classical qsim-classical simulator, explicitly labeled as such. namespace TensorRoll { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Measurement; open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Arrays; /// Encodes a classical tensor block into a qubit register (angle encoding). operation EncodeTensorBlock(block : Double[], register : Qubit[]) : Unit { let n = Length(block) < Length(register) ? Length(block) | Length(register); for i in 0..n - 1 { Ry(2.0 * ArcTan(block[i]), register[i]); } } /// Applies per-qubit RY rotations — the "roll" of the register. operation RollRegister(register : Qubit[], angles : Double[]) : Unit { for i in 0..Length(register) - 1 { Ry(angles[i % Length(angles)], register[i]); } } /// Nearest-neighbour CNOT ladder over the register. operation EntangleRoll(register : Qubit[]) : Unit { for i in 0..Length(register) - 2 { Controlled X([register[i]], register[i + 1]); } } /// Recursive kernel: each level rotates and entangles the active subset, /// measures the outer qubit, resets it, and recurses on the remainder. /// Q# operations may call themselves — this is genuine recursion. /// Returns one measurement Result per recursion level. operation RecursiveRoll(register : Qubit[], angles : Double[], depth : Int) : Result[] { if depth <= 0 or Length(register) == 0 { return []; } RollRegister(register, angles); EntangleRoll(register); let outer = register[Length(register) - 1]; let outcome = MResetZ(outer); let rest = RecursiveRoll(register[0..Length(register) - 2], angles, depth - 1); return [outcome] + rest; } /// Measures the register in the Z basis, resetting each qubit. operation MeasureRoll(register : Qubit[]) : Result[] { mutable results = []; for q in register { set results += [MResetZ(q)]; } return results; } /// Classical reconstruction of amplitude estimates from measurement counts. /// Reconstruction is classical by construction — this function executes on /// the classical host, never on the quantum processor. function ReconstructBlock(counts : (Result[], Int)[], nQubits : Int) : Double[] { mutable total = 0; for (_, c) in counts { set total += c; } let dim = 1 <<< nQubits; mutable amps = [0.0, size = dim]; for (bits, c) in counts { mutable idx = 0; for b in bits { set idx = idx * 2 + (b == One ? 1 | 0); } if idx < dim and total > 0 { set amps w/= idx <- Sqrt(IntAsDouble(c) / IntAsDouble(total)); } } return amps; } @EntryPoint() operation Main() : Unit { // Small demonstration block; mirrors the 8x8-block smoke test that // tensor-roll qkernel runs classically via qsim. let block = [0.1, 0.4, 0.2, 0.8]; use register = Qubit[4]; EncodeTensorBlock(block, register); let rolled = RecursiveRoll(register, [0.3, 0.6, 0.2, 0.9], 2); let tail = MeasureRoll(register); Message($"recursive outcomes: {rolled}"); Message($"tail outcomes: {tail}"); ResetAll(register); } }