physicskit 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- physicskit/__init__.py +51 -0
- physicskit/astro/__init__.py +66 -0
- physicskit/astro/cosmic_web.py +395 -0
- physicskit/astro/galactic_dynamics.py +137 -0
- physicskit/astro/nbody.py +208 -0
- physicskit/astro/orbital_mechanics.py +220 -0
- physicskit/astro/stellar_dynamo.py +628 -0
- physicskit/astro/stellar_structure.py +198 -0
- physicskit/astro/tests/__init__.py +0 -0
- physicskit/astro/tests/conftest.py +7 -0
- physicskit/astro/tests/test_cosmic_web.py +159 -0
- physicskit/astro/tests/test_galactic_dynamics.py +46 -0
- physicskit/astro/tests/test_nbody.py +81 -0
- physicskit/astro/tests/test_orbital_mechanics.py +73 -0
- physicskit/astro/tests/test_stellar_dynamo.py +198 -0
- physicskit/astro/tests/test_stellar_structure.py +52 -0
- physicskit/astro/tests/test_visualizers.py +159 -0
- physicskit/astro/visualizers.py +628 -0
- physicskit/chaos/__init__.py +55 -0
- physicskit/chaos/core/__init__.py +3 -0
- physicskit/chaos/core/base_system.py +342 -0
- physicskit/chaos/core/integrators.py +40 -0
- physicskit/chaos/exceptions.py +24 -0
- physicskit/chaos/quantum/__init__.py +38 -0
- physicskit/chaos/quantum/billiards.py +274 -0
- physicskit/chaos/quantum/husimi.py +85 -0
- physicskit/chaos/quantum/maps.py +366 -0
- physicskit/chaos/systems/__init__.py +38 -0
- physicskit/chaos/systems/billiards.py +1131 -0
- physicskit/chaos/systems/continuous.py +1276 -0
- physicskit/chaos/systems/maps.py +557 -0
- physicskit/chaos/tests/__init__.py +0 -0
- physicskit/chaos/tests/test_basins.py +76 -0
- physicskit/chaos/tests/test_bifurcation.py +132 -0
- physicskit/chaos/tests/test_billiards.py +115 -0
- physicskit/chaos/tests/test_continuous.py +224 -0
- physicskit/chaos/tests/test_dimension.py +69 -0
- physicskit/chaos/tests/test_divergence.py +90 -0
- physicskit/chaos/tests/test_dynamic_plots.py +269 -0
- physicskit/chaos/tests/test_integrators.py +96 -0
- physicskit/chaos/tests/test_io.py +41 -0
- physicskit/chaos/tests/test_maps.py +110 -0
- physicskit/chaos/tests/test_metrics.py +115 -0
- physicskit/chaos/tests/test_phase_space.py +73 -0
- physicskit/chaos/tests/test_properties.py +116 -0
- physicskit/chaos/tests/test_quantum_billiards.py +94 -0
- physicskit/chaos/tests/test_quantum_maps.py +144 -0
- physicskit/chaos/tests/test_recurrence.py +51 -0
- physicskit/chaos/tests/test_repr_and_api_consistency.py +134 -0
- physicskit/chaos/tests/test_section.py +49 -0
- physicskit/chaos/tests/test_spectral.py +48 -0
- physicskit/chaos/tests/test_streamlit_app.py +45 -0
- physicskit/chaos/tests/test_timeseries.py +131 -0
- physicskit/chaos/tests/test_viewer3d.py +41 -0
- physicskit/chaos/utils/__init__.py +46 -0
- physicskit/chaos/utils/dimension.py +139 -0
- physicskit/chaos/utils/io.py +95 -0
- physicskit/chaos/utils/metrics.py +304 -0
- physicskit/chaos/utils/recurrence.py +122 -0
- physicskit/chaos/utils/spectral.py +69 -0
- physicskit/chaos/utils/timeseries.py +303 -0
- physicskit/chaos/visualizers/__init__.py +85 -0
- physicskit/chaos/visualizers/basins.py +185 -0
- physicskit/chaos/visualizers/bifurcation.py +273 -0
- physicskit/chaos/visualizers/divergence.py +374 -0
- physicskit/chaos/visualizers/dynamic_plots.py +1372 -0
- physicskit/chaos/visualizers/phase_space.py +133 -0
- physicskit/chaos/visualizers/quantum.py +299 -0
- physicskit/chaos/visualizers/recurrence.py +91 -0
- physicskit/chaos/visualizers/section.py +161 -0
- physicskit/chaos/visualizers/theme.py +31 -0
- physicskit/chaos/visualizers/viewer3d.py +82 -0
- physicskit/classical/__init__.py +55 -0
- physicskit/classical/core/__init__.py +17 -0
- physicskit/classical/core/base_system.py +510 -0
- physicskit/classical/core/integrators.py +397 -0
- physicskit/classical/systems/__init__.py +32 -0
- physicskit/classical/systems/chains.py +334 -0
- physicskit/classical/systems/hamiltonian.py +215 -0
- physicskit/classical/systems/lagrangian.py +308 -0
- physicskit/classical/systems/newtonian.py +536 -0
- physicskit/classical/systems/rotations.py +614 -0
- physicskit/classical/tests/__init__.py +0 -0
- physicskit/classical/tests/conftest.py +7 -0
- physicskit/classical/tests/test_base_system.py +113 -0
- physicskit/classical/tests/test_chains.py +84 -0
- physicskit/classical/tests/test_conservation.py +244 -0
- physicskit/classical/tests/test_conservation_utils.py +47 -0
- physicskit/classical/tests/test_hamiltonian.py +44 -0
- physicskit/classical/tests/test_integrators.py +123 -0
- physicskit/classical/tests/test_lagrangian.py +69 -0
- physicskit/classical/tests/test_newtonian.py +45 -0
- physicskit/classical/tests/test_rotations.py +160 -0
- physicskit/classical/tests/test_stepsize.py +149 -0
- physicskit/classical/tests/test_symbolic.py +125 -0
- physicskit/classical/tests/test_visualizers.py +172 -0
- physicskit/classical/utils/__init__.py +20 -0
- physicskit/classical/utils/conservation.py +126 -0
- physicskit/classical/utils/stepsize.py +187 -0
- physicskit/classical/utils/symbolic.py +235 -0
- physicskit/classical/visualizers/__init__.py +25 -0
- physicskit/classical/visualizers/animations.py +508 -0
- physicskit/classical/visualizers/interactive.py +113 -0
- physicskit/classical/visualizers/modal_analysis.py +97 -0
- physicskit/classical/visualizers/phase_space.py +214 -0
- physicskit/condensed/__init__.py +122 -0
- physicskit/condensed/anderson_localization.py +155 -0
- physicskit/condensed/correlated.py +284 -0
- physicskit/condensed/ginzburg_landau.py +220 -0
- physicskit/condensed/landau_levels.py +246 -0
- physicskit/condensed/laughlin.py +229 -0
- physicskit/condensed/models.py +627 -0
- physicskit/condensed/tests/__init__.py +0 -0
- physicskit/condensed/tests/test_condensed.py +518 -0
- physicskit/condensed/tests/test_visualizers.py +87 -0
- physicskit/condensed/tight_binding.py +445 -0
- physicskit/condensed/topological_insulator_3d.py +178 -0
- physicskit/condensed/topology.py +217 -0
- physicskit/condensed/visualizers.py +296 -0
- physicskit/condensed/weyl.py +180 -0
- physicskit/constants.py +184 -0
- physicskit/fields/__init__.py +111 -0
- physicskit/fields/electrodynamics.py +671 -0
- physicskit/fields/quantum_fields.py +510 -0
- physicskit/fields/solitons.py +527 -0
- physicskit/fields/tests/__init__.py +0 -0
- physicskit/fields/tests/conftest.py +7 -0
- physicskit/fields/tests/test_field_animations.py +154 -0
- physicskit/fields/tests/test_fields.py +439 -0
- physicskit/fields/tests/test_visualizers.py +101 -0
- physicskit/fields/visualizers.py +503 -0
- physicskit/fluids/__init__.py +134 -0
- physicskit/fluids/core/__init__.py +23 -0
- physicskit/fluids/core/grid.py +165 -0
- physicskit/fluids/core/timestepping.py +231 -0
- physicskit/fluids/exceptions.py +26 -0
- physicskit/fluids/systems/__init__.py +70 -0
- physicskit/fluids/systems/compressible_flow.py +281 -0
- physicskit/fluids/systems/instabilities.py +343 -0
- physicskit/fluids/systems/navier_stokes.py +221 -0
- physicskit/fluids/systems/potential_flow.py +440 -0
- physicskit/fluids/systems/viscous_flow.py +425 -0
- physicskit/fluids/systems/vortex_dynamics.py +304 -0
- physicskit/fluids/tests/__init__.py +0 -0
- physicskit/fluids/tests/conftest.py +7 -0
- physicskit/fluids/tests/test_compressible_flow.py +66 -0
- physicskit/fluids/tests/test_instabilities.py +115 -0
- physicskit/fluids/tests/test_navier_stokes.py +67 -0
- physicskit/fluids/tests/test_potential_flow.py +92 -0
- physicskit/fluids/tests/test_static_visualizers.py +91 -0
- physicskit/fluids/tests/test_utils.py +100 -0
- physicskit/fluids/tests/test_viscous_flow.py +110 -0
- physicskit/fluids/tests/test_visualizers.py +34 -0
- physicskit/fluids/tests/test_vortex_dynamics.py +88 -0
- physicskit/fluids/utils/__init__.py +18 -0
- physicskit/fluids/utils/dimensionless.py +239 -0
- physicskit/fluids/utils/spectral_analysis.py +142 -0
- physicskit/fluids/visualizers/__init__.py +14 -0
- physicskit/fluids/visualizers/compressible.py +39 -0
- physicskit/fluids/visualizers/flow_fields.py +252 -0
- physicskit/fluids/visualizers/potential_flow.py +51 -0
- physicskit/fluids/visualizers/spectra.py +62 -0
- physicskit/fluids/visualizers/theme.py +38 -0
- physicskit/integrators/__init__.py +52 -0
- physicskit/integrators/adaptive.py +199 -0
- physicskit/integrators/fixed_step.py +360 -0
- physicskit/integrators/tests/__init__.py +0 -0
- physicskit/integrators/tests/test_integrators.py +101 -0
- physicskit/optics/__init__.py +124 -0
- physicskit/optics/_compat.py +5 -0
- physicskit/optics/gaussian.py +382 -0
- physicskit/optics/quantum_optics.py +428 -0
- physicskit/optics/ray.py +469 -0
- physicskit/optics/tests/__init__.py +0 -0
- physicskit/optics/tests/test_diffraction_animation.py +38 -0
- physicskit/optics/tests/test_gaussian.py +170 -0
- physicskit/optics/tests/test_quantum_optics.py +147 -0
- physicskit/optics/tests/test_ray.py +177 -0
- physicskit/optics/tests/test_visualizers.py +58 -0
- physicskit/optics/tests/test_wave.py +146 -0
- physicskit/optics/visualizers.py +264 -0
- physicskit/optics/wave.py +365 -0
- physicskit/particle/__init__.py +152 -0
- physicskit/particle/collider.py +382 -0
- physicskit/particle/confinement.py +125 -0
- physicskit/particle/decays.py +357 -0
- physicskit/particle/electroweak.py +300 -0
- physicskit/particle/kinematics.py +271 -0
- physicskit/particle/neutrinos.py +84 -0
- physicskit/particle/nuclear.py +100 -0
- physicskit/particle/scattering.py +159 -0
- physicskit/particle/tests/__init__.py +0 -0
- physicskit/particle/tests/conftest.py +7 -0
- physicskit/particle/tests/test_collider.py +119 -0
- physicskit/particle/tests/test_confinement.py +42 -0
- physicskit/particle/tests/test_decays.py +112 -0
- physicskit/particle/tests/test_electroweak.py +97 -0
- physicskit/particle/tests/test_kinematics.py +138 -0
- physicskit/particle/tests/test_neutrinos.py +36 -0
- physicskit/particle/tests/test_nuclear.py +45 -0
- physicskit/particle/tests/test_scattering.py +64 -0
- physicskit/particle/tests/test_visualizers.py +214 -0
- physicskit/particle/visualizers/__init__.py +38 -0
- physicskit/particle/visualizers/animations.py +705 -0
- physicskit/particle/visualizers/static.py +101 -0
- physicskit/plasma/__init__.py +176 -0
- physicskit/plasma/acceleration.py +152 -0
- physicskit/plasma/instabilities.py +417 -0
- physicskit/plasma/kinetic.py +588 -0
- physicskit/plasma/mhd.py +463 -0
- physicskit/plasma/single_particle.py +562 -0
- physicskit/plasma/tests/__init__.py +0 -0
- physicskit/plasma/tests/conftest.py +7 -0
- physicskit/plasma/tests/test_new_time_domain_features.py +222 -0
- physicskit/plasma/tests/test_plasma.py +232 -0
- physicskit/plasma/tests/test_visualizers.py +79 -0
- physicskit/plasma/turbulence.py +219 -0
- physicskit/plasma/visualizers.py +868 -0
- physicskit/plasma/waves.py +549 -0
- physicskit/quantum/__init__.py +180 -0
- physicskit/quantum/_compat.py +20 -0
- physicskit/quantum/chapters/__init__.py +0 -0
- physicskit/quantum/chapters/entanglement.py +489 -0
- physicskit/quantum/chapters/harmonic_spin.py +517 -0
- physicskit/quantum/chapters/hydrogen_am.py +292 -0
- physicskit/quantum/chapters/perturbation.py +350 -0
- physicskit/quantum/chapters/potentials.py +997 -0
- physicskit/quantum/chapters/spin.py +306 -0
- physicskit/quantum/chapters/wave_packets.py +541 -0
- physicskit/quantum/core/__init__.py +0 -0
- physicskit/quantum/core/eigensolvers.py +311 -0
- physicskit/quantum/core/operators.py +296 -0
- physicskit/quantum/core/solvers.py +271 -0
- physicskit/quantum/tests/__init__.py +0 -0
- physicskit/quantum/tests/conftest.py +7 -0
- physicskit/quantum/tests/test_animations.py +225 -0
- physicskit/quantum/tests/test_compat.py +43 -0
- physicskit/quantum/tests/test_eigensolvers.py +24 -0
- physicskit/quantum/tests/test_entanglement.py +127 -0
- physicskit/quantum/tests/test_harmonic_spin.py +140 -0
- physicskit/quantum/tests/test_hydrogen_am.py +48 -0
- physicskit/quantum/tests/test_measure.py +110 -0
- physicskit/quantum/tests/test_operators.py +105 -0
- physicskit/quantum/tests/test_perturbation.py +112 -0
- physicskit/quantum/tests/test_physics_checks.py +131 -0
- physicskit/quantum/tests/test_potentials.py +191 -0
- physicskit/quantum/tests/test_solvers.py +70 -0
- physicskit/quantum/tests/test_spin.py +22 -0
- physicskit/quantum/tests/test_unitarity.py +84 -0
- physicskit/quantum/tests/test_wave_packets.py +53 -0
- physicskit/quantum/utils/__init__.py +0 -0
- physicskit/quantum/utils/measure.py +253 -0
- physicskit/quantum/visualizers/__init__.py +0 -0
- physicskit/quantum/visualizers/bloch_sphere.py +205 -0
- physicskit/quantum/visualizers/entanglement.py +58 -0
- physicskit/quantum/visualizers/orbitals.py +187 -0
- physicskit/quantum/visualizers/phase_space.py +179 -0
- physicskit/quantum/visualizers/wavefunctions.py +230 -0
- physicskit/relativity/__init__.py +61 -0
- physicskit/relativity/chapters/__init__.py +33 -0
- physicskit/relativity/chapters/cosmology.py +190 -0
- physicskit/relativity/chapters/gw_merger.py +399 -0
- physicskit/relativity/chapters/kerr.py +371 -0
- physicskit/relativity/chapters/lensing.py +196 -0
- physicskit/relativity/chapters/neutron_star.py +149 -0
- physicskit/relativity/chapters/schwarzschild.py +412 -0
- physicskit/relativity/chapters/timekeeping.py +133 -0
- physicskit/relativity/core/__init__.py +12 -0
- physicskit/relativity/core/geodesics.py +216 -0
- physicskit/relativity/core/kerr_raytracer.py +259 -0
- physicskit/relativity/core/raytracer.py +241 -0
- physicskit/relativity/core/tensors.py +468 -0
- physicskit/relativity/tests/__init__.py +0 -0
- physicskit/relativity/tests/test_conservations.py +54 -0
- physicskit/relativity/tests/test_constants.py +34 -0
- physicskit/relativity/tests/test_cosmology.py +61 -0
- physicskit/relativity/tests/test_gw_merger.py +117 -0
- physicskit/relativity/tests/test_kerr.py +116 -0
- physicskit/relativity/tests/test_kerr_raytracer.py +103 -0
- physicskit/relativity/tests/test_lensing.py +75 -0
- physicskit/relativity/tests/test_neutron_star.py +48 -0
- physicskit/relativity/tests/test_raytracer.py +67 -0
- physicskit/relativity/tests/test_schwarzschild.py +126 -0
- physicskit/relativity/tests/test_shadow_render.py +81 -0
- physicskit/relativity/tests/test_tensors.py +86 -0
- physicskit/relativity/tests/test_timekeeping.py +51 -0
- physicskit/relativity/tests/test_visualizers_misc.py +115 -0
- physicskit/relativity/utils/__init__.py +1 -0
- physicskit/relativity/utils/constants.py +232 -0
- physicskit/relativity/visualizers/__init__.py +46 -0
- physicskit/relativity/visualizers/interactive.py +127 -0
- physicskit/relativity/visualizers/shadow_render.py +367 -0
- physicskit/relativity/visualizers/spacetime_3d.py +92 -0
- physicskit/relativity/visualizers/spacetime_diagrams.py +198 -0
- physicskit/relativity/visualizers/wave_plots.py +185 -0
- physicskit/rmt/__init__.py +8 -0
- physicskit/rmt/ensembles/__init__.py +108 -0
- physicskit/rmt/ensembles/banded.py +114 -0
- physicskit/rmt/ensembles/base.py +135 -0
- physicskit/rmt/ensembles/bdg.py +218 -0
- physicskit/rmt/ensembles/chiral.py +308 -0
- physicskit/rmt/ensembles/circular.py +104 -0
- physicskit/rmt/ensembles/crossover.py +82 -0
- physicskit/rmt/ensembles/density_matrix.py +148 -0
- physicskit/rmt/ensembles/effective_hamiltonian.py +230 -0
- physicskit/rmt/ensembles/embedded.py +207 -0
- physicskit/rmt/ensembles/gaussian.py +153 -0
- physicskit/rmt/ensembles/ginibre.py +110 -0
- physicskit/rmt/ensembles/girko.py +190 -0
- physicskit/rmt/ensembles/graph_laplacian.py +92 -0
- physicskit/rmt/ensembles/haar.py +57 -0
- physicskit/rmt/ensembles/jacobi.py +182 -0
- physicskit/rmt/ensembles/poisson.py +77 -0
- physicskit/rmt/ensembles/polynomial.py +139 -0
- physicskit/rmt/ensembles/pt_symmetric.py +120 -0
- physicskit/rmt/ensembles/single_ring.py +170 -0
- physicskit/rmt/ensembles/sparse.py +95 -0
- physicskit/rmt/ensembles/syk.py +170 -0
- physicskit/rmt/ensembles/truncated_unitary.py +80 -0
- physicskit/rmt/ensembles/universality.py +92 -0
- physicskit/rmt/ensembles/wishart.py +88 -0
- physicskit/rmt/py.typed +0 -0
- physicskit/rmt/spectrum.py +82 -0
- physicskit/rmt/stats/__init__.py +160 -0
- physicskit/rmt/stats/characteristic_polynomial.py +77 -0
- physicskit/rmt/stats/circular_law.py +54 -0
- physicskit/rmt/stats/correlations.py +162 -0
- physicskit/rmt/stats/density.py +70 -0
- physicskit/rmt/stats/entanglement.py +36 -0
- physicskit/rmt/stats/free_probability.py +202 -0
- physicskit/rmt/stats/localization.py +338 -0
- physicskit/rmt/stats/marchenko_pastur.py +55 -0
- physicskit/rmt/stats/pt_symmetric.py +265 -0
- physicskit/rmt/stats/ratios.py +110 -0
- physicskit/rmt/stats/real_ginibre.py +134 -0
- physicskit/rmt/stats/rigidity.py +272 -0
- physicskit/rmt/stats/single_ring.py +95 -0
- physicskit/rmt/stats/spacing.py +150 -0
- physicskit/rmt/stats/tracy_widom.py +175 -0
- physicskit/rmt/stats/truncated_unitary.py +40 -0
- physicskit/rmt/stats/unfolding.py +37 -0
- physicskit/rmt/stats/wachter.py +67 -0
- physicskit/rmt/tests/__init__.py +0 -0
- physicskit/rmt/tests/cache_utils.py +107 -0
- physicskit/rmt/tests/conftest.py +8 -0
- physicskit/rmt/tests/test_banded.py +86 -0
- physicskit/rmt/tests/test_base.py +29 -0
- physicskit/rmt/tests/test_bdg.py +133 -0
- physicskit/rmt/tests/test_characteristic_polynomial.py +50 -0
- physicskit/rmt/tests/test_chiral.py +273 -0
- physicskit/rmt/tests/test_circular.py +225 -0
- physicskit/rmt/tests/test_crossover.py +72 -0
- physicskit/rmt/tests/test_density.py +23 -0
- physicskit/rmt/tests/test_density_matrix.py +181 -0
- physicskit/rmt/tests/test_effective_hamiltonian.py +140 -0
- physicskit/rmt/tests/test_embedded.py +169 -0
- physicskit/rmt/tests/test_free_probability.py +81 -0
- physicskit/rmt/tests/test_gaussian_ensembles.py +22 -0
- physicskit/rmt/tests/test_gaussian_semicircle.py +127 -0
- physicskit/rmt/tests/test_ginibre_circular_law.py +131 -0
- physicskit/rmt/tests/test_girko.py +178 -0
- physicskit/rmt/tests/test_graph_laplacian.py +102 -0
- physicskit/rmt/tests/test_haar.py +118 -0
- physicskit/rmt/tests/test_jacobi_wachter.py +136 -0
- physicskit/rmt/tests/test_localization.py +240 -0
- physicskit/rmt/tests/test_poisson.py +149 -0
- physicskit/rmt/tests/test_polynomial.py +107 -0
- physicskit/rmt/tests/test_pt_symmetric.py +178 -0
- physicskit/rmt/tests/test_random_state.py +19 -0
- physicskit/rmt/tests/test_real_ginibre.py +112 -0
- physicskit/rmt/tests/test_rigidity_universality.py +167 -0
- physicskit/rmt/tests/test_single_ring.py +132 -0
- physicskit/rmt/tests/test_spacing_and_ratios.py +122 -0
- physicskit/rmt/tests/test_sparse.py +71 -0
- physicskit/rmt/tests/test_spectrum.py +27 -0
- physicskit/rmt/tests/test_syk.py +136 -0
- physicskit/rmt/tests/test_tracy_widom.py +113 -0
- physicskit/rmt/tests/test_tridiagonal.py +41 -0
- physicskit/rmt/tests/test_truncated_unitary.py +80 -0
- physicskit/rmt/tests/test_validation_base.py +25 -0
- physicskit/rmt/tests/test_validation_misc.py +67 -0
- physicskit/rmt/tests/test_wishart_marchenko_pastur.py +120 -0
- physicskit/rmt/utils/__init__.py +0 -0
- physicskit/rmt/utils/haar.py +128 -0
- physicskit/rmt/utils/random_state.py +24 -0
- physicskit/rmt/utils/tridiagonal.py +167 -0
- physicskit/rmt/validation/__init__.py +36 -0
- physicskit/rmt/validation/base.py +126 -0
- physicskit/rmt/validation/circular_law.py +80 -0
- physicskit/rmt/validation/marchenko_pastur.py +53 -0
- physicskit/rmt/validation/ratio_distribution.py +53 -0
- physicskit/rmt/validation/real_ginibre.py +60 -0
- physicskit/rmt/validation/sine_kernel.py +57 -0
- physicskit/rmt/validation/single_ring.py +68 -0
- physicskit/rmt/validation/tracy_widom.py +89 -0
- physicskit/rmt/validation/universality.py +100 -0
- physicskit/rmt/validation/wachter.py +52 -0
- physicskit/rmt/validation/wigner_semicircle.py +40 -0
- physicskit/rmt/validation/wigner_surmise.py +58 -0
- physicskit/semiclassical/__init__.py +94 -0
- physicskit/semiclassical/_compat.py +5 -0
- physicskit/semiclassical/core/__init__.py +41 -0
- physicskit/semiclassical/core/gutzwiller.py +215 -0
- physicskit/semiclassical/core/path_integral.py +594 -0
- physicskit/semiclassical/core/propagators.py +579 -0
- physicskit/semiclassical/core/wkb.py +308 -0
- physicskit/semiclassical/systems/__init__.py +13 -0
- physicskit/semiclassical/systems/scarring.py +278 -0
- physicskit/semiclassical/tests/__init__.py +0 -0
- physicskit/semiclassical/tests/test_gutzwiller.py +35 -0
- physicskit/semiclassical/tests/test_path_integral.py +194 -0
- physicskit/semiclassical/tests/test_propagators.py +82 -0
- physicskit/semiclassical/tests/test_scarring.py +43 -0
- physicskit/semiclassical/tests/test_visualizers.py +89 -0
- physicskit/semiclassical/tests/test_wkb.py +30 -0
- physicskit/semiclassical/visualizers/__init__.py +17 -0
- physicskit/semiclassical/visualizers/gutzwiller.py +55 -0
- physicskit/semiclassical/visualizers/path_integral.py +195 -0
- physicskit/semiclassical/visualizers/propagators.py +89 -0
- physicskit/semiclassical/visualizers/scarring.py +146 -0
- physicskit/semiclassical/visualizers/wkb.py +55 -0
- physicskit/statphys/__init__.py +80 -0
- physicskit/statphys/chapters/__init__.py +43 -0
- physicskit/statphys/chapters/ehrenfest_urn.py +112 -0
- physicskit/statphys/chapters/ising_lattice.py +431 -0
- physicskit/statphys/chapters/kpz_growth.py +129 -0
- physicskit/statphys/chapters/molecular_dynamics.py +258 -0
- physicskit/statphys/chapters/nonequilibrium_work.py +146 -0
- physicskit/statphys/chapters/percolation.py +305 -0
- physicskit/statphys/chapters/random_walk.py +142 -0
- physicskit/statphys/chapters/renormalization.py +148 -0
- physicskit/statphys/chapters/sandpile.py +109 -0
- physicskit/statphys/chapters/spin_glass.py +275 -0
- physicskit/statphys/core/__init__.py +10 -0
- physicskit/statphys/core/kpz_engine.py +53 -0
- physicskit/statphys/core/md_engine.py +157 -0
- physicskit/statphys/core/monte_carlo.py +462 -0
- physicskit/statphys/core/random_walk_engine.py +68 -0
- physicskit/statphys/core/sandpile_engine.py +52 -0
- physicskit/statphys/tests/__init__.py +0 -0
- physicskit/statphys/tests/test_dynamics.py +66 -0
- physicskit/statphys/tests/test_ehrenfest_urn.py +44 -0
- physicskit/statphys/tests/test_finite_size_scaling.py +62 -0
- physicskit/statphys/tests/test_interactive.py +33 -0
- physicskit/statphys/tests/test_ising.py +68 -0
- physicskit/statphys/tests/test_kpz.py +55 -0
- physicskit/statphys/tests/test_landau_theory.py +49 -0
- physicskit/statphys/tests/test_md_engine.py +31 -0
- physicskit/statphys/tests/test_molecular_dynamics.py +72 -0
- physicskit/statphys/tests/test_nonequilibrium_work.py +33 -0
- physicskit/statphys/tests/test_partition_function.py +26 -0
- physicskit/statphys/tests/test_percolation.py +116 -0
- physicskit/statphys/tests/test_potts_model.py +46 -0
- physicskit/statphys/tests/test_random_walk.py +50 -0
- physicskit/statphys/tests/test_renormalization.py +44 -0
- physicskit/statphys/tests/test_sandpile.py +44 -0
- physicskit/statphys/tests/test_spin_glass.py +73 -0
- physicskit/statphys/tests/test_thermodynamics.py +121 -0
- physicskit/statphys/tests/test_xy_model.py +45 -0
- physicskit/statphys/utils/__init__.py +1 -0
- physicskit/statphys/utils/dynamics.py +100 -0
- physicskit/statphys/utils/finite_size_scaling.py +171 -0
- physicskit/statphys/utils/landau_theory.py +151 -0
- physicskit/statphys/utils/partition_function.py +109 -0
- physicskit/statphys/utils/thermodynamics.py +356 -0
- physicskit/statphys/visualizers/__init__.py +87 -0
- physicskit/statphys/visualizers/interactive.py +161 -0
- physicskit/statphys/visualizers/jarzynski_render.py +44 -0
- physicskit/statphys/visualizers/kpz_render.py +65 -0
- physicskit/statphys/visualizers/lattice_render.py +212 -0
- physicskit/statphys/visualizers/particle_render.py +121 -0
- physicskit/statphys/visualizers/random_walk_render.py +106 -0
- physicskit/statphys/visualizers/rg_render.py +45 -0
- physicskit/statphys/visualizers/sandpile_render.py +65 -0
- physicskit/statphys/visualizers/spin_glass_render.py +40 -0
- physicskit/statphys/visualizers/urn_render.py +38 -0
- physicskit/statphys/visualizers/vortex_render.py +84 -0
- physicskit/tests/__init__.py +0 -0
- physicskit/tests/test_constants.py +38 -0
- physicskit-0.1.0.dist-info/METADATA +196 -0
- physicskit-0.1.0.dist-info/RECORD +484 -0
- physicskit-0.1.0.dist-info/WHEEL +5 -0
- physicskit-0.1.0.dist-info/licenses/LICENSE +21 -0
- physicskit-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"""Tests for the chiral ensembles (chGOE, chGUE, chGSE) -- Altland-
|
|
2
|
+
Zirnbauer classes BDI, AIII, CII: block off-diagonal Hamiltonians with
|
|
3
|
+
an anticommuting chiral symmetry, the QCD-type Dirac operator random
|
|
4
|
+
matrix ensembles of Verbaarschot and Zahed.
|
|
5
|
+
|
|
6
|
+
Two independent layers of verification, mirroring the bar set by
|
|
7
|
+
``physicskit.rmt/ensembles/wishart.py`` for the underlying Laguerre machinery:
|
|
8
|
+
(1) the fast production sampler's structural contract (beta, shape,
|
|
9
|
+
+-pairing, exact zero-mode count, reproducibility) -- trivially true by
|
|
10
|
+
construction, but worth asserting as documentation; and (2) an
|
|
11
|
+
independent, direct check on the actual dense block matrix
|
|
12
|
+
H = [[0, W], [W^dagger, 0]] (Hermiticity, exact chiral-symmetry
|
|
13
|
+
anticommutation with Gamma = diag(I, -I), and that its eigenvalues are
|
|
14
|
+
exactly +-singular-values-of-W plus exact zeros) -- confirming the
|
|
15
|
+
"reuse the Laguerre machinery" shortcut actually represents the linear
|
|
16
|
+
algebra it claims to, not merely trusting the module docstring's
|
|
17
|
+
derivation.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import numpy as np
|
|
21
|
+
import pytest
|
|
22
|
+
from cache_utils import cached_sample
|
|
23
|
+
|
|
24
|
+
import physicskit.rmt as rmt
|
|
25
|
+
|
|
26
|
+
CHIRAL = [
|
|
27
|
+
("chGOE", rmt.ensembles.chGOE, 1),
|
|
28
|
+
("chGUE", rmt.ensembles.chGUE, 2),
|
|
29
|
+
("chGSE", rmt.ensembles.chGSE, 4),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
34
|
+
def test_beta_is_correct(name, cls, beta):
|
|
35
|
+
ens = cls(n=30, seed=0)
|
|
36
|
+
assert ens.beta == beta
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
40
|
+
def test_gamma_property(name, cls, beta):
|
|
41
|
+
ens = cls(n=30, nu=10, seed=0)
|
|
42
|
+
assert ens.gamma == pytest.approx(30.0 / 40.0)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
46
|
+
def test_produces_2n_plus_nu_eigenvalues(name, cls, beta):
|
|
47
|
+
ens = cls(n=40, nu=5, seed=1)
|
|
48
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
49
|
+
assert spectrum.eigenvalues.shape == (5, 85)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
53
|
+
def test_eigenvalues_are_real(name, cls, beta):
|
|
54
|
+
ens = cls(n=35, nu=3, seed=2)
|
|
55
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
56
|
+
assert not np.iscomplexobj(spectrum.eigenvalues)
|
|
57
|
+
assert np.all(np.isfinite(spectrum.eigenvalues))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
61
|
+
def test_reproducibility(name, cls, beta):
|
|
62
|
+
ens_a = cls(n=40, nu=4, seed=42)
|
|
63
|
+
ens_b = cls(n=40, nu=4, seed=42)
|
|
64
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
65
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
66
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
70
|
+
def test_spectrum_symmetric_about_zero(name, cls, beta):
|
|
71
|
+
# Chiral symmetry forces exact +-lambda pairing, like BdG -- but via
|
|
72
|
+
# an anticommuting (not commuting) operator; see module docstring.
|
|
73
|
+
ens = cls(n=50, nu=6, seed=3)
|
|
74
|
+
spectrum = cached_sample(ens, n_samples=10)
|
|
75
|
+
for row in spectrum.eigenvalues:
|
|
76
|
+
row_sorted = np.sort(row)
|
|
77
|
+
pairing_error = np.abs(row_sorted + row_sorted[::-1]).max()
|
|
78
|
+
assert pairing_error < 1e-8
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
82
|
+
def test_exact_zero_modes_match_nu(name, cls, beta):
|
|
83
|
+
ens = cls(n=45, nu=7, seed=4)
|
|
84
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
85
|
+
for row in spectrum.eigenvalues:
|
|
86
|
+
n_zeros = np.sum(np.abs(row) < 1e-10)
|
|
87
|
+
assert n_zeros == 7
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
91
|
+
def test_nonzero_eigenvalues_are_nonnegative_singular_values(name, cls, beta):
|
|
92
|
+
# +-sigma_k by construction: exactly half (rounding for nu>0's
|
|
93
|
+
# zeros) of the nonzero eigenvalues are strictly positive, the rest
|
|
94
|
+
# their exact negatives -- already covered by the pairing test, but
|
|
95
|
+
# additionally check the magnitudes are genuinely nonzero (not
|
|
96
|
+
# spuriously landing on/near zero beyond the nu exact zero modes).
|
|
97
|
+
ens = cls(n=30, nu=0, seed=5)
|
|
98
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
99
|
+
nonzero = spectrum.eigenvalues[np.abs(spectrum.eigenvalues) > 1e-10]
|
|
100
|
+
assert len(nonzero) == 5 * 60 # nu=0 -> no exact zeros
|
|
101
|
+
assert np.all(np.abs(nonzero) > 1e-6)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_invalid_parameters_rejected():
|
|
105
|
+
with pytest.raises(ValueError):
|
|
106
|
+
rmt.ensembles.ChiralBetaEnsemble(n=10, beta=0, seed=0)
|
|
107
|
+
with pytest.raises(ValueError):
|
|
108
|
+
rmt.ensembles.chGUE(n=10, nu=-1, seed=0)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_continuum_beta_also_produces_valid_spectrum():
|
|
112
|
+
ens = rmt.ensembles.ChiralBetaEnsemble(n=200, beta=1.7, nu=3, seed=6)
|
|
113
|
+
spectrum = cached_sample(ens, n_samples=10)
|
|
114
|
+
assert spectrum.eigenvalues.shape == (10, 403)
|
|
115
|
+
for row in spectrum.eigenvalues:
|
|
116
|
+
assert np.sum(np.abs(row) < 1e-10) == 3
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# --- Direct, un-cached structural verification of the actual block
|
|
120
|
+
# matrix (independent of the fast Laguerre-reuse sampler above) ---
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
124
|
+
def test_dense_construction_hermitian_and_chiral_symmetric(name, cls, beta):
|
|
125
|
+
from physicskit.rmt.ensembles.chiral import _dense_chiral_hamiltonian
|
|
126
|
+
|
|
127
|
+
rng = np.random.default_rng(7)
|
|
128
|
+
n, nu = 10, 3
|
|
129
|
+
h = _dense_chiral_hamiltonian(n, nu, rng, beta)
|
|
130
|
+
assert np.abs(h - h.conj().T).max() < 1e-10
|
|
131
|
+
|
|
132
|
+
n_dim = n if beta != 4 else 2 * n
|
|
133
|
+
m_dim = (n + nu) if beta != 4 else 2 * (n + nu)
|
|
134
|
+
gamma5 = np.diag(np.concatenate([np.ones(n_dim), -np.ones(m_dim)]))
|
|
135
|
+
anticommutator_residual = gamma5 @ h @ gamma5 + h
|
|
136
|
+
assert np.abs(anticommutator_residual).max() < 1e-10
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@pytest.mark.parametrize("name,cls,beta", CHIRAL)
|
|
140
|
+
def test_dense_construction_eigenvalues_are_singular_values_plus_zeros(name, cls, beta):
|
|
141
|
+
from physicskit.rmt.ensembles.chiral import _dense_chiral_hamiltonian, _sample_block
|
|
142
|
+
|
|
143
|
+
rng = np.random.default_rng(8)
|
|
144
|
+
n, nu = 10, 3
|
|
145
|
+
rng_for_w = np.random.default_rng(8)
|
|
146
|
+
w = _sample_block(n, n + nu, rng_for_w, beta)
|
|
147
|
+
singular_values = np.linalg.svd(w, compute_uv=False)
|
|
148
|
+
|
|
149
|
+
h = _dense_chiral_hamiltonian(n, nu, rng, beta)
|
|
150
|
+
eigs = np.sort(np.linalg.eigvalsh(h))
|
|
151
|
+
|
|
152
|
+
n_dim, m_dim = w.shape
|
|
153
|
+
n_zero_modes = m_dim - n_dim # rank deficiency of W (>= 0 for nu >= 0)
|
|
154
|
+
positive_eigs = eigs[eigs > 1e-8]
|
|
155
|
+
zero_eigs = eigs[np.abs(eigs) <= 1e-8]
|
|
156
|
+
negative_eigs = eigs[eigs < -1e-8]
|
|
157
|
+
|
|
158
|
+
assert len(zero_eigs) == n_zero_modes
|
|
159
|
+
np.testing.assert_allclose(
|
|
160
|
+
np.sort(positive_eigs),
|
|
161
|
+
np.sort(singular_values[singular_values > 1e-8]),
|
|
162
|
+
atol=1e-8,
|
|
163
|
+
)
|
|
164
|
+
np.testing.assert_allclose(np.sort(-negative_eigs), np.sort(positive_eigs), atol=1e-8)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@pytest.mark.parametrize(
|
|
168
|
+
"name,cls,beta",
|
|
169
|
+
[("chGOE", rmt.ensembles.chGOE, 1), ("chGUE", rmt.ensembles.chGUE, 2)],
|
|
170
|
+
)
|
|
171
|
+
def test_fast_sampler_matches_dense_construction_statistically(name, cls, beta):
|
|
172
|
+
# Two-sample KS test between the fast (Laguerre-reuse) sampler's
|
|
173
|
+
# pooled nonzero |eigenvalue|s and the literal dense block matrix's
|
|
174
|
+
# singular values -- the same cross-check standard
|
|
175
|
+
# ``physicskit.rmt/ensembles/wishart.py`` already applies to the underlying
|
|
176
|
+
# bidiagonal trick, done here explicitly for the chiral wrapper
|
|
177
|
+
# rather than just trusted transitively. beta=4 is excluded because
|
|
178
|
+
# the dense construction's explicit quaternion embedding doubles its
|
|
179
|
+
# dimension relative to the fast sampler's generalized-beta n (see
|
|
180
|
+
# module docstring), so the two are not directly comparable sample-
|
|
181
|
+
# for-sample at matched n.
|
|
182
|
+
#
|
|
183
|
+
# Scale note: the fast sampler reuses ``sample_laguerre_beta_eigenvalues``,
|
|
184
|
+
# which returns Marchenko-Pastur-*normalized* eigenvalues -- despite
|
|
185
|
+
# dividing the raw bidiagonal-model product by (beta*m) internally
|
|
186
|
+
# (see ``physicskit.rmt/utils/tridiagonal.py``), it matches dense X^dagger @ X / m
|
|
187
|
+
# for unit-variance X at every beta (confirmed directly here, and
|
|
188
|
+
# already the standard this repo verifies against -- see
|
|
189
|
+
# ``physicskit.rmt/ensembles/wishart.py``'s module docstring), i.e. the
|
|
190
|
+
# beta-dependence is absorbed into the bidiagonal model's chi
|
|
191
|
+
# degrees of freedom, not left over as an extra factor in the
|
|
192
|
+
# normalization. So the dense construction's raw singular values
|
|
193
|
+
# (built from literal unit-variance entries) need only be divided by
|
|
194
|
+
# sqrt(m), not sqrt(beta*m), to land on the same footing.
|
|
195
|
+
from scipy.stats import ks_2samp
|
|
196
|
+
|
|
197
|
+
from physicskit.rmt.ensembles.chiral import _dense_chiral_hamiltonian
|
|
198
|
+
|
|
199
|
+
n, nu = 12, 2
|
|
200
|
+
m = n + nu
|
|
201
|
+
fast_ens = cls(n=n, nu=nu, seed=9)
|
|
202
|
+
fast_spectrum = fast_ens.sample(n_samples=400)
|
|
203
|
+
fast_nonzero = np.abs(fast_spectrum.eigenvalues[np.abs(fast_spectrum.eigenvalues) > 1e-10])
|
|
204
|
+
|
|
205
|
+
rng = np.random.default_rng(10)
|
|
206
|
+
dense_singular_values = []
|
|
207
|
+
for _ in range(400):
|
|
208
|
+
h = _dense_chiral_hamiltonian(n, nu, rng, beta)
|
|
209
|
+
eigs = np.linalg.eigvalsh(h)
|
|
210
|
+
dense_singular_values.append(np.abs(eigs[np.abs(eigs) > 1e-8]))
|
|
211
|
+
dense_nonzero = np.concatenate(dense_singular_values) / np.sqrt(m)
|
|
212
|
+
|
|
213
|
+
ks = ks_2samp(fast_nonzero, dense_nonzero)
|
|
214
|
+
assert ks.statistic < 0.05, f"{name}: fast sampler diverges from dense construction, {ks}"
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# --- QCD Dirac operator convention (D = i*H, purely imaginary spectrum) ---
|
|
218
|
+
|
|
219
|
+
QCD_DIRAC = [
|
|
220
|
+
("QCDDiracGOE", rmt.ensembles.QCDDiracGOE, rmt.ensembles.chGOE, 1),
|
|
221
|
+
("QCDDiracGUE", rmt.ensembles.QCDDiracGUE, rmt.ensembles.chGUE, 2),
|
|
222
|
+
("QCDDiracGSE", rmt.ensembles.QCDDiracGSE, rmt.ensembles.chGSE, 4),
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
|
|
227
|
+
def test_qcd_dirac_beta_is_correct(name, cls, ch_cls, beta):
|
|
228
|
+
ens = cls(n=30, seed=0)
|
|
229
|
+
assert ens.beta == beta
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
@pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
|
|
233
|
+
def test_qcd_dirac_eigenvalues_are_purely_imaginary(name, cls, ch_cls, beta):
|
|
234
|
+
ens = cls(n=40, nu=3, seed=1)
|
|
235
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
236
|
+
assert np.iscomplexobj(spectrum.eigenvalues)
|
|
237
|
+
assert np.abs(spectrum.eigenvalues.real).max() < 1e-10
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
|
|
241
|
+
def test_qcd_dirac_is_exactly_i_times_chiral_ensemble(name, cls, ch_cls, beta):
|
|
242
|
+
# Thin-wrapper contract from the module docstring: D = i*H exactly,
|
|
243
|
+
# for the SAME underlying random draw (matched seed) -- not just
|
|
244
|
+
# matching in distribution.
|
|
245
|
+
dirac_ens = cls(n=25, nu=2, seed=7)
|
|
246
|
+
chiral_ens = ch_cls(n=25, nu=2, seed=7)
|
|
247
|
+
dirac_spectrum = dirac_ens.sample(n_samples=4)
|
|
248
|
+
chiral_spectrum = chiral_ens.sample(n_samples=4)
|
|
249
|
+
np.testing.assert_allclose(dirac_spectrum.eigenvalues, 1j * chiral_spectrum.eigenvalues)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
|
|
253
|
+
def test_qcd_dirac_exact_zero_modes_match_nu(name, cls, ch_cls, beta):
|
|
254
|
+
ens = cls(n=45, nu=6, seed=2)
|
|
255
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
256
|
+
for row in spectrum.eigenvalues:
|
|
257
|
+
assert np.sum(np.abs(row) < 1e-10) == 6
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
@pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
|
|
261
|
+
def test_qcd_dirac_reproducibility(name, cls, ch_cls, beta):
|
|
262
|
+
ens_a = cls(n=30, nu=3, seed=42)
|
|
263
|
+
ens_b = cls(n=30, nu=3, seed=42)
|
|
264
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
265
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
266
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def test_sample_block_rejects_invalid_beta():
|
|
270
|
+
from physicskit.rmt.ensembles.chiral import _sample_block
|
|
271
|
+
|
|
272
|
+
with pytest.raises(ValueError):
|
|
273
|
+
_sample_block(5, 6, np.random.default_rng(0), beta=3)
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Tests for COE, CUE, CSE and the sine kernel benchmark.
|
|
2
|
+
|
|
3
|
+
Circular ensembles are structurally different from the Gaussian/Wishart
|
|
4
|
+
families: COE is NOT "eigenvalues of a Haar-random orthogonal matrix"
|
|
5
|
+
and CSE is NOT "eigenvalues of a Haar-random symplectic matrix" (see the
|
|
6
|
+
warning in the ``physicskit.rmt.ensembles.circular`` module docstring for why).
|
|
7
|
+
These tests check both the structural correctness of each construction
|
|
8
|
+
(unitarity, symmetry/self-duality, exact degeneracy for CSE) and the
|
|
9
|
+
resulting spacing statistics against the already-validated Wigner
|
|
10
|
+
surmise -- an independent cross-family check, since spacing statistics
|
|
11
|
+
are universal in beta across the Gaussian and circular families.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
import pytest
|
|
16
|
+
from cache_utils import cached_sample
|
|
17
|
+
|
|
18
|
+
import physicskit.rmt as rmt
|
|
19
|
+
from physicskit.rmt.utils.haar import haar_unitary, symplectic_form
|
|
20
|
+
|
|
21
|
+
CIRCULAR = [
|
|
22
|
+
("COE", rmt.ensembles.COE, 1),
|
|
23
|
+
("CUE", rmt.ensembles.CUE, 2),
|
|
24
|
+
("CSE", rmt.ensembles.CSE, 4),
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_haar_unitary_is_unitary():
|
|
29
|
+
rng = np.random.default_rng(0)
|
|
30
|
+
u = haar_unitary(150, rng)
|
|
31
|
+
identity_error = np.abs(u.conj().T @ u - np.eye(150)).max()
|
|
32
|
+
assert identity_error < 1e-9
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_haar_unitary_eigenvalues_on_unit_circle():
|
|
36
|
+
rng = np.random.default_rng(1)
|
|
37
|
+
u = haar_unitary(150, rng)
|
|
38
|
+
eigs = np.linalg.eigvals(u)
|
|
39
|
+
assert np.abs(np.abs(eigs) - 1.0).max() < 1e-9
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.mark.parametrize("name,cls,beta", CIRCULAR)
|
|
43
|
+
def test_beta_is_correct(name, cls, beta):
|
|
44
|
+
ens = cls(n=30, seed=0)
|
|
45
|
+
assert ens.beta == beta
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pytest.mark.parametrize("name,cls,beta", CIRCULAR)
|
|
49
|
+
def test_phases_in_valid_range(name, cls, beta):
|
|
50
|
+
ens = cls(n=100, seed=2)
|
|
51
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
52
|
+
assert np.all(spectrum.eigenvalues >= 0.0)
|
|
53
|
+
assert np.all(spectrum.eigenvalues < 2 * np.pi + 1e-9)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@pytest.mark.parametrize("name,cls,beta", CIRCULAR)
|
|
57
|
+
def test_reproducibility(name, cls, beta):
|
|
58
|
+
ens_a = cls(n=80, seed=42)
|
|
59
|
+
ens_b = cls(n=80, seed=42)
|
|
60
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
61
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
62
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@pytest.mark.parametrize("name,cls,beta", CIRCULAR)
|
|
66
|
+
def test_mean_spacing_is_exactly_unity(name, cls, beta):
|
|
67
|
+
# Unlike Gaussian/Wishart, circular ensembles have EXACT rotational
|
|
68
|
+
# invariance at any finite n, so mean spacing should be unity to
|
|
69
|
+
# floating-point precision, not just asymptotically.
|
|
70
|
+
ens = cls(n=200, seed=3)
|
|
71
|
+
spectrum = cached_sample(ens, n_samples=15)
|
|
72
|
+
spacings = rmt.stats.circular_spacings(spectrum)
|
|
73
|
+
assert spacings.mean() == pytest.approx(1.0, abs=1e-9)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@pytest.mark.parametrize("name,cls,beta", CIRCULAR)
|
|
77
|
+
def test_spacing_matches_wigner_surmise_at_matching_beta(name, cls, beta):
|
|
78
|
+
ens = cls(n=250, seed=4)
|
|
79
|
+
spectrum = cached_sample(ens, n_samples=25)
|
|
80
|
+
spacings = rmt.stats.circular_spacings(spectrum)
|
|
81
|
+
benchmark = rmt.validation.WignerSurmise(beta=beta)
|
|
82
|
+
result = benchmark.validate(spacings, seed=4)
|
|
83
|
+
assert result.ks_statistic < 0.02
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_coe_matrix_is_symmetric():
|
|
87
|
+
rng = np.random.default_rng(5)
|
|
88
|
+
v = haar_unitary(100, rng)
|
|
89
|
+
u = v.T @ v
|
|
90
|
+
assert np.abs(u - u.T).max() < 1e-9
|
|
91
|
+
identity_error = np.abs(u.conj().T @ u - np.eye(100)).max()
|
|
92
|
+
assert identity_error < 1e-9 # still unitary
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_cse_dual_matrix_is_self_dual_unitary():
|
|
96
|
+
rng = np.random.default_rng(6)
|
|
97
|
+
n2 = 60
|
|
98
|
+
v = haar_unitary(n2, rng)
|
|
99
|
+
z = symplectic_form(n2)
|
|
100
|
+
v_dual = (-z) @ v.T @ z
|
|
101
|
+
u = v_dual @ v
|
|
102
|
+
identity_error = np.abs(u.conj().T @ u - np.eye(n2)).max()
|
|
103
|
+
assert identity_error < 1e-9
|
|
104
|
+
# Self-duality: U^R == U, where U^R = Z U^T Z^{-1}
|
|
105
|
+
u_dual = (-z) @ u.T @ z
|
|
106
|
+
assert np.abs(u_dual - u).max() < 1e-8
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_cse_eigenvalues_are_doubly_degenerate():
|
|
110
|
+
# inspect the raw (pre-dedup) construction directly
|
|
111
|
+
rng = np.random.default_rng(7)
|
|
112
|
+
from physicskit.rmt.utils.haar import haar_unitary, symplectic_form
|
|
113
|
+
|
|
114
|
+
n2 = 80
|
|
115
|
+
v = haar_unitary(n2, rng)
|
|
116
|
+
z = symplectic_form(n2)
|
|
117
|
+
v_dual = (-z) @ v.T @ z
|
|
118
|
+
u = v_dual @ v
|
|
119
|
+
eigs = np.linalg.eigvals(u)
|
|
120
|
+
theta = np.sort(np.angle(eigs) % (2 * np.pi))
|
|
121
|
+
pair_gaps = np.diff(theta)[0::2] # gaps WITHIN each claimed degenerate pair
|
|
122
|
+
assert np.max(np.abs(pair_gaps)) < 1e-6
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_sine_kernel_matches_cue_correlations():
|
|
126
|
+
ens = rmt.ensembles.CUE(n=400, seed=8)
|
|
127
|
+
spectrum = cached_sample(ens, n_samples=60)
|
|
128
|
+
benchmark = rmt.validation.SineKernel()
|
|
129
|
+
result = benchmark.validate(spectrum)
|
|
130
|
+
assert result.rmse < 0.05
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_sine_kernel_rejects_non_cue_beta():
|
|
134
|
+
ens = rmt.ensembles.COE(n=100, seed=0)
|
|
135
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
136
|
+
benchmark = rmt.validation.SineKernel()
|
|
137
|
+
with pytest.raises(ValueError):
|
|
138
|
+
benchmark.validate(spectrum)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_sine_kernel_zero_at_origin_and_one_at_large_separation():
|
|
142
|
+
r = np.array([0.0, 0.01, 2.0, 5.0])
|
|
143
|
+
r2 = rmt.stats.sine_kernel_r2(r)
|
|
144
|
+
assert r2[0] == pytest.approx(0.0, abs=1e-9)
|
|
145
|
+
assert r2[1] < 0.01 # strong level repulsion near r=0
|
|
146
|
+
assert r2[3] == pytest.approx(1.0, abs=1e-2)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# --- Pfaffian kernel building blocks (S, D, I) ---
|
|
150
|
+
# See physicskit.rmt/stats/correlations.py module docstring: only these three
|
|
151
|
+
# individually-exact building blocks are implemented, NOT their
|
|
152
|
+
# combination into a beta=1/4 two-point correlation function (an
|
|
153
|
+
# attempted reconstruction was checked and ruled out structurally --
|
|
154
|
+
# see that docstring for the Taylor-expansion argument).
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_kernel_s_matches_sine_kernel_component():
|
|
158
|
+
r = np.array([0.0, 0.3, 1.0, 2.5])
|
|
159
|
+
np.testing.assert_allclose(rmt.stats.kernel_s(r) ** 2, 1.0 - rmt.stats.sine_kernel_r2(r), atol=1e-12)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_kernel_d_is_derivative_of_kernel_s():
|
|
163
|
+
r = np.linspace(0.05, 3.0, 20)
|
|
164
|
+
h = 1e-6
|
|
165
|
+
finite_diff = (rmt.stats.kernel_s(r + h) - rmt.stats.kernel_s(r - h)) / (2 * h)
|
|
166
|
+
np.testing.assert_allclose(rmt.stats.kernel_d(r), finite_diff, atol=1e-4)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_kernel_i_is_antiderivative_of_kernel_s():
|
|
170
|
+
from scipy.integrate import quad
|
|
171
|
+
|
|
172
|
+
for r in [0.3, 1.0, 2.0]:
|
|
173
|
+
expected, _ = quad(lambda t: rmt.stats.kernel_s(np.array([t]))[0], 0, r)
|
|
174
|
+
assert rmt.stats.kernel_i(np.array([r]))[0] == pytest.approx(expected, abs=1e-6)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_kernel_d_is_odd_and_kernel_s_is_even():
|
|
178
|
+
r = np.array([0.2, 0.7, 1.5])
|
|
179
|
+
np.testing.assert_allclose(rmt.stats.kernel_s(-r), rmt.stats.kernel_s(r))
|
|
180
|
+
np.testing.assert_allclose(rmt.stats.kernel_d(-r), -rmt.stats.kernel_d(r))
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# --- general k-point determinantal correlation function (CUE) ---
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_k_point_correlation_reduces_to_sine_kernel_r2_at_k_2():
|
|
187
|
+
r = 0.7
|
|
188
|
+
value = rmt.stats.k_point_correlation(np.array([0.0, r]))
|
|
189
|
+
assert value == pytest.approx(rmt.stats.sine_kernel_r2(np.array([r]))[0])
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def test_k_point_correlation_vanishes_at_coincident_points():
|
|
193
|
+
# Level repulsion at all orders: a determinant with two identical
|
|
194
|
+
# rows (coincident positions) is exactly zero.
|
|
195
|
+
value = rmt.stats.k_point_correlation(np.array([0.0, 0.0, 1.5]))
|
|
196
|
+
assert value == pytest.approx(0.0, abs=1e-12)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_k_point_correlation_factorizes_at_large_separation():
|
|
200
|
+
# Cluster decomposition: R_3(x1, x2, x3) -> R_2(x1, x2) as x3 -> infinity.
|
|
201
|
+
r = 0.7
|
|
202
|
+
r2 = rmt.stats.sine_kernel_r2(np.array([r]))[0]
|
|
203
|
+
r3_near = rmt.stats.k_point_correlation(np.array([0.0, r, 5.0]))
|
|
204
|
+
r3_far = rmt.stats.k_point_correlation(np.array([0.0, r, 500.0]))
|
|
205
|
+
assert abs(r3_far - r2) < abs(r3_near - r2)
|
|
206
|
+
assert r3_far == pytest.approx(r2, abs=1e-4)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def test_level_repulsion_strength_orders_cse_cue_coe():
|
|
210
|
+
# Robust, exponent-free qualitative check (see correlations.py
|
|
211
|
+
# module docstring for why the exact beta=1/4 exponents/kernels are
|
|
212
|
+
# not asserted here): near a fixed small separation, the two-point
|
|
213
|
+
# correlation (level repulsion) should order CSE << CUE << COE,
|
|
214
|
+
# matching beta=4 > beta=2 > beta=1 repulsion strength.
|
|
215
|
+
n = 300
|
|
216
|
+
r_probe = 0.1
|
|
217
|
+
values = {}
|
|
218
|
+
ensembles = [("COE", rmt.ensembles.COE), ("CUE", rmt.ensembles.CUE), ("CSE", rmt.ensembles.CSE)]
|
|
219
|
+
for name, cls in ensembles:
|
|
220
|
+
ens = cls(n=n, seed=0)
|
|
221
|
+
spectrum = cached_sample(ens, n_samples=60)
|
|
222
|
+
centers, empirical = rmt.stats.pair_correlation_estimate(spectrum, r_max=1.0, n_bins=50)
|
|
223
|
+
idx = np.argmin(np.abs(centers - r_probe))
|
|
224
|
+
values[name] = empirical[idx]
|
|
225
|
+
assert values["CSE"] < values["CUE"] < values["COE"]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Tests for GOEGUECrossoverEnsemble.
|
|
2
|
+
|
|
3
|
+
The natural_scale formula sqrt(n*(1+lambda^2)) and the crossover
|
|
4
|
+
behavior in level statistics (ratio statistic KS distance to the GOE
|
|
5
|
+
and GUE surmises) were both verified numerically during development
|
|
6
|
+
before being used here -- see module docstring in
|
|
7
|
+
``physicskit.rmt/ensembles/crossover.py``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import pytest
|
|
12
|
+
from cache_utils import cached_sample
|
|
13
|
+
from scipy.stats import kstest
|
|
14
|
+
|
|
15
|
+
import physicskit.rmt as rmt
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_lambda_0_recovers_goe_natural_scale():
|
|
19
|
+
ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=200, lam=0.0, seed=0)
|
|
20
|
+
assert ens.natural_scale() == pytest.approx(np.sqrt(200))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_natural_scale_matches_verified_formula():
|
|
24
|
+
n, lam = 300, 0.5
|
|
25
|
+
ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=n, lam=lam, seed=0)
|
|
26
|
+
assert ens.natural_scale() == pytest.approx(np.sqrt(n * (1 + lam**2)))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_negative_lambda_rejected():
|
|
30
|
+
with pytest.raises(ValueError):
|
|
31
|
+
rmt.ensembles.GOEGUECrossoverEnsemble(n=10, lam=-1.0, seed=0)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_reproducibility():
|
|
35
|
+
ens_a = rmt.ensembles.GOEGUECrossoverEnsemble(n=40, lam=0.3, seed=42)
|
|
36
|
+
ens_b = rmt.ensembles.GOEGUECrossoverEnsemble(n=40, lam=0.3, seed=42)
|
|
37
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
38
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
39
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_lambda_0_matches_goe_ratio_statistics():
|
|
43
|
+
ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=400, lam=0.0, seed=1)
|
|
44
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
45
|
+
ratios = rmt.stats.ratio_statistics(spectrum)
|
|
46
|
+
ks = kstest(ratios, rmt.stats.RatioSurmise(beta=1).cdf).statistic
|
|
47
|
+
assert ks < 0.03
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_large_lambda_matches_gue_ratio_statistics():
|
|
51
|
+
ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=400, lam=1.0, seed=2)
|
|
52
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
53
|
+
ratios = rmt.stats.ratio_statistics(spectrum)
|
|
54
|
+
ks = kstest(ratios, rmt.stats.RatioSurmise(beta=2).cdf).statistic
|
|
55
|
+
assert ks < 0.03
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_crossover_is_monotonic_between_goe_and_gue():
|
|
59
|
+
# As lambda grows from 0, KS distance to GOE should grow while KS
|
|
60
|
+
# distance to GUE should shrink -- the defining crossover behavior.
|
|
61
|
+
goe_model = rmt.stats.RatioSurmise(beta=1)
|
|
62
|
+
gue_model = rmt.stats.RatioSurmise(beta=2)
|
|
63
|
+
ks_goe = []
|
|
64
|
+
ks_gue = []
|
|
65
|
+
for lam in [0.0, 0.05, 1.0]:
|
|
66
|
+
ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=400, lam=lam, seed=3)
|
|
67
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
68
|
+
ratios = rmt.stats.ratio_statistics(spectrum)
|
|
69
|
+
ks_goe.append(kstest(ratios, goe_model.cdf).statistic)
|
|
70
|
+
ks_gue.append(kstest(ratios, gue_model.cdf).statistic)
|
|
71
|
+
assert ks_goe[0] < ks_goe[1] < ks_goe[2]
|
|
72
|
+
assert ks_gue[0] > ks_gue[1] > ks_gue[2]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Coverage for physicskit.rmt.stats.density.empirical_density (previously
|
|
2
|
+
never called anywhere in the codebase)."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
import physicskit.rmt as rmt
|
|
9
|
+
from physicskit.rmt.stats.density import empirical_density
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_empirical_density_rescaled_and_raw():
|
|
13
|
+
ens = rmt.ensembles.GOE(n=20, seed=0)
|
|
14
|
+
spectrum = ens.sample(n_samples=5)
|
|
15
|
+
|
|
16
|
+
centers_r, counts_r = empirical_density(spectrum, bins=20, rescaled=True)
|
|
17
|
+
assert centers_r.shape == counts_r.shape == (20,)
|
|
18
|
+
assert np.all(np.isfinite(counts_r))
|
|
19
|
+
|
|
20
|
+
centers_raw, counts_raw = empirical_density(spectrum, bins=20, rescaled=False)
|
|
21
|
+
assert centers_raw.shape == counts_raw.shape == (20,)
|
|
22
|
+
assert np.all(np.isfinite(counts_raw))
|
|
23
|
+
assert not np.allclose(centers_r, centers_raw) # genuinely different scale
|