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,40 @@
|
|
|
1
|
+
"""Eigenvalue support of a truncated random unitary matrix (see
|
|
2
|
+
``physicskit.rmt.ensembles.truncated_unitary`` for the construction and the
|
|
3
|
+
numerical verification behind the support-radius formula below).
|
|
4
|
+
|
|
5
|
+
Reference: K. Zyczkowski, H.-J. Sommers, J. Phys. A 33 (2000) 2045.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def truncated_unitary_edge_radius(alpha: float) -> float:
|
|
12
|
+
"""Support radius of a truncated unitary matrix's eigenvalues:
|
|
13
|
+
sqrt(alpha), for alpha = m/n the fraction of the full unitary matrix
|
|
14
|
+
kept.
|
|
15
|
+
|
|
16
|
+
Verified numerically (not assumed from memory -- an initial guess
|
|
17
|
+
of sqrt(1-alpha) had exactly the wrong alpha-dependence, caught
|
|
18
|
+
immediately since it would shrink toward 0 as more of the unitary
|
|
19
|
+
matrix is kept, contradicting the alpha=1 exact-unit-circle limit):
|
|
20
|
+
the 99th-percentile empirical eigenvalue radius converges cleanly to
|
|
21
|
+
this value as n grows at fixed alpha -- see
|
|
22
|
+
``physicskit.rmt.ensembles.truncated_unitary`` module docstring and
|
|
23
|
+
``tests/test_truncated_unitary.py``.
|
|
24
|
+
|
|
25
|
+
Precision note: this gives only the support EDGE, not the (known to
|
|
26
|
+
be non-uniform, edge-weighted) bulk density within the disk -- see
|
|
27
|
+
module docstring for what was and wasn't verified.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
alpha : float
|
|
32
|
+
Fraction of the full unitary matrix kept, in (0, 1].
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
float
|
|
37
|
+
"""
|
|
38
|
+
if not 0.0 < alpha <= 1.0:
|
|
39
|
+
raise ValueError(f"alpha must be in (0, 1], got {alpha}")
|
|
40
|
+
return float(np.sqrt(alpha))
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Spectral unfolding: rescale eigenvalues locally so the mean
|
|
2
|
+
nearest-neighbor spacing is 1 everywhere, which is what the spacing
|
|
3
|
+
distribution and rigidity statistics are defined relative to.
|
|
4
|
+
|
|
5
|
+
Where the ensemble's limiting spectral density is known exactly (e.g. the
|
|
6
|
+
semicircle law for the Gaussian ensembles), unfolding via that theoretical
|
|
7
|
+
CDF is preferable to a polynomial/spline fit to the empirical cumulative
|
|
8
|
+
distribution: it introduces no additional fitting noise, and it's exact in
|
|
9
|
+
the same sense the benchmark it will be validated against is exact.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def unfold_by_cdf(eigenvalues: np.ndarray, cdf_func: Callable[[np.ndarray], np.ndarray]) -> np.ndarray:
|
|
18
|
+
"""Unfold a single realization's eigenvalues using a known theoretical
|
|
19
|
+
integrated density (CDF).
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
eigenvalues : numpy.ndarray, shape (n,)
|
|
24
|
+
A single realization's eigenvalues (already in the ensemble's
|
|
25
|
+
natural/rescaled units -- e.g. semicircle support [-2, 2]),
|
|
26
|
+
ascending order.
|
|
27
|
+
cdf_func : callable
|
|
28
|
+
The theoretical CDF matching the ensemble's limiting spectral
|
|
29
|
+
density (e.g. ``physicskit.rmt.stats.density.semicircle_cdf``).
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
numpy.ndarray, shape (n,)
|
|
34
|
+
Unfolded eigenvalues with unit mean nearest-neighbor spacing.
|
|
35
|
+
"""
|
|
36
|
+
n = len(eigenvalues)
|
|
37
|
+
return n * cdf_func(eigenvalues)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""The Wachter distribution: limiting eigenvalue density of the Jacobi
|
|
2
|
+
(MANOVA) ensembles.
|
|
3
|
+
|
|
4
|
+
Reference: K. W. Wachter, "The limiting empirical measure of multiple
|
|
5
|
+
discriminant ratios", Ann. Statist. 8 (1980) 937. Formula and
|
|
6
|
+
parametrization as given in L. Erdos, B. Farrell, "Local Eigenvalue
|
|
7
|
+
Density for General MANOVA Matrices" (arXiv:1207.0031), verified
|
|
8
|
+
numerically during development against real (beta=1) and complex
|
|
9
|
+
(beta=2) Jacobi ensemble simulations (KS statistic < 0.002 in both
|
|
10
|
+
cases at moderate N -- see ``tests/test_jacobi_wachter.py``).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
from scipy.integrate import quad
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def wachter_support(a: float, b: float) -> tuple[float, float]:
|
|
18
|
+
"""Support edges [lambda_minus, lambda_plus] of the Wachter
|
|
19
|
+
distribution, for inverse aspect ratios a = m1/n, b = m2/n
|
|
20
|
+
(a, b >= 1)."""
|
|
21
|
+
s = a + b
|
|
22
|
+
term1 = np.sqrt((a / s) * (1.0 - 1.0 / s))
|
|
23
|
+
term2 = np.sqrt((1.0 / s) * (1.0 - a / s))
|
|
24
|
+
lam_minus = (term1 - term2) ** 2
|
|
25
|
+
lam_plus = (term1 + term2) ** 2
|
|
26
|
+
return lam_minus, lam_plus
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def wachter_pdf(x: np.ndarray, a: float, b: float) -> np.ndarray:
|
|
30
|
+
"""Wachter probability density at x, for inverse aspect ratios
|
|
31
|
+
a = m1/n, b = m2/n."""
|
|
32
|
+
lam_minus, lam_plus = wachter_support(a, b)
|
|
33
|
+
x = np.asarray(x, dtype=float)
|
|
34
|
+
out = np.zeros_like(x)
|
|
35
|
+
mask = (x > lam_minus) & (x < lam_plus)
|
|
36
|
+
xm = x[mask]
|
|
37
|
+
out[mask] = (a + b) * np.sqrt((xm - lam_minus) * (lam_plus - xm)) / (2.0 * np.pi * xm * (1.0 - xm))
|
|
38
|
+
return out
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _wachter_pdf_scalar(x: float, a: float, b: float, lam_minus: float, lam_plus: float) -> float:
|
|
42
|
+
# Non-vectorized version for use as a quad integrand (quad calls its
|
|
43
|
+
# integrand with plain Python floats; an array-returning function
|
|
44
|
+
# here caused a real bug during development -- see design notes).
|
|
45
|
+
if x <= lam_minus or x >= lam_plus:
|
|
46
|
+
return 0.0
|
|
47
|
+
return (a + b) * np.sqrt((x - lam_minus) * (lam_plus - x)) / (2.0 * np.pi * x * (1.0 - x))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def wachter_cdf(x: np.ndarray, a: float, b: float) -> np.ndarray:
|
|
51
|
+
"""Wachter CDF at x. No elementary closed form, so integrated
|
|
52
|
+
numerically from the lower edge (see
|
|
53
|
+
``validation.wachter.Wachter`` for a fast interpolated version used
|
|
54
|
+
inside KS tests)."""
|
|
55
|
+
lam_minus, lam_plus = wachter_support(a, b)
|
|
56
|
+
x = np.atleast_1d(np.asarray(x, dtype=float))
|
|
57
|
+
out = np.zeros_like(x)
|
|
58
|
+
for i, xi in enumerate(x):
|
|
59
|
+
xi = float(xi)
|
|
60
|
+
if xi <= lam_minus:
|
|
61
|
+
out[i] = 0.0
|
|
62
|
+
elif xi >= lam_plus:
|
|
63
|
+
out[i] = 1.0
|
|
64
|
+
else:
|
|
65
|
+
val, _ = quad(_wachter_pdf_scalar, lam_minus, xi, args=(a, b, lam_minus, lam_plus))
|
|
66
|
+
out[i] = val
|
|
67
|
+
return out
|
|
File without changes
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Disk cache for eigenvalue (and eigenvector, when present) data
|
|
2
|
+
produced by sampling a MatrixEnsemble in tests -- avoids re-running
|
|
3
|
+
expensive matrix diagonalization every time the test suite reruns.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
spectrum = cached_sample(ensemble, n_samples=30)
|
|
7
|
+
|
|
8
|
+
instead of:
|
|
9
|
+
spectrum = ensemble.sample(n_samples=30)
|
|
10
|
+
|
|
11
|
+
Cache key is derived from the ensemble's class name, its public
|
|
12
|
+
constructor-set attributes (n, m, m1, m2, beta, seed, ...), and
|
|
13
|
+
n_samples -- so a fresh cache entry is created whenever any of those
|
|
14
|
+
change, and reruns with identical parameters load straight from disk.
|
|
15
|
+
|
|
16
|
+
NOT used for reproducibility tests that compare two independently
|
|
17
|
+
constructed ensemble instances with the same seed (e.g.
|
|
18
|
+
``ens_a.sample(...)`` vs ``ens_b.sample(...)``): caching by
|
|
19
|
+
(class, params, seed) would make both calls hit the same cache entry,
|
|
20
|
+
so the second would just re-read the first's cached array rather than
|
|
21
|
+
genuinely resampling -- silently defeating the point of that test. Call
|
|
22
|
+
``ensemble.sample(...)`` directly there instead.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import hashlib
|
|
26
|
+
import json
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
import numpy as np
|
|
30
|
+
|
|
31
|
+
from physicskit.rmt.spectrum import Spectrum
|
|
32
|
+
|
|
33
|
+
CACHE_DIR = Path(__file__).parent / ".physicskit.rmt_test_cache"
|
|
34
|
+
CACHE_DIR.mkdir(exist_ok=True)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _public_params(ensemble):
|
|
38
|
+
"""Public, JSON-serializable constructor-set attributes of an
|
|
39
|
+
ensemble instance (n, m, m1, m2, beta, seed, ...) -- excludes
|
|
40
|
+
private attributes like ``_rng``."""
|
|
41
|
+
params = {}
|
|
42
|
+
for key, value in vars(ensemble).items():
|
|
43
|
+
if key.startswith("_"):
|
|
44
|
+
continue
|
|
45
|
+
if isinstance(value, (int, float, str, bool)) or value is None:
|
|
46
|
+
params[key] = value
|
|
47
|
+
return params
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _cache_key(ensemble, n_samples):
|
|
51
|
+
payload = json.dumps(
|
|
52
|
+
{
|
|
53
|
+
"cls": type(ensemble).__name__,
|
|
54
|
+
"params": _public_params(ensemble),
|
|
55
|
+
"n_samples": n_samples,
|
|
56
|
+
},
|
|
57
|
+
sort_keys=True,
|
|
58
|
+
)
|
|
59
|
+
return hashlib.sha256(payload.encode()).hexdigest()[:24]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def cached_sample(ensemble, n_samples):
|
|
63
|
+
"""Sample ``ensemble`` (or load a matching cached result from disk).
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
ensemble : physicskit.rmt.ensembles.base.MatrixEnsemble
|
|
68
|
+
An already-constructed ensemble instance (construction itself is
|
|
69
|
+
cheap; only ``.sample()`` -- the diagonalization -- is cached).
|
|
70
|
+
n_samples : int
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
Spectrum
|
|
75
|
+
"""
|
|
76
|
+
key = _cache_key(ensemble, n_samples)
|
|
77
|
+
path = CACHE_DIR / f"{key}.npz"
|
|
78
|
+
|
|
79
|
+
if path.exists():
|
|
80
|
+
data = np.load(path, allow_pickle=False)
|
|
81
|
+
eigenvalues = data["eigenvalues"]
|
|
82
|
+
beta_raw = data["beta"]
|
|
83
|
+
beta = None if np.isnan(beta_raw) else float(beta_raw)
|
|
84
|
+
spectrum = Spectrum(
|
|
85
|
+
eigenvalues=eigenvalues,
|
|
86
|
+
n=int(data["n"]),
|
|
87
|
+
beta=beta,
|
|
88
|
+
ensemble=str(data["ensemble_name"]),
|
|
89
|
+
scale=float(data["scale"]),
|
|
90
|
+
)
|
|
91
|
+
if "eigenvectors" in data.files:
|
|
92
|
+
spectrum.eigenvectors = data["eigenvectors"]
|
|
93
|
+
return spectrum
|
|
94
|
+
|
|
95
|
+
spectrum = ensemble.sample(n_samples=n_samples)
|
|
96
|
+
save_kwargs = dict(
|
|
97
|
+
eigenvalues=spectrum.eigenvalues,
|
|
98
|
+
n=spectrum.n,
|
|
99
|
+
beta=np.nan if spectrum.beta is None else float(spectrum.beta),
|
|
100
|
+
ensemble_name=spectrum.ensemble,
|
|
101
|
+
scale=spectrum.scale,
|
|
102
|
+
)
|
|
103
|
+
eigenvectors = getattr(spectrum, "eigenvectors", None)
|
|
104
|
+
if eigenvectors is not None:
|
|
105
|
+
save_kwargs["eigenvectors"] = eigenvectors
|
|
106
|
+
np.savez(path, **save_kwargs)
|
|
107
|
+
return spectrum
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Ensures tests/ is importable as a plain module path (for
|
|
2
|
+
``from cache_utils import cached_sample``) regardless of how pytest is
|
|
3
|
+
invoked (rootdir vs tests/ as cwd)."""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Tests for PowerLawBandedEnsemble (PBRM).
|
|
2
|
+
|
|
3
|
+
PBRM has no single universal limiting law to validate against (the
|
|
4
|
+
level statistics themselves are the tunable object of study -- see
|
|
5
|
+
module docstring), so tests check: (1) the variance-profile construction
|
|
6
|
+
matches its own formula directly (the actual thing that could have a
|
|
7
|
+
normalization bug, as one briefly did during development -- an initial
|
|
8
|
+
version halved the target variance by mistakenly reusing GOE's
|
|
9
|
+
two-independent-draws averaging convention for a single-draw
|
|
10
|
+
construction), and (2) the two well-understood limiting regimes behave
|
|
11
|
+
qualitatively as expected (short-range/localized-like vs. GOE-like).
|
|
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
|
+
|
|
20
|
+
|
|
21
|
+
def test_invalid_b_rejected():
|
|
22
|
+
with pytest.raises(ValueError):
|
|
23
|
+
rmt.ensembles.PowerLawBandedEnsemble(n=10, b=0.0, seed=0)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_reproducibility():
|
|
27
|
+
ens_a = rmt.ensembles.PowerLawBandedEnsemble(n=40, b=5.0, alpha=1.0, seed=42)
|
|
28
|
+
ens_b = rmt.ensembles.PowerLawBandedEnsemble(n=40, b=5.0, alpha=1.0, seed=42)
|
|
29
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
30
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
31
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_default_alpha_is_the_critical_point():
|
|
35
|
+
ens = rmt.ensembles.PowerLawBandedEnsemble(n=10, b=3.0, seed=0)
|
|
36
|
+
assert ens.alpha == 1.0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_variance_profile_matches_target_formula():
|
|
40
|
+
# Direct check of the construction's second moment against its own
|
|
41
|
+
# defining formula, pooled over many independent draws -- this is
|
|
42
|
+
# exactly the check that caught an initial /2 normalization bug
|
|
43
|
+
# during development (see module docstring).
|
|
44
|
+
from physicskit.rmt.ensembles.banded import _power_law_variance_profile
|
|
45
|
+
|
|
46
|
+
rng = np.random.default_rng(1)
|
|
47
|
+
n, b, alpha = 20, 5.0, 1.0
|
|
48
|
+
target = _power_law_variance_profile(n, b, alpha)
|
|
49
|
+
|
|
50
|
+
# Build the raw matrix directly (the same way
|
|
51
|
+
# ``PowerLawBandedEnsemble._sample_eigenvalues`` does, bypassing the
|
|
52
|
+
# eigendecomposition) many times to check H_ij's empirical variance
|
|
53
|
+
# against the target profile.
|
|
54
|
+
entries_i_j = []
|
|
55
|
+
for _ in range(30_000):
|
|
56
|
+
variance = target
|
|
57
|
+
std = np.sqrt(variance)
|
|
58
|
+
upper = np.triu(rng.standard_normal((n, n)) * std, k=1)
|
|
59
|
+
h = upper + upper.T
|
|
60
|
+
entries_i_j.append(h[0, 3])
|
|
61
|
+
entries_i_j = np.array(entries_i_j)
|
|
62
|
+
assert entries_i_j.var() == pytest.approx(target[0, 3], rel=0.1)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_short_range_limit_looks_localized_narrow_band():
|
|
66
|
+
# alpha very large with a small, fixed band -> effectively a
|
|
67
|
+
# strictly banded (short-range) matrix; the bulk eigenvalue spread
|
|
68
|
+
# should stay modest (order the band width), not grow like a full
|
|
69
|
+
# GOE's sqrt(n).
|
|
70
|
+
n = 800
|
|
71
|
+
ens = rmt.ensembles.PowerLawBandedEnsemble(n=n, b=2.0, alpha=6.0, seed=2)
|
|
72
|
+
spectrum = cached_sample(ens, n_samples=3)
|
|
73
|
+
goe_like_scale = np.sqrt(n)
|
|
74
|
+
assert spectrum.eigenvalues.std() < 0.3 * goe_like_scale
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_large_alpha_zero_limit_approaches_goe_like_scale():
|
|
78
|
+
# alpha -> 0 makes every entry's variance -> 1 (long-range,
|
|
79
|
+
# effectively unbanded) -- this should look like a GOE matrix with
|
|
80
|
+
# unit-variance entries, i.e. eigenvalue std growing like sqrt(n),
|
|
81
|
+
# not staying bounded the way the short-range case does above.
|
|
82
|
+
n = 800
|
|
83
|
+
ens = rmt.ensembles.PowerLawBandedEnsemble(n=n, b=5.0, alpha=0.01, seed=3)
|
|
84
|
+
spectrum = cached_sample(ens, n_samples=3)
|
|
85
|
+
goe_like_scale = np.sqrt(n)
|
|
86
|
+
assert spectrum.eigenvalues.std() > 0.5 * goe_like_scale
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Coverage for physicskit.rmt.ensembles.base.MatrixEnsemble's default
|
|
2
|
+
natural_scale (every concrete ensemble in this codebase overrides it, so a
|
|
3
|
+
minimal dummy subclass is needed to exercise the base implementation)."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from physicskit.rmt.ensembles.base import MatrixEnsemble
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _DummyEnsemble(MatrixEnsemble):
|
|
13
|
+
"""Implements only the required abstract method; relies on the base
|
|
14
|
+
class's default natural_scale (1.0, no rescaling)."""
|
|
15
|
+
|
|
16
|
+
def _sample_eigenvalues(self, rng):
|
|
17
|
+
return rng.standard_normal(self.n)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_default_natural_scale_is_one():
|
|
21
|
+
ens = _DummyEnsemble(n=4, seed=0)
|
|
22
|
+
assert ens.natural_scale() == 1.0
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_sample_uses_default_natural_scale_unscaled():
|
|
26
|
+
ens = _DummyEnsemble(n=4, seed=0)
|
|
27
|
+
spectrum = ens.sample(n_samples=3)
|
|
28
|
+
assert spectrum.scale == 1.0
|
|
29
|
+
assert np.all(np.isfinite(spectrum.eigenvalues))
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Tests for the Bogoliubov-de Gennes / Altland-Zirnbauer superconductor
|
|
2
|
+
classes D, C, CI, DIII.
|
|
3
|
+
|
|
4
|
+
Unlike most of this package, these are validated only structurally
|
|
5
|
+
(Hermiticity, correct real/complex type per class, and the defining
|
|
6
|
+
+-lambda eigenvalue pairing), not against a closed-form bulk or edge
|
|
7
|
+
density -- see the module docstring in ``physicskit.rmt/ensembles/bdg.py`` for
|
|
8
|
+
why. The constructions themselves come from two independently citable
|
|
9
|
+
sources: Stephanov-Verbaarschot-Wettig (arXiv:hep-ph/0509286, citing
|
|
10
|
+
Altland-Zirnbauer 1997) for classes D and C, and Stolz
|
|
11
|
+
(arXiv:1707.03793, also citing Altland-Zirnbauer) for classes CI and
|
|
12
|
+
DIII, whose definitions are given in purely mathematical terms
|
|
13
|
+
independent of any physics convention -- reducing the risk of a
|
|
14
|
+
convention mismatch relative to earlier, less precisely specified
|
|
15
|
+
sources found during the initial search for this feature.
|
|
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
|
+
BDG_CLASSES = [
|
|
25
|
+
("D", rmt.ensembles.BdGClassD, 2, False), # (name, cls, beta, expect_real)
|
|
26
|
+
("C", rmt.ensembles.BdGClassC, 2, False),
|
|
27
|
+
("CI", rmt.ensembles.BdGClassCI, 1, True),
|
|
28
|
+
("DIII", rmt.ensembles.BdGClassDIII, 4, False),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.mark.parametrize("name,cls,beta,expect_real", BDG_CLASSES)
|
|
33
|
+
def test_beta_is_correct(name, cls, beta, expect_real):
|
|
34
|
+
ens = cls(n=30, seed=0)
|
|
35
|
+
assert ens.beta == beta
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.mark.parametrize("name,cls,beta,expect_real", BDG_CLASSES)
|
|
39
|
+
def test_produces_2n_eigenvalues(name, cls, beta, expect_real):
|
|
40
|
+
ens = cls(n=50, seed=1)
|
|
41
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
42
|
+
assert spectrum.eigenvalues.shape == (5, 100)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.parametrize("name,cls,beta,expect_real", BDG_CLASSES)
|
|
46
|
+
def test_eigenvalues_are_real(name, cls, beta, expect_real):
|
|
47
|
+
# All four classes are built from Hermitian matrices, so eigenvalues
|
|
48
|
+
# are always real-valued floats regardless of whether the underlying
|
|
49
|
+
# matrix entries are real (CI) or complex (D, C, DIII).
|
|
50
|
+
ens = cls(n=40, seed=2)
|
|
51
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
52
|
+
assert not np.iscomplexobj(spectrum.eigenvalues)
|
|
53
|
+
assert np.all(np.isfinite(spectrum.eigenvalues))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@pytest.mark.parametrize("name,cls,beta,expect_real", BDG_CLASSES)
|
|
57
|
+
def test_reproducibility(name, cls, beta, expect_real):
|
|
58
|
+
ens_a = cls(n=40, seed=42)
|
|
59
|
+
ens_b = cls(n=40, 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,expect_real", BDG_CLASSES)
|
|
66
|
+
def test_spectrum_symmetric_about_zero(name, cls, beta, expect_real):
|
|
67
|
+
# The defining particle-hole symmetry: eigenvalues occur in
|
|
68
|
+
# +-lambda pairs (distinct values, not a Kramers-type degeneracy).
|
|
69
|
+
ens = cls(n=60, seed=3)
|
|
70
|
+
spectrum = cached_sample(ens, n_samples=10)
|
|
71
|
+
for row in spectrum.eigenvalues:
|
|
72
|
+
row_sorted = np.sort(row)
|
|
73
|
+
pairing_error = np.abs(row_sorted + row_sorted[::-1]).max()
|
|
74
|
+
assert pairing_error < 1e-8
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_matrix_construction_hermiticity_and_type_directly():
|
|
78
|
+
# Direct, un-cached structural check of the raw matrix construction
|
|
79
|
+
# (not just the eigenvalues) for each class, including confirming
|
|
80
|
+
# CI is REAL (not just Hermitian) and the other three are complex.
|
|
81
|
+
from physicskit.rmt.ensembles.bdg import (
|
|
82
|
+
_dense_antisymmetric,
|
|
83
|
+
_dense_hermitian,
|
|
84
|
+
_dense_symmetric,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
rng = np.random.default_rng(7)
|
|
88
|
+
n = 20
|
|
89
|
+
|
|
90
|
+
a = _dense_hermitian(n, rng, complex_entries=True)
|
|
91
|
+
b_d = _dense_antisymmetric(n, rng, complex_entries=True)
|
|
92
|
+
h_d = np.block([[a, b_d], [b_d.conj().T, -a.T]])
|
|
93
|
+
assert np.abs(h_d - h_d.conj().T).max() < 1e-10
|
|
94
|
+
assert np.abs(h_d.imag).max() > 1e-3 # genuinely complex, not real
|
|
95
|
+
|
|
96
|
+
b_c = _dense_symmetric(n, rng, complex_entries=True)
|
|
97
|
+
h_c = np.block([[a, b_c], [b_c.conj().T, -a.T]])
|
|
98
|
+
assert np.abs(h_c - h_c.conj().T).max() < 1e-10
|
|
99
|
+
|
|
100
|
+
x1_ci = _dense_symmetric(n, rng, complex_entries=False)
|
|
101
|
+
x2_ci = _dense_symmetric(n, rng, complex_entries=False)
|
|
102
|
+
h_ci = np.block([[x1_ci, x2_ci], [x2_ci, -x1_ci]])
|
|
103
|
+
assert np.abs(h_ci.imag).max() == 0.0 # exactly real
|
|
104
|
+
assert np.abs(h_ci - h_ci.T).max() < 1e-10
|
|
105
|
+
|
|
106
|
+
y1 = _dense_antisymmetric(n, rng, complex_entries=False)
|
|
107
|
+
y2 = _dense_antisymmetric(n, rng, complex_entries=False)
|
|
108
|
+
x1_diii, x2_diii = 1j * y1, 1j * y2
|
|
109
|
+
h_diii = np.block([[x1_diii, x2_diii], [x2_diii, -x1_diii]])
|
|
110
|
+
assert np.abs(h_diii - h_diii.conj().T).max() < 1e-10
|
|
111
|
+
assert np.abs(h_diii.real).max() == 0.0 # exactly purely-imaginary entries
|
|
112
|
+
|
|
113
|
+
a_real = _dense_hermitian(n, rng, complex_entries=False)
|
|
114
|
+
assert np.abs(a_real.imag).max() == 0.0 # exactly real
|
|
115
|
+
assert np.abs(a_real - a_real.T).max() < 1e-10
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_all_four_classes_are_structurally_distinct():
|
|
119
|
+
# Sanity check that the four classes don't accidentally collapse to
|
|
120
|
+
# the same construction (a risk given how similar the block forms
|
|
121
|
+
# look on paper).
|
|
122
|
+
n = 30
|
|
123
|
+
spectra = {}
|
|
124
|
+
for name, cls, _beta, _expect_real in BDG_CLASSES:
|
|
125
|
+
ens = cls(n=n, seed=8)
|
|
126
|
+
spectra[name] = np.sort(ens.sample(n_samples=1).eigenvalues[0])
|
|
127
|
+
|
|
128
|
+
# Different beta values (D/C share beta=2 but differ in B's symmetry
|
|
129
|
+
# type; CI and DIII have distinct beta) should generally give
|
|
130
|
+
# different largest-eigenvalue values for the same seed.
|
|
131
|
+
largest = {name: spec[-1] for name, spec in spectra.items()}
|
|
132
|
+
values = list(largest.values())
|
|
133
|
+
assert len(set(np.round(values, 6))) == len(values)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Tests for CUE characteristic polynomial moments (Keating-Snaith).
|
|
2
|
+
|
|
3
|
+
The product formula was verified numerically against direct Monte Carlo
|
|
4
|
+
(Haar-random unitary matrices, evaluated at theta=0) at several (n, k)
|
|
5
|
+
pairs before being trusted -- see
|
|
6
|
+
``physicskit.rmt/stats/characteristic_polynomial.py`` module docstring.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pytest
|
|
11
|
+
from cache_utils import cached_sample
|
|
12
|
+
|
|
13
|
+
import physicskit.rmt as rmt
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_n1_k1_matches_hand_derivation():
|
|
17
|
+
# 1x1 case: Z_1 = 1 - e^{i(phi-theta)}, E[|Z_1|^2] = 2 - 2*E[cos] = 2
|
|
18
|
+
# exactly (uniform phi over a full period).
|
|
19
|
+
assert rmt.stats.keating_snaith_moment(1, 1) == pytest.approx(2.0)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_k1_special_case_is_n_plus_1():
|
|
23
|
+
# Noticed and checked during development: k=1 telescopes to n+1.
|
|
24
|
+
for n in [1, 2, 3, 4, 8]:
|
|
25
|
+
assert rmt.stats.keating_snaith_moment(n, 1) == pytest.approx(n + 1)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_rejects_non_positive_k():
|
|
29
|
+
with pytest.raises(ValueError):
|
|
30
|
+
rmt.stats.keating_snaith_moment(5, 0)
|
|
31
|
+
with pytest.raises(ValueError):
|
|
32
|
+
rmt.stats.characteristic_polynomial_empirical_moment(np.zeros((1, 3)), 0)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.mark.parametrize("n,k", [(2, 1), (3, 1), (4, 1), (2, 2)])
|
|
36
|
+
def test_moment_matches_empirical_cue_simulation(n, k):
|
|
37
|
+
ens = rmt.ensembles.CUE(n=n, seed=0)
|
|
38
|
+
spectrum = cached_sample(ens, n_samples=20000)
|
|
39
|
+
theory = rmt.stats.keating_snaith_moment(n, k)
|
|
40
|
+
empirical = rmt.stats.characteristic_polynomial_empirical_moment(spectrum.eigenvalues, k)
|
|
41
|
+
assert empirical == pytest.approx(theory, rel=0.05)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_moments_grow_with_k():
|
|
45
|
+
# Higher moments of a nonnegative random variable are larger (given
|
|
46
|
+
# the variable isn't a.s. constant, which |Z_n| generically isn't).
|
|
47
|
+
n = 4
|
|
48
|
+
m1 = rmt.stats.keating_snaith_moment(n, 1)
|
|
49
|
+
m2 = rmt.stats.keating_snaith_moment(n, 2)
|
|
50
|
+
assert m2 > m1
|