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,122 @@
|
|
|
1
|
+
"""Tests for the nearest-neighbor spacing distribution, the ratio
|
|
2
|
+
statistic, and their respective surmises.
|
|
3
|
+
|
|
4
|
+
Important methodological distinction from ``test_gaussian_semicircle.py``:
|
|
5
|
+
the Wigner semicircle law is the *exact* N -> infinity limit, so its KS
|
|
6
|
+
distance to a sampled ensemble should shrink toward zero as N grows. The
|
|
7
|
+
Wigner surmise (spacing) and the Atas et al. (2013) surmise (ratio) are
|
|
8
|
+
NOT exact limits -- they are known, very good, but imperfect
|
|
9
|
+
approximations (a fixed ~0.1-1% level discrepancy from the true limiting
|
|
10
|
+
distribution, which involves Fredholm-determinant sine-kernel statistics
|
|
11
|
+
with no elementary closed form). That gap does not vanish as N grows, so
|
|
12
|
+
these tests check "already small at moderate N" rather than "shrinks to
|
|
13
|
+
zero" -- asserting the latter would eventually fail once N is large
|
|
14
|
+
enough for the surmise's own approximation error to dominate over
|
|
15
|
+
finite-size noise, which is expected behavior, not a defect.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
import pytest
|
|
20
|
+
from cache_utils import cached_sample
|
|
21
|
+
|
|
22
|
+
import physicskit.rmt as rmt
|
|
23
|
+
|
|
24
|
+
CLASSICAL = [
|
|
25
|
+
("GOE", rmt.ensembles.GOE, 1),
|
|
26
|
+
("GUE", rmt.ensembles.GUE, 2),
|
|
27
|
+
("GSE", rmt.ensembles.GSE, 4),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# Exact surmise-mean reference values (Atas et al. 2013), NOT the
|
|
31
|
+
# numerically-exact full-ensemble means (which differ at the ~1% level --
|
|
32
|
+
# see docstring in physicskit.rmt/stats/ratios.py).
|
|
33
|
+
RATIO_SURMISE_EXACT_MEANS = {
|
|
34
|
+
1: 4 - 2 * np.sqrt(3), # 0.535898...
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.mark.parametrize("name,cls,beta", CLASSICAL)
|
|
39
|
+
def test_unfolded_mean_spacing_is_unity(name, cls, beta):
|
|
40
|
+
ens = cls(n=1000, seed=10)
|
|
41
|
+
spectrum = cached_sample(ens, n_samples=30)
|
|
42
|
+
spacings = rmt.stats.nearest_neighbor_spacings(spectrum, rmt.stats.semicircle_cdf)
|
|
43
|
+
assert spacings.mean() == pytest.approx(1.0, abs=0.01)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@pytest.mark.parametrize("name,cls,beta", CLASSICAL)
|
|
47
|
+
def test_spacing_distribution_matches_surmise_at_moderate_n(name, cls, beta):
|
|
48
|
+
# Moderate N and sample count deliberately: pooling an enormous number
|
|
49
|
+
# of spacings would give the KS test enough power to reject on the
|
|
50
|
+
# surmise's own known small approximation error rather than anything
|
|
51
|
+
# wrong with the implementation (see module docstring).
|
|
52
|
+
ens = cls(n=1000, seed=20)
|
|
53
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
54
|
+
spacings = rmt.stats.nearest_neighbor_spacings(spectrum, rmt.stats.semicircle_cdf)
|
|
55
|
+
|
|
56
|
+
benchmark = rmt.validation.WignerSurmise(beta=beta)
|
|
57
|
+
result = benchmark.validate(spacings, seed=20)
|
|
58
|
+
assert result.ks_statistic < 0.015
|
|
59
|
+
assert result.wasserstein_distance < 0.01
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.mark.parametrize("name,cls,beta", CLASSICAL)
|
|
63
|
+
def test_ratio_statistics_in_unit_interval(name, cls, beta):
|
|
64
|
+
ens = cls(n=500, seed=30)
|
|
65
|
+
spectrum = cached_sample(ens, n_samples=10)
|
|
66
|
+
ratios = rmt.stats.ratio_statistics(spectrum)
|
|
67
|
+
assert np.all(ratios >= 0.0)
|
|
68
|
+
assert np.all(ratios <= 1.0)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@pytest.mark.parametrize("name,cls,beta", CLASSICAL)
|
|
72
|
+
def test_ratio_distribution_matches_surmise_at_moderate_n(name, cls, beta):
|
|
73
|
+
ens = cls(n=1000, seed=40)
|
|
74
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
75
|
+
ratios = rmt.stats.ratio_statistics(spectrum)
|
|
76
|
+
|
|
77
|
+
benchmark = rmt.validation.RatioDistribution(beta=beta)
|
|
78
|
+
result = benchmark.validate(ratios, seed=40)
|
|
79
|
+
assert result.ks_statistic < 0.02
|
|
80
|
+
assert result.wasserstein_distance < 0.01
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_ratio_surmise_exact_mean_matches_atas_et_al():
|
|
84
|
+
# The surmise's OWN mean (not the full-ensemble numerical mean) has a
|
|
85
|
+
# known closed form at beta=1: 4 - 2*sqrt(3). This checks the surmise
|
|
86
|
+
# model itself, independent of any sampling.
|
|
87
|
+
model = rmt.stats.RatioSurmise(beta=1)
|
|
88
|
+
grid = np.linspace(0, 1, 200_000)
|
|
89
|
+
mean_r = np.trapezoid(grid * model.pdf(grid), grid)
|
|
90
|
+
assert mean_r == pytest.approx(RATIO_SURMISE_EXACT_MEANS[1], abs=1e-3)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@pytest.mark.parametrize("name,cls,beta", CLASSICAL)
|
|
94
|
+
def test_spacing_and_ratio_agree_independently(name, cls, beta):
|
|
95
|
+
# The spacing distribution requires unfolding; the ratio statistic
|
|
96
|
+
# does not. If an unfolding bug were inflating apparent agreement (or
|
|
97
|
+
# disagreement) in the spacing test, the ratio test -- computed on
|
|
98
|
+
# raw eigenvalues -- would not be affected the same way. Checking
|
|
99
|
+
# both pass together (loosely) guards against that class of bug.
|
|
100
|
+
ens = cls(n=1200, seed=50)
|
|
101
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
102
|
+
|
|
103
|
+
spacings = rmt.stats.nearest_neighbor_spacings(spectrum, rmt.stats.semicircle_cdf)
|
|
104
|
+
spacing_result = rmt.validation.WignerSurmise(beta=beta).validate(spacings, seed=50)
|
|
105
|
+
|
|
106
|
+
ratios = rmt.stats.ratio_statistics(spectrum)
|
|
107
|
+
ratio_result = rmt.validation.RatioDistribution(beta=beta).validate(ratios, seed=50)
|
|
108
|
+
|
|
109
|
+
assert spacing_result.ks_statistic < 0.02
|
|
110
|
+
assert ratio_result.ks_statistic < 0.02
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_ratio_statistics_and_spacings_skip_rows_too_short_after_edge_trim():
|
|
114
|
+
# edge_trim=0.5 on a small n leaves fewer than the required minimum
|
|
115
|
+
# eigenvalues per row, so every row is skipped (the "continue" guard)
|
|
116
|
+
# and pooling across zero surviving rows raises downstream.
|
|
117
|
+
ens = rmt.ensembles.GOE(n=5, seed=0)
|
|
118
|
+
spectrum = ens.sample(n_samples=3)
|
|
119
|
+
with pytest.raises(ValueError):
|
|
120
|
+
rmt.stats.ratio_statistics(spectrum, edge_trim=0.5)
|
|
121
|
+
with pytest.raises(ValueError):
|
|
122
|
+
rmt.stats.nearest_neighbor_spacings(spectrum, rmt.stats.semicircle_cdf, edge_trim=0.5)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Tests for the sparse random matrix ensembles (ErdosRenyiEnsemble,
|
|
2
|
+
BernoulliWignerEnsemble).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pytest
|
|
7
|
+
from cache_utils import cached_sample
|
|
8
|
+
|
|
9
|
+
import physicskit.rmt as rmt
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_invalid_p_rejected():
|
|
13
|
+
with pytest.raises(ValueError):
|
|
14
|
+
rmt.ensembles.ErdosRenyiEnsemble(n=10, p=0.0, seed=0)
|
|
15
|
+
with pytest.raises(ValueError):
|
|
16
|
+
rmt.ensembles.BernoulliWignerEnsemble(n=10, p=1.5, seed=0)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_erdos_renyi_reproducibility():
|
|
20
|
+
ens_a = rmt.ensembles.ErdosRenyiEnsemble(n=40, p=0.2, seed=42)
|
|
21
|
+
ens_b = rmt.ensembles.ErdosRenyiEnsemble(n=40, p=0.2, seed=42)
|
|
22
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
23
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
24
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_erdos_renyi_has_furedi_komlos_outlier():
|
|
28
|
+
# The largest eigenvalue should sit near the mean degree n*p,
|
|
29
|
+
# well separated from the sqrt(n*p*(1-p))-scale bulk.
|
|
30
|
+
n, p = 1500, 0.05
|
|
31
|
+
ens = rmt.ensembles.ErdosRenyiEnsemble(n=n, p=p, seed=1)
|
|
32
|
+
spectrum = cached_sample(ens, n_samples=3)
|
|
33
|
+
mean_degree = n * p
|
|
34
|
+
largest = spectrum.eigenvalues.max(axis=1)
|
|
35
|
+
assert np.all(np.abs(largest - mean_degree) < 0.15 * mean_degree)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_erdos_renyi_bulk_approaches_semicircle_scale_when_dense():
|
|
39
|
+
# In the crossover regime (n*p large), the BULK (all but the top
|
|
40
|
+
# outlier) should stay within the semicircle radius
|
|
41
|
+
# 2*sqrt(n*p*(1-p)) up to a modest finite-size margin.
|
|
42
|
+
n, p = 2000, 0.1
|
|
43
|
+
ens = rmt.ensembles.ErdosRenyiEnsemble(n=n, p=p, seed=2)
|
|
44
|
+
spectrum = cached_sample(ens, n_samples=3)
|
|
45
|
+
scale = ens.natural_scale()
|
|
46
|
+
for row in spectrum.eigenvalues:
|
|
47
|
+
bulk = np.sort(row)[:-1] # drop the single largest (outlier)
|
|
48
|
+
assert bulk.max() < 2.2 * scale
|
|
49
|
+
assert bulk.min() > -2.2 * scale
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_bernoulli_wigner_reproducibility():
|
|
53
|
+
ens_a = rmt.ensembles.BernoulliWignerEnsemble(n=40, p=0.3, seed=42)
|
|
54
|
+
ens_b = rmt.ensembles.BernoulliWignerEnsemble(n=40, p=0.3, seed=42)
|
|
55
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
56
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
57
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.mark.parametrize("p", [0.3, 0.05, 0.01])
|
|
61
|
+
def test_bernoulli_wigner_matches_semicircle_even_when_sparse(p):
|
|
62
|
+
# No Furedi-Komlos outlier here (mean-zero entries) -- the bulk
|
|
63
|
+
# should match the semicircle law directly, validated against the
|
|
64
|
+
# already-implemented WignerSemicircle benchmark, even at
|
|
65
|
+
# substantial sparsity (as long as n*p stays reasonably large).
|
|
66
|
+
n = 2000
|
|
67
|
+
ens = rmt.ensembles.BernoulliWignerEnsemble(n=n, p=p, seed=3)
|
|
68
|
+
spectrum = cached_sample(ens, n_samples=10)
|
|
69
|
+
benchmark = rmt.validation.WignerSemicircle()
|
|
70
|
+
result = benchmark.validate(spectrum, seed=3)
|
|
71
|
+
assert result.ks_statistic < 0.03
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Coverage for physicskit.rmt.spectrum.Spectrum's simple derived properties
|
|
2
|
+
and __repr__ (previously never exercised directly)."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
import physicskit.rmt as rmt
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_flat_ravels_all_samples():
|
|
12
|
+
ens = rmt.ensembles.GOE(n=5, seed=0)
|
|
13
|
+
spectrum = ens.sample(n_samples=3)
|
|
14
|
+
assert spectrum.flat.shape == (15,)
|
|
15
|
+
np.testing.assert_allclose(spectrum.flat, spectrum.eigenvalues.ravel())
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_n_samples_matches_first_axis():
|
|
19
|
+
ens = rmt.ensembles.GOE(n=5, seed=0)
|
|
20
|
+
spectrum = ens.sample(n_samples=4)
|
|
21
|
+
assert spectrum.n_samples == 4
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_repr_contains_ensemble_name_and_n_samples():
|
|
25
|
+
ens = rmt.ensembles.GOE(n=5, seed=0)
|
|
26
|
+
spectrum = ens.sample(n_samples=2)
|
|
27
|
+
assert repr(spectrum) == f"Spectrum(ensemble='GOE', n=5, beta={spectrum.beta}, n_samples=2)"
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Tests for the Sachdev-Ye-Kitaev (SYK) ensemble.
|
|
2
|
+
|
|
3
|
+
Unlike every other ensemble in this package, SYK is not built from
|
|
4
|
+
i.i.d. matrix entries -- it's an explicit many-body Hamiltonian on an
|
|
5
|
+
exponentially large (2**(N/2)-dimensional) Hilbert space. Validation
|
|
6
|
+
here is therefore structural (Clifford algebra, Hermiticity, the exact
|
|
7
|
+
algebraic reason q=4 needs no phase but q=2 needs a factor of i) rather
|
|
8
|
+
than against a closed-form limiting spectral density, which -- unlike
|
|
9
|
+
the semicircle/Marchenko-Pastur/circular laws elsewhere in this package
|
|
10
|
+
-- has no simple exact form for general q at finite N. Kept to small N
|
|
11
|
+
throughout (cost is exponential in N, not polynomial -- see the module
|
|
12
|
+
docstring).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import math
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
import pytest
|
|
19
|
+
from cache_utils import cached_sample
|
|
20
|
+
|
|
21
|
+
import physicskit.rmt as rmt
|
|
22
|
+
from physicskit.rmt.ensembles.syk import _sample_syk_hamiltonian, majorana_operators
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.mark.parametrize("n", [4, 6, 8])
|
|
26
|
+
def test_majorana_operators_are_hermitian(n):
|
|
27
|
+
for gamma in majorana_operators(n):
|
|
28
|
+
assert np.abs(gamma - gamma.conj().T).max() < 1e-12
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.mark.parametrize("n", [4, 6, 8])
|
|
32
|
+
def test_majorana_operators_satisfy_clifford_algebra(n):
|
|
33
|
+
gammas = majorana_operators(n)
|
|
34
|
+
dim = gammas[0].shape[0]
|
|
35
|
+
identity = np.eye(dim)
|
|
36
|
+
for a in range(n):
|
|
37
|
+
for b in range(n):
|
|
38
|
+
anticommutator = gammas[a] @ gammas[b] + gammas[b] @ gammas[a]
|
|
39
|
+
target = 2.0 * identity if a == b else np.zeros((dim, dim))
|
|
40
|
+
assert np.abs(anticommutator - target).max() < 1e-10
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_majorana_operators_reject_odd_n():
|
|
44
|
+
with pytest.raises(ValueError):
|
|
45
|
+
majorana_operators(5)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pytest.mark.parametrize("q,should_need_phase", [(2, True), (4, False), (6, True), (8, False)])
|
|
49
|
+
def test_raw_q_body_product_hermiticity_matches_derivation(q, should_need_phase):
|
|
50
|
+
# Reversing q distinct anticommuting Majoranas picks up sign
|
|
51
|
+
# (-1)**(q*(q-1)/2) -- the raw (no i**(q/2) prefactor) product should
|
|
52
|
+
# be Hermitian exactly when that sign is +1, i.e. exactly when
|
|
53
|
+
# should_need_phase is False. This is the algebraic fact the
|
|
54
|
+
# i**(q/2) prefactor in the module docstring is derived from;
|
|
55
|
+
# checked directly here rather than only trusted from the derivation.
|
|
56
|
+
n = 8
|
|
57
|
+
gammas = majorana_operators(n)
|
|
58
|
+
idx = list(range(q))
|
|
59
|
+
term = gammas[idx[0]]
|
|
60
|
+
for i in idx[1:]:
|
|
61
|
+
term = term @ gammas[i]
|
|
62
|
+
is_hermitian = np.abs(term - term.conj().T).max() < 1e-10
|
|
63
|
+
assert is_hermitian == (not should_need_phase)
|
|
64
|
+
# With the i**(q/2) prefactor applied, it should always be Hermitian.
|
|
65
|
+
phased = (1j ** (q // 2)) * term
|
|
66
|
+
assert np.abs(phased - phased.conj().T).max() < 1e-10
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_beta_is_none():
|
|
70
|
+
ens = rmt.ensembles.SYKEnsemble(n=8, seed=0)
|
|
71
|
+
assert ens.beta is None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_default_q_is_four():
|
|
75
|
+
ens = rmt.ensembles.SYKEnsemble(n=8, seed=0)
|
|
76
|
+
assert ens.q == 4
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@pytest.mark.parametrize("n", [4, 6, 8, 10])
|
|
80
|
+
def test_produces_2_pow_n_over_2_real_eigenvalues(n):
|
|
81
|
+
ens = rmt.ensembles.SYKEnsemble(n=n, seed=1)
|
|
82
|
+
spectrum = cached_sample(ens, n_samples=3)
|
|
83
|
+
assert spectrum.eigenvalues.shape == (3, 2 ** (n // 2))
|
|
84
|
+
assert not np.iscomplexobj(spectrum.eigenvalues)
|
|
85
|
+
assert np.all(np.isfinite(spectrum.eigenvalues))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_reproducibility():
|
|
89
|
+
ens_a = rmt.ensembles.SYKEnsemble(n=8, seed=42)
|
|
90
|
+
ens_b = rmt.ensembles.SYKEnsemble(n=8, seed=42)
|
|
91
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
92
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
93
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_invalid_parameters_rejected():
|
|
97
|
+
with pytest.raises(ValueError):
|
|
98
|
+
rmt.ensembles.SYKEnsemble(n=7, seed=0) # odd n
|
|
99
|
+
with pytest.raises(ValueError):
|
|
100
|
+
rmt.ensembles.SYKEnsemble(n=8, q=3, seed=0) # odd q
|
|
101
|
+
with pytest.raises(ValueError):
|
|
102
|
+
rmt.ensembles.SYKEnsemble(n=8, q=10, seed=0) # q > n
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_q_two_produces_a_finite_nondegenerate_free_fermion_spectrum():
|
|
106
|
+
# q=2 is the (non-chaotic) free-fermion special case: H is built
|
|
107
|
+
# from a single random N x N antisymmetric coupling matrix rather
|
|
108
|
+
# than C(N,4) independent ones. Just check it produces a sane,
|
|
109
|
+
# genuinely nonzero-scale spectrum -- not a specific numeric target,
|
|
110
|
+
# since the exact eigenvalue scale for q=2 (checked empirically
|
|
111
|
+
# during development to grow roughly like sqrt(N), not stay O(1) the
|
|
112
|
+
# way q=4's does) isn't asserted here.
|
|
113
|
+
ens = rmt.ensembles.SYKEnsemble(n=10, q=2, coupling=1.0, seed=3)
|
|
114
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
115
|
+
assert np.all(np.isfinite(spectrum.eigenvalues))
|
|
116
|
+
assert spectrum.eigenvalues.std() > 0.1
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_coupling_scales_hamiltonian_linearly():
|
|
120
|
+
n, q = 8, 4
|
|
121
|
+
gammas = majorana_operators(n)
|
|
122
|
+
h1 = _sample_syk_hamiltonian(n, q, 1.0, np.random.default_rng(5), gammas)
|
|
123
|
+
h2 = _sample_syk_hamiltonian(n, q, 2.0, np.random.default_rng(5), gammas)
|
|
124
|
+
np.testing.assert_allclose(h2, 2.0 * h1)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_variance_normalization_matches_maldacena_stanford():
|
|
128
|
+
# <J_{i1...iq}^2> = (q-1)! * J^2 / N^(q-1) -- checked directly against
|
|
129
|
+
# the empirical variance of many independently drawn couplings,
|
|
130
|
+
# rather than only trusted from the module docstring's citation.
|
|
131
|
+
n, q, coupling = 12, 4, 1.5
|
|
132
|
+
rng = np.random.default_rng(6)
|
|
133
|
+
expected_variance = math.factorial(q - 1) * coupling**2 / n ** (q - 1)
|
|
134
|
+
std = math.sqrt(expected_variance)
|
|
135
|
+
draws = rng.normal(0.0, std, size=200_000)
|
|
136
|
+
assert draws.var() == pytest.approx(expected_variance, rel=0.05)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Tests for the Painleve II solution and the Tracy-Widom soft-edge
|
|
2
|
+
benchmark.
|
|
3
|
+
|
|
4
|
+
Two things were determined empirically during development, not assumed
|
|
5
|
+
from memory, and are worth testing explicitly here rather than only in
|
|
6
|
+
the module docstring: (1) q(x)'s known asymptotic tail
|
|
7
|
+
q(x) ~ sqrt(-x/2) as x -> -infinity, and (2) the beta=4 (GSE) edge
|
|
8
|
+
scaling requires (2n)^(2/3), not n^(2/3) -- confirmed by direct
|
|
9
|
+
comparison against Monte Carlo GSE samples via a KS test, since the
|
|
10
|
+
half-remembered formula did NOT match without this factor.
|
|
11
|
+
|
|
12
|
+
Note on statistical power: the largest eigenvalue is a single
|
|
13
|
+
extreme-value statistic per matrix sample, so pooling matters much less
|
|
14
|
+
than the bulk-statistic benchmarks (each sample of GOE/GUE/GSE
|
|
15
|
+
contributes exactly one data point to the edge-statistic distribution).
|
|
16
|
+
n_samples in these tests is correspondingly large (hundreds), unlike
|
|
17
|
+
elsewhere in the test suite.
|
|
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
|
+
|
|
27
|
+
def test_painleve_ii_matches_known_asymptotic_tail():
|
|
28
|
+
# Re-derive q via the same ODE construction used internally, at a
|
|
29
|
+
# couple of points in the asymptotic regime, and compare to the
|
|
30
|
+
# known analytic tail sqrt(-x/2).
|
|
31
|
+
from scipy.integrate import solve_ivp
|
|
32
|
+
from scipy.special import airy
|
|
33
|
+
|
|
34
|
+
def rhs(x, y):
|
|
35
|
+
qv, qp = y
|
|
36
|
+
return [qp, x * qv + 2.0 * qv**3]
|
|
37
|
+
|
|
38
|
+
x0 = 6.0
|
|
39
|
+
ai, aip, _, _ = airy(x0)
|
|
40
|
+
ivp = solve_ivp(rhs, [x0, -6.0], [ai, aip], dense_output=True, rtol=1e-12, atol=1e-14, max_step=0.005)
|
|
41
|
+
for x in [-6.0, -5.0, -4.0]:
|
|
42
|
+
q_val = ivp.sol(x)[0]
|
|
43
|
+
asymptotic = np.sqrt(-x / 2.0)
|
|
44
|
+
assert q_val == pytest.approx(asymptotic, rel=0.01)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_cdfs_are_monotonic_and_span_zero_to_one():
|
|
48
|
+
grid = np.linspace(-6, 6, 200)
|
|
49
|
+
for beta in (1, 2, 4):
|
|
50
|
+
cdf = rmt.stats.tracy_widom_cdf(grid, beta)
|
|
51
|
+
assert np.all(np.diff(cdf) >= -1e-10) # monotone non-decreasing
|
|
52
|
+
assert cdf[0] < 0.01
|
|
53
|
+
assert cdf[-1] > 0.99
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_unsupported_beta_rejected():
|
|
57
|
+
with pytest.raises(ValueError):
|
|
58
|
+
rmt.stats.tracy_widom_cdf(0.0, beta=1.7)
|
|
59
|
+
with pytest.raises(ValueError):
|
|
60
|
+
rmt.validation.TracyWidom(beta=3)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_edge_scale_beta4_has_extra_factor_of_two():
|
|
64
|
+
n = 500
|
|
65
|
+
scale_1 = rmt.stats.tracy_widom_edge_scale(n, beta=1)
|
|
66
|
+
scale_2 = rmt.stats.tracy_widom_edge_scale(n, beta=2)
|
|
67
|
+
scale_4 = rmt.stats.tracy_widom_edge_scale(n, beta=4)
|
|
68
|
+
assert scale_1 == pytest.approx(n ** (2 / 3))
|
|
69
|
+
assert scale_2 == pytest.approx(n ** (2 / 3))
|
|
70
|
+
assert scale_4 == pytest.approx((2 * n) ** (2 / 3))
|
|
71
|
+
assert scale_4 != pytest.approx(scale_1) # the easy-to-miss distinction
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_edge_scale_and_rvs_reject_unsupported_beta():
|
|
75
|
+
with pytest.raises(ValueError):
|
|
76
|
+
rmt.stats.tracy_widom_edge_scale(100, beta=3)
|
|
77
|
+
with pytest.raises(ValueError):
|
|
78
|
+
rmt.stats.tracy_widom_rvs(5, beta=3, rng=np.random.default_rng(0))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
GAUSSIAN_TW = [
|
|
82
|
+
("GOE", rmt.ensembles.GOE, 1),
|
|
83
|
+
("GUE", rmt.ensembles.GUE, 2),
|
|
84
|
+
("GSE", rmt.ensembles.GSE, 4),
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@pytest.mark.parametrize("name,cls,beta", GAUSSIAN_TW)
|
|
89
|
+
def test_largest_eigenvalue_matches_tracy_widom(name, cls, beta):
|
|
90
|
+
ens = cls(n=500, seed=10)
|
|
91
|
+
spectrum = cached_sample(ens, n_samples=400)
|
|
92
|
+
benchmark = rmt.validation.TracyWidom(beta=beta)
|
|
93
|
+
result = benchmark.validate(spectrum, seed=10)
|
|
94
|
+
assert result.ks_statistic < 0.08
|
|
95
|
+
assert result.ks_pvalue > 0.05
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@pytest.mark.parametrize("name,cls,beta", GAUSSIAN_TW)
|
|
99
|
+
def test_beta_mismatch_rejected(name, cls, beta):
|
|
100
|
+
other_beta = {1: 2, 2: 4, 4: 1}[beta]
|
|
101
|
+
ens = cls(n=100, seed=0)
|
|
102
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
103
|
+
benchmark = rmt.validation.TracyWidom(beta=other_beta)
|
|
104
|
+
with pytest.raises(ValueError):
|
|
105
|
+
benchmark.validate(spectrum)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_largest_eigenvalues_helper():
|
|
109
|
+
ens = rmt.ensembles.GUE(n=200, seed=0)
|
|
110
|
+
spectrum = cached_sample(ens, n_samples=10)
|
|
111
|
+
lam_max = rmt.stats.largest_eigenvalues(spectrum)
|
|
112
|
+
assert lam_max.shape == (10,)
|
|
113
|
+
np.testing.assert_allclose(lam_max, spectrum.rescaled.max(axis=1))
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Coverage for physicskit.rmt.utils.tridiagonal's input-validation branches
|
|
2
|
+
(each function is exercised through the ensembles that call it, but never
|
|
3
|
+
with an invalid n/m that should raise)."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from physicskit.rmt.utils.tridiagonal import (
|
|
11
|
+
sample_hermite_beta_eigenvalues,
|
|
12
|
+
sample_hermite_beta_eigenvalues_and_vectors,
|
|
13
|
+
sample_laguerre_beta_eigenvalues,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_sample_hermite_beta_eigenvalues_rejects_n_below_2():
|
|
18
|
+
with pytest.raises(ValueError):
|
|
19
|
+
sample_hermite_beta_eigenvalues(1, beta=1, rng=np.random.default_rng(0))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_sample_hermite_beta_eigenvalues_and_vectors_rejects_n_below_2():
|
|
23
|
+
with pytest.raises(ValueError):
|
|
24
|
+
sample_hermite_beta_eigenvalues_and_vectors(1, beta=1, rng=np.random.default_rng(0))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_sample_hermite_beta_eigenvalues_and_vectors_returns_matching_shapes():
|
|
28
|
+
n = 12
|
|
29
|
+
eigenvalues, eigenvectors = sample_hermite_beta_eigenvalues_and_vectors(n, beta=1, rng=np.random.default_rng(1))
|
|
30
|
+
assert eigenvalues.shape == (n,)
|
|
31
|
+
assert eigenvectors.shape == (n, n)
|
|
32
|
+
assert np.all(np.diff(eigenvalues) >= 0) # ascending
|
|
33
|
+
# eigenvectors should be orthonormal columns
|
|
34
|
+
np.testing.assert_allclose(eigenvectors.T @ eigenvectors, np.eye(n), atol=1e-8)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_sample_laguerre_beta_eigenvalues_rejects_n_below_2_and_m_below_n():
|
|
38
|
+
with pytest.raises(ValueError):
|
|
39
|
+
sample_laguerre_beta_eigenvalues(m=10, n=1, beta=2, rng=np.random.default_rng(0))
|
|
40
|
+
with pytest.raises(ValueError):
|
|
41
|
+
sample_laguerre_beta_eigenvalues(m=5, n=10, beta=2, rng=np.random.default_rng(0))
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Tests for TruncatedUnitaryEnsemble and its support-radius formula.
|
|
2
|
+
|
|
3
|
+
The support radius sqrt(alpha) was NOT assumed from memory -- an initial
|
|
4
|
+
guess of sqrt(1-alpha) had exactly the wrong alpha-dependence (shrinking
|
|
5
|
+
as more of the unitary matrix is kept, contradicting the alpha=1 exact-
|
|
6
|
+
unit-circle limit), caught by checking the direction of the trend before
|
|
7
|
+
committing to a formula. The correct formula was then confirmed via the
|
|
8
|
+
99th-percentile empirical eigenvalue radius converging cleanly to it as
|
|
9
|
+
n grows at fixed alpha -- see
|
|
10
|
+
``physicskit.rmt/ensembles/truncated_unitary.py`` module docstring.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
import pytest
|
|
15
|
+
from cache_utils import cached_sample
|
|
16
|
+
|
|
17
|
+
import physicskit.rmt as rmt
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_invalid_alpha_rejected():
|
|
21
|
+
with pytest.raises(ValueError):
|
|
22
|
+
rmt.ensembles.TruncatedUnitaryEnsemble(m=10, alpha=0.0, seed=0)
|
|
23
|
+
with pytest.raises(ValueError):
|
|
24
|
+
rmt.ensembles.TruncatedUnitaryEnsemble(m=10, alpha=1.5, seed=0)
|
|
25
|
+
with pytest.raises(ValueError):
|
|
26
|
+
rmt.stats.truncated_unitary_edge_radius(0.0)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_alpha_1_recovers_unit_circle():
|
|
30
|
+
# A full (untruncated) Haar-unitary matrix's eigenvalues lie exactly
|
|
31
|
+
# on the unit circle.
|
|
32
|
+
ens = rmt.ensembles.TruncatedUnitaryEnsemble(m=100, alpha=1.0, seed=0)
|
|
33
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
34
|
+
radii = np.abs(spectrum.eigenvalues.ravel())
|
|
35
|
+
np.testing.assert_allclose(radii, 1.0, atol=1e-8)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_edge_radius_matches_formula():
|
|
39
|
+
for alpha in [0.2, 0.5, 0.8]:
|
|
40
|
+
assert rmt.stats.truncated_unitary_edge_radius(alpha) == pytest.approx(np.sqrt(alpha))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_reproducibility():
|
|
44
|
+
ens_a = rmt.ensembles.TruncatedUnitaryEnsemble(m=40, alpha=0.5, seed=42)
|
|
45
|
+
ens_b = rmt.ensembles.TruncatedUnitaryEnsemble(m=40, alpha=0.5, seed=42)
|
|
46
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
47
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
48
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_edge_radius_converges_with_increasing_m():
|
|
52
|
+
# The 99th-percentile RESCALED radius (spectrum.rescaled already
|
|
53
|
+
# divides by natural_scale() = sqrt(alpha), so the target here is
|
|
54
|
+
# 1.0, not sqrt(alpha) again) should approach 1 as the truncated
|
|
55
|
+
# block size (and hence the full unitary dimension, at fixed alpha)
|
|
56
|
+
# grows -- checked here via a shrinking overshoot rather than a
|
|
57
|
+
# fixed tolerance at one size.
|
|
58
|
+
alpha = 0.5
|
|
59
|
+
overshoots = []
|
|
60
|
+
for m in [50, 100, 200, 400]:
|
|
61
|
+
ens = rmt.ensembles.TruncatedUnitaryEnsemble(m=m, alpha=alpha, seed=1)
|
|
62
|
+
spectrum = cached_sample(ens, n_samples=30)
|
|
63
|
+
radii = np.abs(spectrum.rescaled.ravel())
|
|
64
|
+
p99 = np.percentile(radii, 99)
|
|
65
|
+
overshoots.append(p99 - 1.0)
|
|
66
|
+
assert overshoots[0] > overshoots[-1] > -0.05
|
|
67
|
+
assert overshoots[-1] < 0.05
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_bulk_density_is_not_uniform_like_ginibre():
|
|
71
|
+
# Qualitative check of the module docstring's claim: mean radius
|
|
72
|
+
# should exceed a uniform disk's (2/3)*edge prediction, i.e. the
|
|
73
|
+
# density is weighted toward the edge, unlike the circular law's
|
|
74
|
+
# flat disk.
|
|
75
|
+
alpha = 0.5
|
|
76
|
+
ens = rmt.ensembles.TruncatedUnitaryEnsemble(m=300, alpha=alpha, seed=2)
|
|
77
|
+
spectrum = cached_sample(ens, n_samples=30)
|
|
78
|
+
radii = np.abs(spectrum.rescaled.ravel())
|
|
79
|
+
uniform_disk_mean = (2.0 / 3.0) * rmt.stats.truncated_unitary_edge_radius(alpha)
|
|
80
|
+
assert radii.mean() > uniform_disk_mean
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Coverage for physicskit.rmt.validation.base: Benchmark.convergence_curve's
|
|
2
|
+
generic (non-overridden) implementation and ValidationResult.__repr__ --
|
|
3
|
+
every existing test that mentions convergence_curve deliberately loops
|
|
4
|
+
manually instead, so the base implementation itself was never called."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
import physicskit.rmt as rmt
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_convergence_curve_generic_implementation_runs_and_shrinks():
|
|
14
|
+
benchmark = rmt.validation.WignerSemicircle()
|
|
15
|
+
results = benchmark.convergence_curve(lambda n, seed: rmt.ensembles.GOE(n=n, seed=seed), n_values=[20, 60], n_samples=5, seed=0)
|
|
16
|
+
assert [n for n, _ in results] == [20, 60]
|
|
17
|
+
ks_20 = results[0][1].ks_statistic
|
|
18
|
+
ks_60 = results[1][1].ks_statistic
|
|
19
|
+
assert ks_60 < ks_20
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_validation_result_repr():
|
|
23
|
+
result = rmt.validation.base.ValidationResult(ks_statistic=0.01234, ks_pvalue=0.5, wasserstein_distance=0.005, n_eigenvalues=100)
|
|
24
|
+
assert repr(result) == "ValidationResult(ks_statistic=0.01234, ks_pvalue=0.5, wasserstein_distance=0.00500, n_eigenvalues=100)"
|
|
25
|
+
assert np.isfinite(result.ks_statistic)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Coverage for a handful of never-exercised convenience methods across
|
|
2
|
+
physicskit.rmt.validation.*: each Benchmark subclass's theoretical_pdf
|
|
3
|
+
(only theoretical_cdf is used internally elsewhere), the sine_kernel and
|
|
4
|
+
real_ginibre result types' __repr__, UniversalityResult.__repr__, and the
|
|
5
|
+
circular_law/tracy_widom convergence_curve overrides (every existing test
|
|
6
|
+
that mentions them deliberately loops manually instead)."""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
import physicskit.rmt as rmt
|
|
13
|
+
from physicskit.rmt.validation.real_ginibre import RealEigenvalueCountResult
|
|
14
|
+
from physicskit.rmt.validation.sine_kernel import CorrelationValidationResult
|
|
15
|
+
from physicskit.rmt.validation.universality import UniversalityResult
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_theoretical_pdf_methods_are_finite_and_nonnegative():
|
|
19
|
+
cases = [
|
|
20
|
+
(rmt.validation.MarchenkoPastur(gamma=0.5), np.linspace(0.1, 2.0, 10)),
|
|
21
|
+
(rmt.validation.Wachter(a=1.0, b=1.0), np.linspace(0.1, 0.9, 10)),
|
|
22
|
+
(rmt.validation.WignerSemicircle(), np.linspace(-1.5, 1.5, 10)),
|
|
23
|
+
(rmt.validation.SingleRingTheorem(r_in=0.5, r_out=1.0), np.linspace(0.5, 1.0, 10)),
|
|
24
|
+
(rmt.validation.CircularLaw(), np.linspace(0.1, 0.9, 10)),
|
|
25
|
+
]
|
|
26
|
+
for benchmark, x in cases:
|
|
27
|
+
pdf = benchmark.theoretical_pdf(x)
|
|
28
|
+
assert np.all(np.isfinite(pdf))
|
|
29
|
+
assert np.all(pdf >= 0.0)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_ratio_distribution_and_wigner_surmise_theoretical_pdf():
|
|
33
|
+
ratio = rmt.validation.RatioDistribution(beta=2)
|
|
34
|
+
r = np.linspace(0.0, 5.0, 10)
|
|
35
|
+
assert np.all(np.isfinite(ratio.theoretical_pdf(r)))
|
|
36
|
+
|
|
37
|
+
surmise = rmt.validation.WignerSurmise(beta=2)
|
|
38
|
+
s = np.linspace(0.0, 3.0, 10)
|
|
39
|
+
assert np.all(np.isfinite(surmise.theoretical_pdf(s)))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_correlation_validation_result_repr():
|
|
43
|
+
result = CorrelationValidationResult(rmse=0.01234, r_max=4.0, n_bins=60)
|
|
44
|
+
assert repr(result) == "CorrelationValidationResult(rmse=0.01234, r_max=4.0, n_bins=60)"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_real_eigenvalue_count_result_repr_and_relative_error():
|
|
48
|
+
result = RealEigenvalueCountResult(empirical_mean=8.0, theoretical=10.0, n=100)
|
|
49
|
+
assert result.relative_error == 0.2
|
|
50
|
+
assert repr(result) == "RealEigenvalueCountResult(empirical_mean=8.0000, theoretical=10.0000, n=100, relative_error=0.2000)"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_universality_result_repr():
|
|
54
|
+
result = UniversalityResult(per_distribution={"uniform": rmt.validation.base.ValidationResult(0.01, 0.5, 0.02, 50)}, max_ks_statistic=0.01)
|
|
55
|
+
text = repr(result)
|
|
56
|
+
assert text.startswith("UniversalityResult(\n")
|
|
57
|
+
assert "max_ks=0.01000" in text
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_circular_law_and_tracy_widom_convergence_curve_overrides():
|
|
61
|
+
circ = rmt.validation.CircularLaw()
|
|
62
|
+
results_c = circ.convergence_curve(lambda n, seed: rmt.ensembles.GinUE(n=n, seed=seed), n_values=[20, 40], n_samples=5, seed=0)
|
|
63
|
+
assert [n for n, _ in results_c] == [20, 40]
|
|
64
|
+
|
|
65
|
+
tw = rmt.validation.TracyWidom(beta=2)
|
|
66
|
+
results_tw = tw.convergence_curve(lambda n, seed: rmt.ensembles.GUE(n=n, seed=seed), n_values=[20, 40], n_samples=10, seed=0)
|
|
67
|
+
assert [n for n, _ in results_tw] == [20, 40]
|