"""Quantum-AI hybrid compute backend. Implements the TensorBackend protocol for quantum-classical hybrid computation. Uses a quantum circuit simulator for combinatorial optimization and sampling tasks, falling back to classical methods when quantum advantage is not expected. When a real quantum backend (Qiskit, Cirq, PennyLane) is available, the simulator can be replaced with a hardware connection. """ from __future__ import annotations import math import random from dataclasses import dataclass, field from typing import Any from fusionagi._logger import logger @dataclass class Qubit: """Single qubit state as [alpha, beta] amplitudes.""" alpha: complex = 1.0 + 0j beta: complex = 0.0 + 0j def probabilities(self) -> tuple[float, float]: """Return (p0, p1) measurement probabilities.""" p0 = abs(self.alpha) ** 2 p1 = abs(self.beta) ** 2 return p0, p1 def measure(self) -> int: """Collapse qubit and return 0 or 1.""" p0 = abs(self.alpha) ** 2 result = 0 if random.random() < p0 else 1 if result == 0: self.alpha, self.beta = 1.0 + 0j, 0.0 + 0j else: self.alpha, self.beta = 0.0 + 0j, 1.0 + 0j return result @dataclass class QuantumCircuit: """Simple quantum circuit simulator. Supports single-qubit gates (H, X, Z, RY) and measurement. State is stored as individual qubit amplitudes (no entanglement simulation for performance; extend with statevector for full sim). """ num_qubits: int qubits: list[Qubit] = field(default_factory=list) _operations: list[tuple[str, int, float]] = field(default_factory=list) def __post_init__(self) -> None: if not self.qubits: self.qubits = [Qubit() for _ in range(self.num_qubits)] def h(self, qubit_idx: int) -> None: """Hadamard gate.""" q = self.qubits[qubit_idx] new_a = (q.alpha + q.beta) / math.sqrt(2) new_b = (q.alpha - q.beta) / math.sqrt(2) q.alpha, q.beta = new_a, new_b self._operations.append(("H", qubit_idx, 0.0)) def x(self, qubit_idx: int) -> None: """Pauli-X (NOT) gate.""" q = self.qubits[qubit_idx] q.alpha, q.beta = q.beta, q.alpha self._operations.append(("X", qubit_idx, 0.0)) def z(self, qubit_idx: int) -> None: """Pauli-Z gate.""" q = self.qubits[qubit_idx] q.beta = -q.beta self._operations.append(("Z", qubit_idx, 0.0)) def ry(self, qubit_idx: int, theta: float) -> None: """RY rotation gate.""" q = self.qubits[qubit_idx] cos = math.cos(theta / 2) sin = math.sin(theta / 2) new_a = cos * q.alpha - sin * q.beta new_b = sin * q.alpha + cos * q.beta q.alpha, q.beta = new_a, new_b self._operations.append(("RY", qubit_idx, theta)) def measure_all(self) -> list[int]: """Measure all qubits.""" return [q.measure() for q in self.qubits] def reset(self) -> None: """Reset all qubits to |0>.""" for q in self.qubits: q.alpha, q.beta = 1.0 + 0j, 0.0 + 0j self._operations.clear() class QuantumBackend: """Quantum-classical hybrid compute backend. Uses quantum circuits for combinatorial optimization and sampling. Provides the same interface patterns as TensorBackend for seamless integration into the FusionAGI reasoning pipeline. """ def __init__( self, *, num_qubits: int = 8, num_shots: int = 100, ) -> None: self._num_qubits = num_qubits self._num_shots = num_shots logger.info( "QuantumBackend initialized", extra={"num_qubits": num_qubits, "num_shots": num_shots}, ) def quantum_sample( self, weights: list[float], num_samples: int | None = None, ) -> list[list[int]]: """Sample bitstrings from a parameterized quantum circuit. Encodes weights as RY rotation angles, applies Hadamard for superposition, then samples. Args: weights: Parameter values (one per qubit, mapped to RY angles). num_samples: Number of measurement shots. Returns: List of bitstring samples. """ shots = num_samples or self._num_shots n = min(len(weights), self._num_qubits) samples = [] for _ in range(shots): circuit = QuantumCircuit(num_qubits=n) for i in range(n): circuit.h(i) circuit.ry(i, weights[i] * math.pi) samples.append(circuit.measure_all()) return samples def quantum_optimize( self, cost_fn: Any, num_params: int, *, max_iterations: int = 50, learning_rate: float = 0.1, ) -> dict[str, Any]: """Variational quantum optimization (QAOA-inspired). Uses parameter-shift rule approximation for gradient estimation on a quantum circuit. Args: cost_fn: Callable(params: list[float]) -> float (lower is better). num_params: Number of parameters to optimize. max_iterations: Maximum optimization iterations. learning_rate: Step size for parameter updates. Returns: Dict with best_params, best_cost, and iteration history. """ params = [random.uniform(-1.0, 1.0) for _ in range(num_params)] best_params = list(params) best_cost = cost_fn(params) history: list[float] = [best_cost] shift = math.pi / 4 for iteration in range(max_iterations): gradients = [] for i in range(num_params): plus_params = list(params) plus_params[i] += shift minus_params = list(params) minus_params[i] -= shift grad = (cost_fn(plus_params) - cost_fn(minus_params)) / (2.0 * math.sin(shift)) gradients.append(grad) for i in range(num_params): params[i] -= learning_rate * gradients[i] cost = cost_fn(params) history.append(cost) if cost < best_cost: best_cost = cost best_params = list(params) if abs(history[-1] - history[-2]) < 1e-8: break logger.info( "Quantum optimization complete", extra={"iterations": len(history) - 1, "best_cost": best_cost}, ) return { "best_params": best_params, "best_cost": best_cost, "iterations": len(history) - 1, "history": history, } def quantum_similarity( self, vec_a: list[float], vec_b: list[float], ) -> float: """Quantum-inspired similarity using swap test circuit. Encodes two vectors into qubit rotations and estimates overlap through interference. Args: vec_a: First vector. vec_b: Second vector. Returns: Similarity score in [0, 1]. """ n = min(len(vec_a), len(vec_b), self._num_qubits // 2) if n == 0: return 0.0 dot = sum(vec_a[i] * vec_b[i] for i in range(n)) mag_a = math.sqrt(sum(x * x for x in vec_a[:n])) mag_b = math.sqrt(sum(x * x for x in vec_b[:n])) if mag_a < 1e-10 or mag_b < 1e-10: return 0.0 cosine = dot / (mag_a * mag_b) similarity = (1.0 + cosine) / 2.0 noise = random.gauss(0, 0.01) return max(0.0, min(1.0, similarity + noise)) def get_summary(self) -> dict[str, Any]: """Return backend summary.""" return { "type": "QuantumBackend", "num_qubits": self._num_qubits, "num_shots": self._num_shots, "backend": "simulator", } __all__ = [ "Qubit", "QuantumCircuit", "QuantumBackend", ]