| import math |
|
|
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
|
|
| from config import ( |
| EMBEDDING_DIM, |
| MODEL_DIM, |
| PHASE_MODE, |
| PHASE_SOURCE, |
| MIXING, |
| USE_LLM_PRIOR, |
| QUANTUM_DEVICE, |
| ) |
|
|
| from models.validator import HypothesisValidator |
| from models.quantum_layer import QuantumEvolutionLayer |
| from models.classical_control_layer import ClassicalControlLayer |
| from models.persistent_reasoner import PersistentReasoner |
| from models.collapse import CollapseController |
| from models.answer_selector import EnergyAnswerSelector, bounded_phase |
| from models.energy_fusion import EnergyFusion |
| from models.interference import CoherentCollapse |
|
|
| BACKENDS = ("quantum", "classical_control", "none") |
|
|
|
|
| def _masked_zscore(x, mask, eps=1e-5): |
| """Per-sample standardization over the option axis, ignoring padding.""" |
|
|
| m = mask.to(x.dtype) if mask is not None else torch.ones_like(x) |
|
|
| n = m.sum(dim=1, keepdim=True).clamp(min=1.0) |
|
|
| mean = (x * m).sum(dim=1, keepdim=True) / n |
|
|
| var = (((x - mean) ** 2) * m).sum(dim=1, keepdim=True) / n |
|
|
| return ((x - mean) / torch.sqrt(var + eps)) * m |
|
|
|
|
| class QAIRvNext(nn.Module): |
| """ |
| qAIR-v45. |
| |
| Q, H, O -> in_proj (384 -> MODEL_DIM) |
| -> PersistentReasoner (orthogonal mixing) |
| -> Quantum / classical layer (state + energy + PHASE) |
| -> HypothesisValidator (-> potential, fed back) |
| -> EnergyAnswerSelector (E_kn + compatibility phase) |
| -> EnergyFusion (-> E_k) |
| -> CollapseController (per-sample temperature) |
| -> CoherentCollapse (complex amplitudes, |
| |sum_k c_k v_kn|^2) |
| -> + LLM log-prior (optional, ablatable) |
| |
| Three things are different from v44 in ways that matter, all of them |
| responses to specific measured failures rather than tuning: |
| |
| 1. **Width.** v44 ran 10.58M parameters over 800 training examples -- |
| 13,223 per example -- and its best validation accuracy was at |
| epoch 1, declining monotonically after while train loss fell 54%. |
| Everything past `in_proj` now runs at MODEL_DIM (128), roughly 1.1M |
| parameters. Below that ratio, "hypotheses don't help" and "the |
| model memorizes before it learns to use them" are not |
| distinguishable, so no mechanistic claim from v44 was safe. |
| |
| 2. **Evidence channels.** The cache now carries a supporting AND an |
| attacking hypothesis per option, each tagged with its polarity and |
| the option it argues about (`align`). v44's support-only |
| hypotheses were measured at argmax diag(H.O) = 0.2481 against a |
| chance of 0.2500 -- literally zero discriminative signal, because |
| asking a competent LLM to justify all four options gets all four |
| justified. |
| |
| 3. **Genuine interference.** The final distribution is |
| |sum_k c_k v_kn|^2 over complex amplitudes, so hypotheses can |
| cancel. See models/interference.py. `phase_mode="classical"` |
| recovers v44's real-amplitude mixture as a control, and |
| `interference_ratio` is reported every epoch so an inert phase |
| channel shows up as a number rather than hiding behind a plausible |
| accuracy. |
| |
| The LLM log-prior (`use_llm_prior`) deserves its own warning. It adds |
| the generator's own cached per-option log-likelihood to the final |
| score. That is legitimate -- it is the only channel by which the LLM's |
| judgement reaches the answer without being squeezed through a frozen |
| 384-d sentence encoder -- but it also means the model can score well |
| while ignoring every hypothesis. Always read |
| `evaluation/input_ablation.py` alongside accuracy, and always run the |
| `use_llm_prior=False` arm before attributing a gain to reasoning. |
| """ |
|
|
| def __init__( |
| self, |
| dim=EMBEDDING_DIM, |
| model_dim=MODEL_DIM, |
| use_quantum=True, |
| use_validator=True, |
| persistent_steps=3, |
| n_qubits=12, |
| backend=None, |
| use_question=True, |
| validator_feedback=True, |
| keep_trajectory=False, |
| phase_mode=PHASE_MODE, |
| phase_source=PHASE_SOURCE, |
| mixing=MIXING, |
| use_llm_prior=USE_LLM_PRIOR, |
| use_attack=True, |
| quantum_device=QUANTUM_DEVICE, |
| verbose=False, |
| ): |
|
|
| super().__init__() |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if backend is None: |
| backend = "quantum" if use_quantum else "none" |
|
|
| if backend not in BACKENDS: |
| raise ValueError(f"backend must be one of {BACKENDS}, got {backend!r}") |
|
|
| d = model_dim or dim |
|
|
| self.embed_dim = dim |
| self.model_dim = d |
|
|
| self.backend = backend |
| self.use_quantum = backend != "none" |
| self.use_validator = use_validator |
| self.use_question = use_question |
| self.use_llm_prior = use_llm_prior |
| self.use_attack = use_attack |
| self.phase_mode = phase_mode |
| self.phase_source = phase_source |
| self.mixing = mixing |
| self.quantum_device = quantum_device |
| self.persistent_steps = persistent_steps |
|
|
| |
| |
| |
| |
| |
| |
| |
| self.validator_feedback = validator_feedback and use_validator |
|
|
| |
| |
| |
|
|
| if d == dim: |
| self.in_proj = nn.Identity() |
| else: |
| self.in_proj = nn.Sequential(nn.Linear(dim, d), nn.LayerNorm(d)) |
|
|
| |
| |
| |
| self.polarity_embed = nn.Parameter(torch.zeros(d)) |
|
|
| self.reasoner = PersistentReasoner( |
| d, steps=persistent_steps, keep_trajectory=keep_trajectory, |
| mixing=mixing, |
| ) |
|
|
| if backend == "quantum": |
| self.quantum = QuantumEvolutionLayer( |
| d, n_qubits=n_qubits, verbose=verbose, |
| quantum_device=quantum_device, |
| ) |
| elif backend == "classical_control": |
| self.quantum = ClassicalControlLayer(d, n_qubits=n_qubits, verbose=verbose) |
|
|
| if use_validator: |
| self.validator = HypothesisValidator(d, use_question=use_question) |
|
|
| self.selector = EnergyAnswerSelector(d, use_question=use_question) |
|
|
| self.fusion = EnergyFusion() |
|
|
| self.collapse = CollapseController() |
|
|
| self.interference = CoherentCollapse(phase_mode=phase_mode) |
|
|
| |
| |
| |
| self.phase_head = nn.Linear(d, 1) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| self.polarity_phase = nn.Parameter(torch.tensor(math.pi)) |
|
|
| |
| |
| |
| |
| self.llm_prior_weight = nn.Parameter(torch.tensor(-1.0)) |
|
|
| def _run_quantum(self, H): |
|
|
| if H.is_cuda: |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| from torch.amp import autocast |
|
|
| with autocast(device_type="cuda", enabled=False): |
| return self.quantum(H.float()) |
|
|
| return self.quantum(H.float()) |
|
|
| def forward(self, H, O, Q=None, y=None, H_mask=None, O_mask=None, |
| polarity=None, align=None, llm_logprob=None): |
| """ |
| H : (B, K, D_embed) hypothesis embeddings, K = 2N |
| O : (B, N, D_embed) option embeddings |
| Q : (B, D_embed) question embedding |
| y : (B,) labels, training only -- used solely to build |
| the validator's BCE target, never to compute energy |
| H_mask : (B, K) bool, True for real hypotheses |
| O_mask : (B, N) bool, True for real options |
| polarity : (B, K) +1 support / -1 attack |
| align : (B, K, N) 1 where hypothesis k is about option n |
| llm_logprob : (B, N) cached per-option LLM log-likelihood |
| |
| Masks matter: collate_fn pads ragged option/hypothesis counts with |
| zeros, and before the v44 audit those masks were computed and then |
| never passed to the model, so zero-padded options participated in |
| every reduction and could be returned as the argmax prediction. |
| """ |
|
|
| B, K, _ = H.shape |
| N = O.shape[1] |
|
|
| if H_mask is None: |
| H_mask = torch.ones(B, K, dtype=torch.bool, device=H.device) |
|
|
| if O_mask is None: |
| O_mask = torch.ones(B, N, dtype=torch.bool, device=O.device) |
|
|
| if polarity is None: |
| polarity = torch.ones(B, K, device=H.device, dtype=H.dtype) |
|
|
| |
| |
| if not self.use_attack: |
| H_mask = H_mask & (polarity >= 0) |
|
|
| |
| |
| |
|
|
| H = self.in_proj(H) |
| O = self.in_proj(O) |
| Q = self.in_proj(Q) if Q is not None else None |
|
|
| H = H + polarity.unsqueeze(-1) * self.polarity_embed |
|
|
| H = H * H_mask.unsqueeze(-1).to(H.dtype) |
|
|
| |
| |
| |
|
|
| H, trajectory, interaction = self.reasoner(H, mask=H_mask) |
|
|
| quantum_energy = None |
| quantum_phase = None |
|
|
| if self.use_quantum: |
|
|
| q_state, quantum_energy, quantum_phase = self._run_quantum(H) |
|
|
| H = H + q_state |
|
|
| validator_out = None |
| validator_energy = None |
| potential = None |
|
|
| if self.use_validator: |
|
|
| validator_out = self.validator( |
| H, O, Q=Q, y=y, H_mask=H_mask, O_mask=O_mask, |
| align=align, polarity=polarity, |
| ) |
|
|
| potential = validator_out["potential"] |
|
|
| validator_energy = validator_out["validator_energy"] |
|
|
| if self.validator_feedback: |
|
|
| |
| |
| |
| H, trajectory2, interaction = self.reasoner( |
| H, potential=potential, mask=H_mask |
| ) |
|
|
| trajectory = trajectory + trajectory2 |
|
|
| if self.use_quantum: |
| q_state, quantum_energy, quantum_phase = self._run_quantum(H) |
| H = H + q_state |
|
|
| validator_out = self.validator( |
| H, O, Q=Q, y=y, H_mask=H_mask, O_mask=O_mask, |
| align=align, polarity=polarity, |
| ) |
|
|
| potential = validator_out["potential"] |
|
|
| validator_energy = validator_out["validator_energy"] |
|
|
| |
| |
| |
|
|
| selector = self.selector( |
| H, O, Q=Q, align=align, polarity=polarity, |
| H_mask=H_mask, O_mask=O_mask, |
| ) |
|
|
| answer_energy = selector["energy"] |
|
|
| collapse_energy = self.fusion( |
| answer_energy, |
| quantum_energy=quantum_energy, |
| validator_energy=validator_energy, |
| option_mask=O_mask, |
| ) |
|
|
| collapse_out = self.collapse(collapse_energy, mask=H_mask) |
|
|
| |
| |
| |
|
|
| if self.phase_source == "circuit" and quantum_phase is not None: |
| phase_h = quantum_phase |
| else: |
| phase_h = bounded_phase(self.phase_head(H).squeeze(-1)) |
|
|
| |
| phase_h = phase_h + 0.5 * (1.0 - polarity) * self.polarity_phase |
|
|
| phase_h = phase_h * H_mask.to(phase_h.dtype) |
|
|
| |
| |
| |
|
|
| coherent = self.interference( |
| collapse_energy, |
| answer_energy, |
| phase_h=phase_h, |
| phase_kn=selector["phase"], |
| H_mask=H_mask, |
| O_mask=O_mask, |
| hyp_temperature=collapse_out["temperature"], |
| ) |
|
|
| scores = coherent["log_probs"] |
|
|
| |
| |
| |
|
|
| llm_term = None |
|
|
| if self.use_llm_prior and llm_logprob is not None: |
|
|
| |
| |
| |
| |
| llm_term = _masked_zscore(llm_logprob, O_mask) |
|
|
| scores = scores + F.softplus(self.llm_prior_weight) * llm_term |
|
|
| |
| |
| neg_inf = torch.finfo(scores.dtype).min / 2 |
| scores = scores.masked_fill(~O_mask, neg_inf) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| scores = torch.log_softmax(scores, dim=1).clamp(min=-30.0) |
|
|
| collapse_probs = coherent["collapse_probs"] |
|
|
| entropy = -( |
| collapse_probs * torch.log(collapse_probs + 1e-8) |
| ).sum(dim=1).mean() |
|
|
| return { |
| "scores": scores, |
| "answer_energy": answer_energy, |
| "collapse_energy": collapse_energy, |
| "collapse_probs": collapse_probs, |
| "quantum_energy": quantum_energy, |
| "quantum_phase": quantum_phase, |
| "phase_h": phase_h, |
| "phase_kn": selector["phase"], |
| "interference": coherent["interference"], |
| "interference_ratio": coherent["interference_ratio"], |
| "phase_effect": coherent["phase_effect"], |
| "destructive_fraction": coherent["destructive_fraction"], |
| "coherent_contrast": coherent["coherent_contrast"], |
| "classical_weights": coherent["classical"], |
| "coherent_weights": coherent["coherent"], |
| "llm_prior": llm_term, |
| "llm_prior_weight": F.softplus(self.llm_prior_weight).detach(), |
| "entropy": entropy, |
| "diversity": collapse_out["diversity"], |
| "spread": collapse_out["spread"], |
| "peak": collapse_probs.max(dim=1).values.mean(), |
| "collapse_confidence": collapse_out["confidence"], |
| "validator_potential": potential, |
| "trajectory": trajectory, |
| "attention": interaction, |
| "validator": validator_out, |
| "H_mask": H_mask, |
| "O_mask": O_mask, |
| |
| |
| |
| |
| "H_reasoned": H, |
| } |
|
|