From 29fd8b19745d251e16e0c975380fc4158b3a76ba Mon Sep 17 00:00:00 2001 From: "Jorge A. Garcia" <681013+jagg-ix@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:45:00 -0600 Subject: [PATCH] feat(M11.2-M11.4): combine Liouville tensor, QDO interactions, and optional QCD --- .../m11_cat_ept_soliton_qdo/__init__.py | 14 +- .../formal/liouville_soliton_tensor.v1.json | 19 ++ .../formal/optional_qcd_coupling.v1.json | 15 ++ .../formal/qdo_lj_atm_interaction.v1.json | 21 ++ .../liouville_soliton_tensor_m112.py | 198 +++++++++++++++ .../optional_qcd_coupling_m114.py | 229 +++++++++++++++++ .../qdo_lj_atm_interaction_m113.py | 231 ++++++++++++++++++ .../research/zil/m11_liouville_tensor_m112.zc | 6 + .../research/zil/m11_optional_qcd_m114.zc | 7 + .../research/zil/m11_qdo_lj_atm_m113.zc | 8 + tests/test_m11_liouville_tensor_m112.py | 6 + tests/test_m11_optional_qcd_m114.py | 5 + tests/test_m11_qdo_lj_atm_m113.py | 6 + 13 files changed, 760 insertions(+), 5 deletions(-) create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/formal/liouville_soliton_tensor.v1.json create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/formal/optional_qcd_coupling.v1.json create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/formal/qdo_lj_atm_interaction.v1.json create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/liouville_soliton_tensor_m112.py create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/optional_qcd_coupling_m114.py create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/qdo_lj_atm_interaction_m113.py create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_liouville_tensor_m112.zc create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_optional_qcd_m114.zc create mode 100644 openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_qdo_lj_atm_m113.zc create mode 100644 tests/test_m11_liouville_tensor_m112.py create mode 100644 tests/test_m11_optional_qcd_m114.py create mode 100644 tests/test_m11_qdo_lj_atm_m113.py diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/__init__.py b/openwave/xperiments/m11_cat_ept_soliton_qdo/__init__.py index fa547d56..966342d2 100644 --- a/openwave/xperiments/m11_cat_ept_soliton_qdo/__init__.py +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/__init__.py @@ -1,9 +1,13 @@ """M11 CAT/EPT pointwise soliton--Liouville--QDO particle model.""" -from .pointwise_soliton_carrier_m111 import ( - PointwiseSolitonConfig, PointwiseSolitonState, - construct_pointwise_soliton, run_pointwise_soliton_study, -) +from .pointwise_soliton_carrier_m111 import PointwiseSolitonConfig, PointwiseSolitonState, construct_pointwise_soliton, run_pointwise_soliton_study +from .liouville_soliton_tensor_m112 import LiouvilleTensorConfig, LiouvilleTensorState, construct_liouville_tensor, run_liouville_tensor_study +from .qdo_lj_atm_interaction_m113 import QDOLJATMConfig, run_qdo_lj_atm_study +from .optional_qcd_coupling_m114 import OptionalQCDConfig, run_optional_qcd_study __all__ = [ "PointwiseSolitonConfig", "PointwiseSolitonState", - "construct_pointwise_soliton", "run_pointwise_soliton_study", + "LiouvilleTensorConfig", "LiouvilleTensorState", "QDOLJATMConfig", + "OptionalQCDConfig", "construct_pointwise_soliton", + "run_pointwise_soliton_study", "construct_liouville_tensor", + "run_liouville_tensor_study", "run_qdo_lj_atm_study", + "run_optional_qcd_study", ] diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/liouville_soliton_tensor.v1.json b/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/liouville_soliton_tensor.v1.json new file mode 100644 index 00000000..b59ed678 --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/liouville_soliton_tensor.v1.json @@ -0,0 +1,19 @@ +{ + "schema": "openwave.m11.liouville-soliton-tensor-ledger.v1", + "model_id": "M11", + "milestone": "M11.2", + "formal_repository": "jagg-ix/entropic-physlib-private", + "formal_branch": "entropic-physlib-linear-full", + "formal_head": "8bafa9ab93cbb39e85909fc3837bb4b6e0dec748", + "equations": [ + {"id": "pure-density-tensor", "equation": "rho_ij=a_i conjugate(a_j)", "numerical_source": "construct_liouville_tensor"}, + {"id": "pointwise-actions", "equation": "L_a R_b rho=R_b L_a rho", "formal_theorem": "leftPointwise_rightPointwise_commute"}, + {"id": "fixed-particle-sector", "equation": "sum_k n_k=N", "formal_theorem": "kernelOccupationBasis_particleNumber"} + ], + "formal_sources": [ + {"path": "Physlib/QuantumMechanics/OpenSystems/LiouvilleSecondQuantization.lean", "sha": "9d2c905c940480f1ed570cf0be965d5a9b6c4831", "theorem": "leftPointwise_rightPointwise_commute"}, + {"path": "Physlib/QuantumMechanics/OpenSystems/LiouvilleSecondQuantization.lean", "sha": "9d2c905c940480f1ed570cf0be965d5a9b6c4831", "theorem": "kernelMode_infinite"}, + {"path": "Physlib/QuantumMechanics/OpenSystems/LiouvilleSecondQuantization.lean", "sha": "9d2c905c940480f1ed570cf0be965d5a9b6c4831", "theorem": "kernelOccupationBasis_particleNumber"}, + {"path": "Physlib/QuantumMechanics/OpenSystems/LiouvilleSecondQuantization.lean", "sha": "9d2c905c940480f1ed570cf0be965d5a9b6c4831", "theorem": "continuumKernelNormSq_nonneg"} + ] +} diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/optional_qcd_coupling.v1.json b/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/optional_qcd_coupling.v1.json new file mode 100644 index 00000000..3698e00c --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/optional_qcd_coupling.v1.json @@ -0,0 +1,15 @@ +{ + "schema": "openwave.m11.optional-qcd-coupling-ledger.v1", + "model_id": "M11", + "milestone": "M11.4", + "formal_repository": "jagg-ix/entropic-physlib-private", + "formal_branch": "entropic-physlib-linear-full", + "formal_head": "8bafa9ab93cbb39e85909fc3837bb4b6e0dec748", + "reuses": ["M10.5", "M10.6", "M10.7"], + "formal_sources": [ + {"path": "Physlib/QuantumMechanics/ComplexAction/YangMillsGaugeDynamics.lean", "sha": "4fe7ae3471057b5c7b64fc22705d76f854d66766", "theorem": "yangMillsEquation_gauge_covariant"}, + {"path": "Physlib/QuantumMechanics/ComplexAction/Particles/GellMannStructureConstants.lean", "sha": "b721ea5e04a72430a81d84c6a0a6c20b3f9558a0", "theorem": "gellMann_structure_constants"}, + {"path": "Physlib/QuantumMechanics/ComplexAction/Particles/SuNGaugeSector.lean", "sha": "4585ddf9bc44396b5f9dce14321c4d6b2826cb8a", "theorem": "su3_adjoint_eq_gluonCount"}, + {"path": "Physlib/QuantumMechanics/ComplexAction/HorizonCell/QCDComplexActionUnification.lean", "sha": "c5d7108ec4781eee3068898d0d844b689230a6fa", "theorem": "qcd_theta_confinement_factorization"} + ] +} diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/qdo_lj_atm_interaction.v1.json b/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/qdo_lj_atm_interaction.v1.json new file mode 100644 index 00000000..37600b4b --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/formal/qdo_lj_atm_interaction.v1.json @@ -0,0 +1,21 @@ +{ + "schema": "openwave.m11.qdo-lj-atm-interaction-ledger.v1", + "model_id": "M11", + "milestone": "M11.3", + "formal_repository": "jagg-ix/entropic-physlib-private", + "formal_branch": "entropic-physlib-linear-full", + "formal_head": "8bafa9ab93cbb39e85909fc3837bb4b6e0dec748", + "equations": [ + {"id": "lj-split", "equation": "E_LJ=ljRepulsive-ljAttractive", "formal_theorem": "ljPotential_split"}, + {"id": "lj-tail", "equation": "-ljAttractive=-C6_LJ/r^6", "formal_theorem": "lj_tail_dispersion_form"}, + {"id": "qdo-c6", "equation": "C6_LJ=C6_QDO=3/4 alpha1^2 hbar omega", "formal_theorem": "lj_tail_is_qdo_C6"}, + {"id": "qdo-c9", "equation": "alpha1 C6=4 C9", "formal_theorem": "lattice_couplings_qdo_related"} + ], + "formal_sources": [ + {"path": "Physlib/QuantumMechanics/ComplexAction/Particles/LennardJonesAxilrodTeller.lean", "sha": "93f5e1b55d1fbfe44dc5b8106b7331d08bdb5159", "theorem": "ljPotential_split"}, + {"path": "Physlib/QuantumMechanics/ComplexAction/Particles/LennardJonesAxilrodTeller.lean", "sha": "93f5e1b55d1fbfe44dc5b8106b7331d08bdb5159", "theorem": "lj_tail_dispersion_form"}, + {"path": "Physlib/QuantumMechanics/ComplexAction/Particles/LennardJonesAxilrodTeller.lean", "sha": "93f5e1b55d1fbfe44dc5b8106b7331d08bdb5159", "theorem": "lj_tail_eq_vdw_dispersionEnergy"}, + {"path": "Physlib/QuantumMechanics/ComplexAction/Particles/LennardJonesAxilrodTeller.lean", "sha": "93f5e1b55d1fbfe44dc5b8106b7331d08bdb5159", "theorem": "lj_tail_is_qdo_C6"}, + {"path": "Physlib/QuantumMechanics/ComplexAction/Particles/LennardJonesAxilrodTeller.lean", "sha": "93f5e1b55d1fbfe44dc5b8106b7331d08bdb5159", "theorem": "lattice_couplings_qdo_related"} + ] +} diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/liouville_soliton_tensor_m112.py b/openwave/xperiments/m11_cat_ept_soliton_qdo/liouville_soliton_tensor_m112.py new file mode 100644 index 00000000..68e4830e --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/liouville_soliton_tensor_m112.py @@ -0,0 +1,198 @@ +"""M11.2 continuum/infinite-mode Liouville tensor of the M11.1 soliton.""" +from __future__ import annotations + +from dataclasses import asdict, dataclass +from hashlib import sha256 +import json +from typing import Any, Mapping + +import numpy as np + +from .pointwise_soliton_carrier_m111 import ( + PointwiseSolitonConfig, + construct_pointwise_soliton, +) + +MILESTONE = "M11.2" +SCHEMA = "openwave.m11.liouville-soliton-tensor.v1" +FORMAL_HEAD = "8bafa9ab93cbb39e85909fc3837bb4b6e0dec748" +FORMAL_SOURCES = ( + { + "path": "Physlib/QuantumMechanics/OpenSystems/LiouvilleSecondQuantization.lean", + "sha": "9d2c905c940480f1ed570cf0be965d5a9b6c4831", + "theorem": "leftPointwise_rightPointwise_commute", + }, + { + "path": "Physlib/QuantumMechanics/OpenSystems/LiouvilleSecondQuantization.lean", + "sha": "9d2c905c940480f1ed570cf0be965d5a9b6c4831", + "theorem": "kernelMode_infinite", + }, + { + "path": "Physlib/QuantumMechanics/OpenSystems/LiouvilleSecondQuantization.lean", + "sha": "9d2c905c940480f1ed570cf0be965d5a9b6c4831", + "theorem": "kernelOccupationBasis_particleNumber", + }, + { + "path": "Physlib/QuantumMechanics/OpenSystems/LiouvilleSecondQuantization.lean", + "sha": "9d2c905c940480f1ed570cf0be965d5a9b6c4831", + "theorem": "continuumKernelNormSq_nonneg", + }, +) + + +def _canonical_json(value: Mapping[str, Any]) -> str: + return json.dumps(value, sort_keys=True, separators=(",", ":"), default=str) + + +@dataclass(frozen=True) +class LiouvilleTensorConfig: + mode_count: int = 96 + refinement_modes: tuple[int, ...] = (16, 32, 64, 96) + particle_number: int = 3 + + def validate(self, grid_points: int) -> None: + if self.mode_count < 8 or self.mode_count > grid_points: + raise ValueError("mode_count must fit inside the pointwise grid") + if any(mode < 4 or mode > self.mode_count for mode in self.refinement_modes): + raise ValueError("refinement modes must lie in [4, mode_count]") + if tuple(sorted(self.refinement_modes)) != self.refinement_modes: + raise ValueError("refinement modes must be increasing") + if self.particle_number < 0: + raise ValueError("particle number must be nonnegative") + + +@dataclass(frozen=True) +class LiouvilleTensorState: + config: LiouvilleTensorConfig + full_amplitudes: np.ndarray + selected_indices: np.ndarray + amplitudes: np.ndarray + density_matrix: np.ndarray + retained_probability: float + + +def _centered_indices(length: int, count: int) -> np.ndarray: + shifted = np.arange(length) - length // 2 + order = np.argsort(np.abs(shifted), kind="stable") + return np.sort(order[:count]) + + +def construct_liouville_tensor( + config: LiouvilleTensorConfig | None = None, + soliton_config: PointwiseSolitonConfig | None = None, +) -> LiouvilleTensorState: + cfg = LiouvilleTensorConfig() if config is None else config + soliton = construct_pointwise_soliton(soliton_config) + cfg.validate(soliton.config.grid_points) + coordinate_vector = np.asarray(soliton.psi * np.sqrt(soliton.dx), dtype=np.complex128) + coordinate_vector /= np.linalg.norm(coordinate_vector) + full = np.fft.fftshift(np.fft.fft(coordinate_vector, norm="ortho")) + indices = _centered_indices(full.size, cfg.mode_count) + raw = full[indices] + retained = float(np.vdot(raw, raw).real) + amplitudes = np.asarray(raw / np.linalg.norm(raw), dtype=np.complex128) + density = np.outer(amplitudes, np.conj(amplitudes)) + return LiouvilleTensorState(cfg, full, indices, amplitudes, density, retained) + + +def left_pointwise_action(multiplier: np.ndarray, kernel: np.ndarray) -> np.ndarray: + return np.asarray(multiplier[:, None] * kernel, dtype=np.complex128) + + +def right_pointwise_action(multiplier: np.ndarray, kernel: np.ndarray) -> np.ndarray: + return np.asarray(kernel * multiplier[None, :], dtype=np.complex128) + + +def fixed_particle_occupation(mode_count: int, particle_number: int) -> np.ndarray: + occupation = np.zeros(mode_count, dtype=np.int64) + for index in range(particle_number): + occupation[index % mode_count] += 1 + return occupation + + +def _retained_probability(full: np.ndarray, count: int) -> float: + indices = _centered_indices(full.size, count) + values = full[indices] + return float(np.vdot(values, values).real) + + +def canonical_payload(config: LiouvilleTensorConfig | None = None) -> dict[str, Any]: + cfg = LiouvilleTensorConfig() if config is None else config + return { + "schema": SCHEMA, + "model_id": "M11", + "milestone": MILESTONE, + "configuration": asdict(cfg), + "study_api": ( + "openwave.xperiments.m11_cat_ept_soliton_qdo." + "liouville_soliton_tensor_m112:run_liouville_tensor_study" + ), + "formal_authority": { + "repository": "jagg-ix/entropic-physlib-private", + "branch": "entropic-physlib-linear-full", + "head": FORMAL_HEAD, + "sources": list(FORMAL_SOURCES), + }, + } + + +def fingerprint(payload: Mapping[str, Any] | None = None) -> str: + selected = canonical_payload() if payload is None else dict(payload) + return sha256(_canonical_json(selected).encode()).hexdigest() + + +def run_liouville_tensor_study( + config: LiouvilleTensorConfig | None = None, +) -> dict[str, Any]: + state = construct_liouville_tensor(config) + rho = state.density_matrix + eigenvalues = np.linalg.eigvalsh(rho) + multiplier_left = np.exp(0.013j * np.arange(rho.shape[0])) + multiplier_right = np.exp(-0.017j * np.arange(rho.shape[0])) + left_right = left_pointwise_action( + multiplier_left, right_pointwise_action(multiplier_right, rho) + ) + right_left = right_pointwise_action( + multiplier_right, left_pointwise_action(multiplier_left, rho) + ) + occupation = fixed_particle_occupation( + state.config.mode_count, state.config.particle_number + ) + retained = [ + _retained_probability(state.full_amplitudes, count) + for count in state.config.refinement_modes + ] + diagnostics = { + "trace_error": abs(np.trace(rho) - 1.0), + "hermiticity_error": float(np.linalg.norm(rho - rho.conj().T)), + "purity_error": float(np.linalg.norm(rho @ rho - rho)), + "minimum_eigenvalue": float(eigenvalues.min()), + "largest_eigenvalue_error": abs(float(eigenvalues.max()) - 1.0), + "pointwise_action_commutator": float(np.linalg.norm(left_right - right_left)), + "particle_number": int(np.sum(occupation)), + "retained_probability": state.retained_probability, + "refinement_retained_probability": retained, + "continuum_kernel_norm_sq": float(np.vdot(rho, rho).real), + } + acceptance = { + "trace_one": diagnostics["trace_error"] < 5.0e-13, + "hermitian": diagnostics["hermiticity_error"] < 5.0e-13, + "rank_one_pure": diagnostics["purity_error"] < 5.0e-13, + "positive_semidefinite": diagnostics["minimum_eigenvalue"] > -5.0e-13, + "one_unit_eigenvalue": diagnostics["largest_eigenvalue_error"] < 5.0e-13, + "pointwise_actions_commute": diagnostics["pointwise_action_commutator"] < 5.0e-13, + "fixed_particle_number": diagnostics["particle_number"] == state.config.particle_number, + "mode_refinement_monotone": all( + later + 1.0e-15 >= earlier for earlier, later in zip(retained, retained[1:]) + ), + "cutoff_retains_signal": diagnostics["retained_probability"] > 0.999, + } + payload = canonical_payload(state.config) + return { + **payload, + "task": "M11.2", + "diagnostics": diagnostics, + "acceptance": acceptance, + "fingerprint": fingerprint(payload), + "passed": all(acceptance.values()), + } diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/optional_qcd_coupling_m114.py b/openwave/xperiments/m11_cat_ept_soliton_qdo/optional_qcd_coupling_m114.py new file mode 100644 index 00000000..4483768c --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/optional_qcd_coupling_m114.py @@ -0,0 +1,229 @@ +"""M11.4 optional SU(3) color coupling for the pointwise soliton carrier. + +This layer intentionally reuses the M10 matrix-valued SU(3) link, covariant +Hamiltonian, exact propagator, and gauge-transformation APIs. The neutral M11 +molecular/QDO sector remains available without color. +""" +from __future__ import annotations + +from dataclasses import asdict, dataclass +from hashlib import sha256 +import json +import math +from typing import Any, Mapping + +import numpy as np + +from openwave.xperiments.m10_cat_ept.color_matter_gauss_m107 import ( + exact_matter_step, + gauge_transform_matter, + hamiltonian_action, + matter_energy, + matter_norm, +) +from openwave.xperiments.m10_cat_ept.periodic_su3_hamiltonian_m106 import ( + deterministic_gauges, + deterministic_lattice_links, + gauge_transform_links, + gauss_residual, + magnetic_action, + zero_electric_field, +) + +from .pointwise_soliton_carrier_m111 import construct_pointwise_soliton +from .qdo_lj_atm_interaction_m113 import QDOLJATMConfig, run_qdo_lj_atm_study + +MILESTONE = "M11.4" +SCHEMA = "openwave.m11.optional-qcd-coupling.v1" +FORMAL_HEAD = "8bafa9ab93cbb39e85909fc3837bb4b6e0dec748" +FORMAL_SOURCES = ( + { + "path": "Physlib/QuantumMechanics/ComplexAction/YangMillsGaugeDynamics.lean", + "sha": "4fe7ae3471057b5c7b64fc22705d76f854d66766", + "theorem": "yangMillsEquation_gauge_covariant", + }, + { + "path": "Physlib/QuantumMechanics/ComplexAction/Particles/GellMannStructureConstants.lean", + "sha": "b721ea5e04a72430a81d84c6a0a6c20b3f9558a0", + "theorem": "gellMann_structure_constants", + }, + { + "path": "Physlib/QuantumMechanics/ComplexAction/Particles/SuNGaugeSector.lean", + "sha": "4585ddf9bc44396b5f9dce14321c4d6b2826cb8a", + "theorem": "su3_adjoint_eq_gluonCount", + }, + { + "path": "Physlib/QuantumMechanics/ComplexAction/HorizonCell/QCDComplexActionUnification.lean", + "sha": "c5d7108ec4781eee3068898d0d844b689230a6fa", + "theorem": "qcd_theta_confinement_factorization", + }, +) + + +def _canonical_json(value: Mapping[str, Any]) -> str: + return json.dumps(value, sort_keys=True, separators=(",", ":"), default=str) + + +@dataclass(frozen=True) +class OptionalQCDConfig: + enabled: bool = True + lattice_size: int = 2 + link_scale: float = 0.055 + gauge_scale: float = 0.071 + mass: float = 0.9 + hopping: float = 0.08 + timestep: float = 0.035 + inverse_coupling: float = 1.4 + theta: float = 0.23 + beta: float = 0.8 + + def validate(self) -> None: + if self.lattice_size != 2: + raise ValueError("the M11.4 reference campaign uses a 2x2 lattice") + if self.link_scale <= 0 or self.gauge_scale <= 0: + raise ValueError("positive link and gauge scales are required") + if self.mass <= 0 or self.hopping <= 0 or self.timestep <= 0: + raise ValueError("positive dynamical parameters are required") + + +def soliton_color_matter(size: int = 2) -> np.ndarray: + soliton = construct_pointwise_soliton() + sample_indices = np.linspace(0, soliton.x.size - 1, size * size, dtype=int) + scalar = soliton.psi[sample_indices].reshape(size, size) + matter = np.empty((size, size, 3), dtype=np.complex128) + for x in range(size): + for y in range(size): + color = np.asarray( + [ + 1.0, + (0.63 + 0.05 * x) * np.exp(1.0j * (0.31 * x + 0.17 * y)), + (0.41 + 0.04 * y) * np.exp(-1.0j * (0.13 * x + 0.29 * y)), + ], + dtype=np.complex128, + ) + color /= np.linalg.norm(color) + matter[x, y] = scalar[x, y] * color + norm = float(np.linalg.norm(matter)) + if norm <= 0.0: + raise ValueError("nonzero soliton matter field required") + return np.asarray(matter / norm, dtype=np.complex128) + + +def _max_link_unitarity_error(links: np.ndarray) -> float: + identity = np.eye(3) + return float( + max( + np.linalg.norm(links[index].conj().T @ links[index] - identity) + for index in np.ndindex(links.shape[:3]) + ) + ) + + +def _max_link_determinant_error(links: np.ndarray) -> float: + return float( + max(abs(np.linalg.det(links[index]) - 1.0) for index in np.ndindex(links.shape[:3])) + ) + + +def _qcd_history_weight(cfg: OptionalQCDConfig, magnetic: float, matter_energy_value: float) -> complex: + if not cfg.enabled: + return complex(np.exp(-cfg.beta * matter_energy_value)) + return complex(np.exp(1.0j * cfg.theta - cfg.beta * (magnetic + matter_energy_value))) + + +def canonical_payload(config: OptionalQCDConfig | None = None) -> dict[str, Any]: + cfg = OptionalQCDConfig() if config is None else config + return { + "schema": SCHEMA, + "model_id": "M11", + "milestone": MILESTONE, + "configuration": asdict(cfg), + "study_api": ( + "openwave.xperiments.m11_cat_ept_soliton_qdo." + "optional_qcd_coupling_m114:run_optional_qcd_study" + ), + "reuses": [ + "openwave.xperiments.m10_cat_ept.periodic_su3_hamiltonian_m106", + "openwave.xperiments.m10_cat_ept.color_matter_gauss_m107", + ], + "formal_authority": { + "repository": "jagg-ix/entropic-physlib-private", + "branch": "entropic-physlib-linear-full", + "head": FORMAL_HEAD, + "sources": list(FORMAL_SOURCES), + }, + } + + +def fingerprint(payload: Mapping[str, Any] | None = None) -> str: + selected = canonical_payload() if payload is None else dict(payload) + return sha256(_canonical_json(selected).encode()).hexdigest() + + +def run_optional_qcd_study(config: OptionalQCDConfig | None = None) -> dict[str, Any]: + cfg = OptionalQCDConfig() if config is None else config + cfg.validate() + links = deterministic_lattice_links(cfg.lattice_size, cfg.link_scale) + gauges = deterministic_gauges(cfg.lattice_size, cfg.gauge_scale) + matter = soliton_color_matter(cfg.lattice_size) + transformed_links = gauge_transform_links(links, gauges) + transformed_matter = gauge_transform_matter(matter, gauges) + action = hamiltonian_action(links, matter, cfg.mass, cfg.hopping) + transformed_action = hamiltonian_action( + transformed_links, transformed_matter, cfg.mass, cfg.hopping + ) + expected_transformed_action = gauge_transform_matter(action, gauges) + evolved = exact_matter_step( + links, matter, cfg.timestep, cfg.mass, cfg.hopping + ) + evolved_transformed = exact_matter_step( + transformed_links, + transformed_matter, + cfg.timestep, + cfg.mass, + cfg.hopping, + ) + expected_evolved = gauge_transform_matter(evolved, gauges) + electric = zero_electric_field(cfg.lattice_size) + magnetic = magnetic_action(links, cfg.inverse_coupling) + energy = matter_energy(links, matter, cfg.mass, cfg.hopping) + weight = _qcd_history_weight(cfg, magnetic, energy) + neutral_cfg = OptionalQCDConfig(**{**asdict(cfg), "enabled": False}) + neutral_weight = _qcd_history_weight(neutral_cfg, magnetic, energy) + qdo = run_qdo_lj_atm_study(QDOLJATMConfig()) + diagnostics = { + "matter_norm_error": abs(matter_norm(matter) - 1.0), + "evolved_norm_error": abs(matter_norm(evolved) - 1.0), + "gauge_covariance_error": float(np.linalg.norm(transformed_action - expected_transformed_action)), + "evolution_covariance_error": float(np.linalg.norm(evolved_transformed - expected_evolved)), + "link_unitarity_error": _max_link_unitarity_error(links), + "link_determinant_error": _max_link_determinant_error(links), + "source_free_gauss_residual": gauss_residual(links, electric), + "magnetic_action": magnetic, + "matter_energy": energy, + "qcd_weight_modulus": abs(weight), + "neutral_weight_phase_error": abs(np.angle(neutral_weight)), + "colored_weight_phase_error": abs(np.angle(weight) - cfg.theta), + "qdo_sector_passed": bool(qdo["passed"]), + } + acceptance = { + "normalized_soliton_color_field": diagnostics["matter_norm_error"] < 5.0e-13, + "exact_propagator_preserves_norm": diagnostics["evolved_norm_error"] < 5.0e-13, + "hamiltonian_is_gauge_covariant": diagnostics["gauge_covariance_error"] < 5.0e-12, + "evolution_is_gauge_covariant": diagnostics["evolution_covariance_error"] < 5.0e-12, + "links_are_unitary": diagnostics["link_unitarity_error"] < 5.0e-12, + "links_have_unit_determinant": diagnostics["link_determinant_error"] < 5.0e-12, + "source_free_gauss_closes": diagnostics["source_free_gauss_residual"] < 5.0e-13, + "neutral_sector_has_no_theta_phase": diagnostics["neutral_weight_phase_error"] < 5.0e-13, + "colored_sector_carries_theta_phase": diagnostics["colored_weight_phase_error"] < 5.0e-13, + "qdo_sector_remains_available": diagnostics["qdo_sector_passed"], + } + payload = canonical_payload(cfg) + return { + **payload, + "task": "M11.4", + "diagnostics": diagnostics, + "acceptance": acceptance, + "fingerprint": fingerprint(payload), + "passed": all(acceptance.values()), + } diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/qdo_lj_atm_interaction_m113.py b/openwave/xperiments/m11_cat_ept_soliton_qdo/qdo_lj_atm_interaction_m113.py new file mode 100644 index 00000000..bb9b4dda --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/qdo_lj_atm_interaction_m113.py @@ -0,0 +1,231 @@ +"""M11.3 QDO-calibrated Lennard-Jones and Axilrod-Teller interactions.""" +from __future__ import annotations + +from dataclasses import asdict, dataclass +from hashlib import sha256 +import itertools +import json +import math +from typing import Any, Mapping + +import numpy as np + +MILESTONE = "M11.3" +SCHEMA = "openwave.m11.qdo-lj-atm-interaction.v1" +FORMAL_HEAD = "8bafa9ab93cbb39e85909fc3837bb4b6e0dec748" +FORMAL_SOURCE_PATH = ( + "Physlib/QuantumMechanics/ComplexAction/Particles/" + "LennardJonesAxilrodTeller.lean" +) +FORMAL_SOURCE_SHA = "93f5e1b55d1fbfe44dc5b8106b7331d08bdb5159" +FORMAL_SOURCES = tuple( + { + "path": FORMAL_SOURCE_PATH, + "sha": FORMAL_SOURCE_SHA, + "theorem": theorem, + } + for theorem in ( + "ljPotential_split", + "lj_tail_dispersion_form", + "lj_tail_eq_vdw_dispersionEnergy", + "lj_tail_is_qdo_C6", + "lattice_couplings_qdo_related", + "atm_equilateral", + "atm_linear", + ) +) + + +def _canonical_json(value: Mapping[str, Any]) -> str: + return json.dumps(value, sort_keys=True, separators=(",", ":"), default=str) + + +@dataclass(frozen=True) +class QDOLJATMConfig: + alpha1: float = 1.0 + hbar_omega: float = 1.0 + repulsive_exponent: int = 12 + equilibrium_distance: float = 1.0 + epsilon: float = 0.375 + core_radius: float = 0.08 + + def validate(self) -> None: + if self.alpha1 <= 0 or self.hbar_omega <= 0: + raise ValueError("positive QDO response parameters are required") + if self.repulsive_exponent <= 6: + raise ValueError("repulsive exponent must exceed six") + if self.equilibrium_distance <= 0 or self.epsilon <= 0: + raise ValueError("positive LJ parameters are required") + if self.core_radius < 0: + raise ValueError("nonnegative core radius required") + + +def qdo_c6(alpha1: float, hbar_omega: float) -> float: + return 0.75 * alpha1**2 * hbar_omega + + +def qdo_c9(alpha1: float, hbar_omega: float) -> float: + return 3.0 / 16.0 * alpha1**3 * hbar_omega + + +def lj_c6(epsilon: float, equilibrium_distance: float, exponent: int) -> float: + return epsilon * exponent * equilibrium_distance**6 / (exponent - 6.0) + + +def lj_repulsive(epsilon: float, re: float, r: float, n: int, m: int = 6) -> float: + return epsilon * n * m / (n - m) * (1.0 / n) * (re / r) ** n + + +def lj_attractive(epsilon: float, re: float, r: float, n: int, m: int = 6) -> float: + return epsilon * n * m / (n - m) * (1.0 / m) * (re / r) ** m + + +def lj_potential(epsilon: float, re: float, r: float, n: int, m: int = 6) -> float: + return lj_repulsive(epsilon, re, r, n, m) - lj_attractive(epsilon, re, r, n, m) + + +def dispersion_energy(coefficient: float, r: float) -> float: + return -0.75 * coefficient / r**6 + + +def atm_angular_factor(cosines: tuple[float, float, float]) -> float: + c1, c2, c3 = cosines + return 1.0 + 3.0 * c1 * c2 * c3 + + +def atm_energy( + coupling: float, + cosines: tuple[float, float, float], + distances: tuple[float, float, float], +) -> float: + return coupling * atm_angular_factor(cosines) / np.prod(distances) ** 3 + + +def triangle_cosines(points: np.ndarray) -> tuple[float, float, float]: + if points.shape != (3, points.shape[1]): + raise ValueError("three points required") + cosines: list[float] = [] + for center in range(3): + left = points[(center + 1) % 3] - points[center] + right = points[(center + 2) % 3] - points[center] + cosine = float(np.dot(left, right) / (np.linalg.norm(left) * np.linalg.norm(right))) + cosines.append(float(np.clip(cosine, -1.0, 1.0))) + return tuple(cosines) # type: ignore[return-value] + + +def trimer_atm_energy(points: np.ndarray, coupling: float) -> float: + distances = tuple( + float(np.linalg.norm(points[i] - points[j])) + for i, j in ((0, 1), (0, 2), (1, 2)) + ) + return atm_energy(coupling, triangle_cosines(points), distances) + + +def density_smeared_dispersion( + x: np.ndarray, + density_a: np.ndarray, + density_b: np.ndarray, + separation: float, + c6: float, + core_radius: float, +) -> float: + dx = float(x[1] - x[0]) + shifted = x[:, None] - (x[None, :] + separation) + kernel = 1.0 / (shifted**2 + core_radius**2) ** 3 + return float(-c6 * np.sum(density_a[:, None] * density_b[None, :] * kernel) * dx**2) + + +def canonical_payload(config: QDOLJATMConfig | None = None) -> dict[str, Any]: + cfg = QDOLJATMConfig() if config is None else config + return { + "schema": SCHEMA, + "model_id": "M11", + "milestone": MILESTONE, + "configuration": asdict(cfg), + "study_api": ( + "openwave.xperiments.m11_cat_ept_soliton_qdo." + "qdo_lj_atm_interaction_m113:run_qdo_lj_atm_study" + ), + "formal_authority": { + "repository": "jagg-ix/entropic-physlib-private", + "branch": "entropic-physlib-linear-full", + "head": FORMAL_HEAD, + "sources": list(FORMAL_SOURCES), + }, + } + + +def fingerprint(payload: Mapping[str, Any] | None = None) -> str: + selected = canonical_payload() if payload is None else dict(payload) + return sha256(_canonical_json(selected).encode()).hexdigest() + + +def run_qdo_lj_atm_study(config: QDOLJATMConfig | None = None) -> dict[str, Any]: + cfg = QDOLJATMConfig() if config is None else config + cfg.validate() + c6_qdo = qdo_c6(cfg.alpha1, cfg.hbar_omega) + c9_qdo = qdo_c9(cfg.alpha1, cfg.hbar_omega) + c6_lj = lj_c6(cfg.epsilon, cfg.equilibrium_distance, cfg.repulsive_exponent) + distances = np.geomspace(1.3, 8.0, 32) + split_errors = [] + tail_errors = [] + vdw_errors = [] + tails = [] + for r in distances: + repulsive = lj_repulsive(cfg.epsilon, cfg.equilibrium_distance, float(r), cfg.repulsive_exponent) + attractive = lj_attractive(cfg.epsilon, cfg.equilibrium_distance, float(r), cfg.repulsive_exponent) + total = lj_potential(cfg.epsilon, cfg.equilibrium_distance, float(r), cfg.repulsive_exponent) + split_errors.append(abs(total - (repulsive - attractive))) + tail = -attractive + tails.append(abs(tail)) + tail_errors.append(abs(tail + c6_lj / float(r) ** 6)) + vdw_errors.append(abs(tail - dispersion_energy(4.0 / 3.0 * c6_lj, float(r)))) + slope = float(np.polyfit(np.log(distances[-12:]), np.log(np.asarray(tails[-12:])), 1)[0]) + equilateral = np.asarray([[0.0, 0.0], [1.0, 0.0], [0.5, math.sqrt(3.0) / 2.0]]) + linear = np.asarray([[-1.0, 0.0], [0.0, 0.0], [1.0, 0.0]]) + permutations = [trimer_atm_energy(equilateral[list(order)], c9_qdo) for order in itertools.permutations(range(3))] + eq_factor = atm_angular_factor(triangle_cosines(equilateral)) + linear_factor = atm_angular_factor(triangle_cosines(linear)) + scale = 1.7 + atm_scale_ratio = trimer_atm_energy(equilateral * scale, c9_qdo) / trimer_atm_energy(equilateral, c9_qdo) + diagnostics = { + "c6_lj": c6_lj, + "c6_qdo": c6_qdo, + "c6_match_error": abs(c6_lj - c6_qdo), + "c9_qdo": c9_qdo, + "threebody_invariant_error": abs(cfg.alpha1 * c6_qdo - 4.0 * c9_qdo), + "maximum_split_error": max(split_errors), + "maximum_tail_error": max(tail_errors), + "maximum_vdw_error": max(vdw_errors), + "far_field_log_slope": slope, + "equilateral_factor": eq_factor, + "linear_factor": linear_factor, + "atm_permutation_error": float(max(permutations) - min(permutations)), + "atm_scaling_error": abs(atm_scale_ratio - scale**-9), + "well_depth_error": abs( + lj_potential(cfg.epsilon, cfg.equilibrium_distance, cfg.equilibrium_distance, cfg.repulsive_exponent) + + cfg.epsilon + ), + } + acceptance = { + "lj_split_exact": diagnostics["maximum_split_error"] < 5.0e-13, + "tail_is_minus_c6_over_r6": diagnostics["maximum_tail_error"] < 5.0e-13, + "tail_equals_vdw_energy": diagnostics["maximum_vdw_error"] < 5.0e-13, + "lj_c6_is_qdo_c6": diagnostics["c6_match_error"] < 5.0e-13, + "qdo_two_three_body_invariant": diagnostics["threebody_invariant_error"] < 5.0e-13, + "tail_slope_is_minus_six": abs(slope + 6.0) < 5.0e-12, + "atm_equilateral_repulsive": abs(eq_factor - 11.0 / 8.0) < 5.0e-13, + "atm_linear_attractive": abs(linear_factor + 2.0) < 5.0e-13, + "atm_permutation_symmetric": diagnostics["atm_permutation_error"] < 5.0e-13, + "atm_scales_as_r_minus_nine": diagnostics["atm_scaling_error"] < 5.0e-13, + "well_depth_is_minus_epsilon": diagnostics["well_depth_error"] < 5.0e-13, + } + payload = canonical_payload(cfg) + return { + **payload, + "task": "M11.3", + "diagnostics": diagnostics, + "acceptance": acceptance, + "fingerprint": fingerprint(payload), + "passed": all(acceptance.values()), + } diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_liouville_tensor_m112.zc b/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_liouville_tensor_m112.zc new file mode 100644 index 00000000..a20e5cff --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_liouville_tensor_m112.zc @@ -0,0 +1,6 @@ +model:m11.2#extends@model:m11.1. +model:m11.2#tensor@liouville:rho-psi. +liouville:rho-psi#defined-by@equation:rho-ij-equals-ai-conjugate-aj. +liouville:rho-psi#finite-cutoff-of@lean:LiouvilleSecondQuantization.kernelMode_infinite. +liouville:rho-psi#fixed-particle-sector@lean:LiouvilleSecondQuantization.kernelOccupationBasis_particleNumber. +liouville:rho-psi#pointwise-actions-commute@lean:LiouvilleSecondQuantization.leftPointwise_rightPointwise_commute. diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_optional_qcd_m114.zc b/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_optional_qcd_m114.zc new file mode 100644 index 00000000..a24105b7 --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_optional_qcd_m114.zc @@ -0,0 +1,7 @@ +model:m11.4#extends@model:m11.3. +model:m11.4#optional-sector@qcd:su3-color. +qcd:su3-color#reuses@openwave:m10.5-matrix-links. +qcd:su3-color#reuses@openwave:m10.6-periodic-hamiltonian. +qcd:su3-color#reuses@openwave:m10.7-color-matter-gauss. +qcd:su3-color#covariant-by@lean:YangMillsGaugeDynamics.yangMillsEquation_gauge_covariant. +model:m11.4#retains@sector:neutral-qdo. diff --git a/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_qdo_lj_atm_m113.zc b/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_qdo_lj_atm_m113.zc new file mode 100644 index 00000000..11c98285 --- /dev/null +++ b/openwave/xperiments/m11_cat_ept_soliton_qdo/research/zil/m11_qdo_lj_atm_m113.zc @@ -0,0 +1,8 @@ +model:m11.3#extends@model:m11.2. +model:m11.3#pair-interaction@potential:lennard-jones. +potential:lennard-jones#splits@lean:LennardJonesDispersion.ljPotential_split. +potential:lennard-jones#tail@equation:minus-c6-over-r6. +equation:minus-c6-over-r6#identified-with@lean:LennardJonesDispersion.lj_tail_eq_vdw_dispersionEnergy. +qdo:c6#equals@coefficient:lj-c6. +qdo:c6#related-to@qdo:c9. +qdo:c9#controls@potential:axilrod-teller-muto. diff --git a/tests/test_m11_liouville_tensor_m112.py b/tests/test_m11_liouville_tensor_m112.py new file mode 100644 index 00000000..c8e82855 --- /dev/null +++ b/tests/test_m11_liouville_tensor_m112.py @@ -0,0 +1,6 @@ +from openwave.xperiments.m11_cat_ept_soliton_qdo.liouville_soliton_tensor_m112 import run_liouville_tensor_study + +def test_liouville_tensor_campaign(): + result=run_liouville_tensor_study() + assert result['passed'], result + assert result['diagnostics']['particle_number']==3 diff --git a/tests/test_m11_optional_qcd_m114.py b/tests/test_m11_optional_qcd_m114.py new file mode 100644 index 00000000..7e18e981 --- /dev/null +++ b/tests/test_m11_optional_qcd_m114.py @@ -0,0 +1,5 @@ +from openwave.xperiments.m11_cat_ept_soliton_qdo.optional_qcd_coupling_m114 import run_optional_qcd_study + +def test_optional_qcd_campaign(): + result=run_optional_qcd_study() + assert result['passed'], result diff --git a/tests/test_m11_qdo_lj_atm_m113.py b/tests/test_m11_qdo_lj_atm_m113.py new file mode 100644 index 00000000..398cb263 --- /dev/null +++ b/tests/test_m11_qdo_lj_atm_m113.py @@ -0,0 +1,6 @@ +from openwave.xperiments.m11_cat_ept_soliton_qdo.qdo_lj_atm_interaction_m113 import run_qdo_lj_atm_study + +def test_qdo_lj_atm_campaign(): + result=run_qdo_lj_atm_study() + assert result['passed'], result + assert abs(result['diagnostics']['far_field_log_slope']+6)<1e-10