Download quantum/include/QuantumOps.td from Snapkitty/nvidia-stack: direct link, hf CLI and curl.
- Browser
- Download file 10.7 kB
-
https://huggingface.co/Snapkitty/nvidia-stack/resolve/main/quantum/include/QuantumOps.td
- Command line
-
hf download hf://Snapkitty/nvidia-stack/quantum/include/QuantumOps.td
-
curl -L -o QuantumOps.td https://huggingface.co/Snapkitty/nvidia-stack/resolve/main/quantum/include/QuantumOps.td
10.7 kB
| // ============================================================ | |
| // QuantumOps.td — Operation definitions for the #q quantum dialect | |
| // ============================================================ | |
| // Covers: alloc, unitary, entangle, measure, reset, concat, extract. | |
| // Linear-type discipline enforced via traits + verifier. | |
| #ifndef QUANTUM_OPS | |
| #define QUANTUM_OPS | |
| include "QuantumDialect.td" | |
| include "QuantumTypes.td" | |
| include "mlir/Interfaces/SideEffectInterfaces.td" | |
| // ============================================================ | |
| // Traits | |
| // ============================================================ | |
| // Enforce no-cloning: every !quantum.qubit SSA value must have | |
| // exactly one use (consumed by unitary, entangle, or measure). | |
| def Quantum_NoCloning : NativeOpTrait<"NoCloning"> { | |
| let cppNamespace = "::mlir::quantum"; | |
| } | |
| // ============================================================ | |
| // Allocation Operations | |
| // ============================================================ | |
| def Quantum_AllocOp : Quantum_Op<"alloc", [ | |
| MemoryEffects<[MemAlloc]>, | |
| DeclareOpInterfaceMethods<InferTypeOpInterface>, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Allocate a clean qubit or qureg"; | |
| let description = [{ | |
| Allocates a fresh qubit or register in the |0⟩ state. | |
| The result type determines the allocation: | |
| !quantum.qubit → single qubit | |
| !quantum.qureg<N> → register of N qubits | |
| !quantum.qureg<?> → dynamic-size register | |
| The allocated resource must be consumed by a unitary, entangle, | |
| or measure operation before the function returns. The verifier | |
| rejects dangling allocations (no-cloning trait). | |
| }]; | |
| let arguments = (ins Optional<I64>:$size); | |
| let results = (outs AnyTypeOf<[Quantum_QubitType, Quantum_QuregType]>:$result); | |
| let assemblyFormat = "($size^)? attr-dict `:` type($result)"; | |
| let hasVerifier = 1; | |
| } | |
| def Quantum_AllocWithStateOp : Quantum_Op<"alloc_with_state", [ | |
| MemoryEffects<[MemAlloc]>, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Allocate qubits with a specific initial state"; | |
| let description = [{ | |
| Allocates a qubit or register initialized to a user-specified | |
| state vector. The state must be normalized. | |
| This mirrors the CUDA-Q RAII allocation with initialisation: | |
| qubit q = cudaq::qrt::qubit_alloca(initialState); | |
| The verifier checks that the state length matches the allocation | |
| size (2^N for N qubits). | |
| }]; | |
| let arguments = (ins | |
| AnyTypeOf<[Quantum_QubitType, Quantum_QuregType]>:$qubits, | |
| Attribute:$state // DenseComplexFPElementsAttr | |
| ); | |
| let results = (outs AnyTypeOf<[Quantum_QubitType, Quantum_QuregType]>:$result); | |
| let assemblyFormat = [{ | |
| $qubits `with` $state attr-dict `:` type($result) | |
| }]; | |
| } | |
| // ============================================================ | |
| // Unitary Operations | |
| // ============================================================ | |
| def Quantum_UnitaryOp : Quantum_Op<"unitary", [ | |
| NoMemoryEffect, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Parametrised multi-axis rotation (exact algebraic angles)"; | |
| let description = [{ | |
| Applies a parametrised unitary to one or more qubits. | |
| The angles are stored as exact algebraic values (rational or | |
| symbolic), not floating-point approximations. This enables: | |
| - Exact Clifford+T synthesis | |
| - Symbolic gradient computation for variational algorithms | |
| - Noise-aware compilation with precision guarantees | |
| The axis parameter selects the rotation axis: | |
| "X" → R_x(θ) = exp(-iθ/2 · σ_x) | |
| "Y" → R_y(θ) = exp(-iθ/2 · σ_y) | |
| "Z" → R_z(θ) = exp(-iθ/2 · σ_z) | |
| "arbitrary" → arbitrary single-qubit unitary | |
| Examples: | |
| quantum.unitary %q [0.5] axis "Y" // H gate (θ=π/2) | |
| quantum.unitary %q [0.25] // T gate (θ=π/4) | |
| quantum.unitary %q [0.125, 0.5, 0.0] // U3 gate | |
| }]; | |
| let arguments = (ins | |
| Variadic<Quantum_QubitType>:$qubits, | |
| ArrayAttr:$angles, // e.g. [89/2462, ...] | |
| OptionalAttr<StrAttr>:$axis // "X","Y","Z","arbitrary" | |
| ); | |
| let results = (outs Variadic<Quantum_QubitType>:$results); // linear consumption | |
| let assemblyFormat = [{ | |
| $qubits `(` $angles `)` (`axis` $axis^)? | |
| attr-dict `:` functional-type($qubits, $results) | |
| }]; | |
| let hasVerifier = 1; // enforce angle domain, no-cloning | |
| } | |
| // ============================================================ | |
| // Entangle Operations (controlled gates) | |
| // ============================================================ | |
| def Quantum_EntangleOp : Quantum_Op<"entangle", [ | |
| NoMemoryEffect, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Multi-qubit controlled operation (CNOT, Toffoli, CPhase, ...)"; | |
| let description = [{ | |
| Controlled operation acting on control and target qubits. | |
| This is the universal controlled gate. The base gate is | |
| determined by the number of targets and optional phases: | |
| 1 target, no phases → CNOT (X) or controlled-U | |
| 1 target, phase π → CZ (Z) | |
| 2 targets → Toffoli (CCX) or Fredkin (CSWAP) | |
| The adjoint flag negates all angles for parameterised gates | |
| and reverses the gate sequence for non-parameterised gates. | |
| Linear-type discipline: all input qubits are consumed and | |
| replaced by output qubits in the same positions. | |
| }]; | |
| let arguments = (ins | |
| Variadic<Quantum_QubitType>:$controls, | |
| Variadic<Quantum_QubitType>:$targets, | |
| OptionalAttr<ArrayAttr>:$phases, // for controlled-phase | |
| UnitAttr:$is_adj | |
| ); | |
| let results = (outs | |
| Variadic<Quantum_QubitType>:$out_controls, | |
| Variadic<Quantum_QubitType>:$out_targets | |
| ); | |
| let assemblyFormat = [{ | |
| (`adj` $is_adj^)? `[` $controls `]` $targets | |
| (`phases` $phases^)? | |
| attr-dict `:` functional-type(operands, results) | |
| }]; | |
| let hasVerifier = 1; | |
| } | |
| // ============================================================ | |
| // Measurement Operations | |
| // ============================================================ | |
| def Quantum_MeasureOp : Quantum_Op<"measure", [ | |
| MemoryEffects<[MemRead, MemWrite]>, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Collapse amplitude vector into classical bits"; | |
| let description = [{ | |
| Measures the specified qubits in the computational (Z) basis. | |
| Returns: | |
| - A classical bit (i1) for each measured qubit | |
| - The post-measurement qubit state (consumed, cannot be reused | |
| without a fresh allocation) | |
| The optional registerName attaches metadata for classical | |
| control flow (e.g. "c" for the full register, "q0" for a | |
| single qubit). | |
| This mirrors the CUDA-Q QuakeToLLVM measurement pattern: | |
| %r = call %Result* @__quantum__qis__mz(%Qubit* %q) | |
| %bit = trunc %r to i1 | |
| }]; | |
| let arguments = (ins | |
| Variadic<Quantum_QubitType>:$qubits, | |
| OptionalAttr<StrAttr>:$registerName | |
| ); | |
| let results = (outs | |
| Variadic<I1>:$bits, // classical results | |
| Variadic<Quantum_QubitType>:$collapsed // post-measurement state | |
| ); | |
| let assemblyFormat = [{ | |
| $qubits (`->` $registerName^)? | |
| attr-dict `:` functional-type($qubits, results) | |
| }]; | |
| let hasVerifier = 1; | |
| } | |
| // ============================================================ | |
| // Register Operations | |
| // ============================================================ | |
| def Quantum_ConcatOp : Quantum_Op<"concat", [ | |
| NoMemoryEffect, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Concatenate two quregs into one"; | |
| let arguments = (ins | |
| Quantum_QuregType:$left, | |
| Quantum_QuregType:$right | |
| ); | |
| let results = (outs Quantum_QuregType:$result); | |
| let assemblyFormat = [{ | |
| $left `,` $right attr-dict `:` type($result) | |
| }]; | |
| } | |
| def Quantum_ExtractRefOp : Quantum_Op<"extract_ref", [ | |
| NoMemoryEffect, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Extract a single qubit from a qureg by index"; | |
| let arguments = (ins | |
| Quantum_QuregType:$source, | |
| IntegerAttr<I64>:$index | |
| ); | |
| let results = (outs Quantum_QubitType:$result); | |
| let assemblyFormat = [{ | |
| $source `[` $index `]` attr-dict `:` type($result) | |
| }]; | |
| let hasVerifier = 1; // bounds check | |
| } | |
| def Quantum_SubveqOp : Quantum_Op<"subveq", [ | |
| NoMemoryEffect, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Extract a contiguous sub-register"; | |
| let arguments = (ins | |
| Quantum_QuregType:$source, | |
| IntegerAttr<I64>:$low, | |
| IntegerAttr<I64>:$high | |
| ); | |
| let results = (outs Quantum_QuregType:$result); | |
| let assemblyFormat = [{ | |
| $source `[` $low `:` $high `]` attr-dict `:` type($result) | |
| }]; | |
| let hasVerifier = 1; // bounds check, low < high | |
| } | |
| def Quantum_VeqSizeOp : Quantum_Op<"veq_size", [ | |
| Pure | |
| ]> { | |
| let summary = "Return the size of a qureg"; | |
| let arguments = (ins Quantum_QuregType:$source); | |
| let results = (outs I64:$size); | |
| let assemblyFormat = [{ | |
| $source attr-dict `:` type($size) | |
| }]; | |
| } | |
| // ============================================================ | |
| // Reset Operation | |
| // ============================================================ | |
| def Quantum_ResetOp : Quantum_Op<"reset", [ | |
| MemoryEffects<[MemWrite]>, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Reset qubit to |0⟩ without measurement"; | |
| let arguments = (ins Quantum_QubitType:$target); | |
| let results = (outs Quantum_QubitType:$result); | |
| let assemblyFormat = [{ | |
| $target attr-dict `:` type($result) | |
| }]; | |
| } | |
| // ============================================================ | |
| // Exp Pauli (exponentiation of Pauli string) | |
| // ============================================================ | |
| def Quantum_ExpPauliOp : Quantum_Op<"exp_pauli", [ | |
| NoMemoryEffect, | |
| Quantum_NoCloning | |
| ]> { | |
| let summary = "Exponentiation of a Pauli string: exp(-iθ/2 · P)"; | |
| let description = [{ | |
| Applies exp(-iθ/2 · P) where P is a tensor product of Pauli | |
| operators (X, Y, Z, I) on the specified qubits. | |
| This is the native gate for: | |
| - QAOA cost Hamiltonian evolution | |
| - Variational quantum eigensolver (VQE) ansatz | |
| - Suzuki-Trotter decomposition of molecular Hamiltonians | |
| The pauli string is encoded as a dense integer array: | |
| 0 = I, 1 = X, 2 = Y, 3 = Z | |
| Example: | |
| // e^{-iθ/2 · X⊗Z} on q0, q1 | |
| quantum.exp_pauli %q0, %q1 [1, 3] for θ = 0.5 | |
| }]; | |
| let arguments = (ins | |
| Variadic<Quantum_QubitType>:$qubits, | |
| DenseI32ArrayAttr:$pauli, // Pauli string encoding | |
| AnyAttr:$theta // angle (rational or float) | |
| ); | |
| let results = (outs Variadic<Quantum_QubitType>:$results); | |
| let assemblyFormat = [{ | |
| $qubits `(` $pauli `)` `for` $theta | |
| attr-dict `:` functional-type($qubits, $results) | |
| }]; | |
| let hasVerifier = 1; // pauli length == qubit count | |
| } | |
| #endif // QUANTUM_OPS | |