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,36 @@
|
|
|
1
|
+
"""Von Neumann entanglement entropy and Page's (1993) exact average --
|
|
2
|
+
the "Page curve" -- for the bipartite pure-state ensemble realized by
|
|
3
|
+
``physicskit.rmt.ensembles.density_matrix.InducedMeasureEnsemble``.
|
|
4
|
+
|
|
5
|
+
Reference: D. N. Page, "Average entropy of a subsystem", Phys. Rev.
|
|
6
|
+
Lett. 71 (1993) 1291. Verified numerically here (against Monte Carlo
|
|
7
|
+
samples from ``InducedMeasureEnsemble`` at several (n, k) pairs) before
|
|
8
|
+
being trusted -- see ``tests/test_density_matrix.py``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from scipy.special import digamma
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def von_neumann_entropy(eigenvalues: np.ndarray) -> float:
|
|
16
|
+
"""Von Neumann entropy -sum(lambda_i * log(lambda_i)) (nats), given a
|
|
17
|
+
density matrix's eigenvalues. Zero eigenvalues (exact or numerically
|
|
18
|
+
negligible) contribute 0, per the standard 0*log(0)=0 convention --
|
|
19
|
+
not NaN from log(0).
|
|
20
|
+
"""
|
|
21
|
+
eigenvalues = np.asarray(eigenvalues, dtype=float)
|
|
22
|
+
eigenvalues = eigenvalues[eigenvalues > 1e-14]
|
|
23
|
+
return float(-np.sum(eigenvalues * np.log(eigenvalues)))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def page_curve_average_entropy(n: int, k: int) -> float:
|
|
27
|
+
"""Page's (1993) exact average von Neumann entropy (nats) of the
|
|
28
|
+
n-dimensional reduced density matrix of a Haar-random pure state on
|
|
29
|
+
C^n (x) C^k, n <= k:
|
|
30
|
+
|
|
31
|
+
<S> = digamma(n*k + 1) - digamma(k + 1) - (n - 1) / (2*k)
|
|
32
|
+
|
|
33
|
+
This is an exact finite-(n, k) result, not an asymptotic
|
|
34
|
+
approximation.
|
|
35
|
+
"""
|
|
36
|
+
return digamma(n * k + 1) - digamma(k + 1) - (n - 1) / (2.0 * k)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Free probability basics: the Stieltjes (Cauchy) transform, the
|
|
2
|
+
R-transform (which linearizes FREE additive convolution, the large-N
|
|
3
|
+
limiting analogue of ordinary convolution for independent, unitarily-
|
|
4
|
+
invariant random matrices), and free additive convolution itself.
|
|
5
|
+
|
|
6
|
+
References
|
|
7
|
+
----------
|
|
8
|
+
D. Voiculescu, "Symmetries of some reduced free product C*-algebras",
|
|
9
|
+
Operator Algebras and their Connections with Topology and Ergodic
|
|
10
|
+
Theory, Lecture Notes in Math. 1132, Springer, 1985 -- free
|
|
11
|
+
independence and the R-transform.
|
|
12
|
+
A. Nica, R. Speicher, "Lectures on the Combinatorics of Free
|
|
13
|
+
Probability", Cambridge Univ. Press, 2006 -- standard reference.
|
|
14
|
+
|
|
15
|
+
For a probability measure with Stieltjes transform
|
|
16
|
+
G(z) = integral rho(x)/(z-x) dx (rho the density; z off the real
|
|
17
|
+
support), the R-transform is defined via the functional inverse K of G
|
|
18
|
+
(K(G(z)) = z, valid in a neighborhood of z = infinity / w = 0):
|
|
19
|
+
|
|
20
|
+
R(w) = K(w) - 1/w
|
|
21
|
+
|
|
22
|
+
The defining property (why this is useful): if A, B are independent,
|
|
23
|
+
unitarily-invariant random matrices (hence "asymptotically free" in the
|
|
24
|
+
N -> infinity limit), the limiting spectral distribution of A + B has
|
|
25
|
+
R-transform R_{A+B} = R_A + R_B -- the free-probability analogue of how
|
|
26
|
+
cumulants add for a sum of independent classical random variables.
|
|
27
|
+
|
|
28
|
+
Precision approach (see ``physicskit.rmt.stats.correlations`` module docstring
|
|
29
|
+
for why this matters): rather than trust a recalled closed-form R(w) for
|
|
30
|
+
each distribution, ``stieltjes_transform_numerical`` and
|
|
31
|
+
``r_transform_numerical`` compute G and R directly from their
|
|
32
|
+
DEFINITIONS (numerical integration / functional inversion via root-
|
|
33
|
+
finding), with no distribution-specific formula assumed. The two closed
|
|
34
|
+
forms provided (``r_transform_semicircle``, ``r_transform_marchenko_pastur``)
|
|
35
|
+
were each independently checked against this numerical pipeline before
|
|
36
|
+
being trusted:
|
|
37
|
+
|
|
38
|
+
- Semicircle (variance 1): R(w) = w exactly -- derived directly here
|
|
39
|
+
(not recalled) from the semicircle's own Stieltjes transform
|
|
40
|
+
G(z) = (z - sqrt(z^2-4))/2 by solving w = G(z) for z, giving the
|
|
41
|
+
functional inverse K(w) = w + 1/w, hence R(w) = K(w) - 1/w = w.
|
|
42
|
+
Confirmed numerically: the generic root-finding inversion pipeline
|
|
43
|
+
applied to this G reproduces R(w) = w to 5 decimal places for
|
|
44
|
+
w in (0, 1) (the R-transform's domain of convergence here).
|
|
45
|
+
- Marchenko-Pastur (aspect ratio gamma): R(w) = 1/(1-gamma*w).
|
|
46
|
+
Verified numerically against ``physicskit.rmt.stats.marchenko_pastur.mp_pdf``
|
|
47
|
+
(already independently validated elsewhere in this package) via the
|
|
48
|
+
same numerical G-inversion pipeline: matched to 5 significant figures
|
|
49
|
+
at gamma=0.5, w = 0.1, 0.3, 0.6.
|
|
50
|
+
|
|
51
|
+
Free additive convolution of A and B (asymptotically free): verified
|
|
52
|
+
here via direct random matrix simulation, not just the R-transform
|
|
53
|
+
formulas in isolation -- see ``tests/test_free_probability.py``: for
|
|
54
|
+
independent GOE-type (semicircle) and Wishart-type (Marchenko-Pastur)
|
|
55
|
+
matrices, the EMPIRICAL R-transform of their sum's spectral
|
|
56
|
+
distribution (extracted via ``r_transform_numerical`` applied to the
|
|
57
|
+
sum's own Monte Carlo eigenvalues) matches
|
|
58
|
+
``r_transform_semicircle(w) + r_transform_marchenko_pastur(w, gamma)``
|
|
59
|
+
to within Monte Carlo noise -- the genuine, non-trivial content of free
|
|
60
|
+
probability's additive convolution theorem, not merely the two
|
|
61
|
+
closed-form R-transforms considered separately.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
from collections.abc import Callable
|
|
65
|
+
|
|
66
|
+
import numpy as np
|
|
67
|
+
from scipy.optimize import brentq
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def stieltjes_transform_empirical(eigenvalues: np.ndarray, z: complex) -> complex:
|
|
71
|
+
"""Empirical Stieltjes (Cauchy) transform G(z) = mean(1/(z - x)),
|
|
72
|
+
directly from eigenvalue samples.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
eigenvalues : numpy.ndarray
|
|
77
|
+
Pooled real eigenvalues (any shape; flattened).
|
|
78
|
+
z : complex
|
|
79
|
+
Evaluation point, off the real support.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
complex
|
|
84
|
+
"""
|
|
85
|
+
eigenvalues = np.asarray(eigenvalues).ravel()
|
|
86
|
+
return complex(np.mean(1.0 / (z - eigenvalues)))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def stieltjes_transform_semicircle(z: complex) -> complex:
|
|
90
|
+
"""Exact Stieltjes transform of the standard (variance 1) semicircle
|
|
91
|
+
law on [-2, 2]: G(z) = (z - sqrt(z^2 - 4)) / 2 (the branch of the
|
|
92
|
+
square root with a cut on [-2, 2], decaying as 1/z at infinity, is
|
|
93
|
+
selected automatically here for real z > 2 or complex z off the
|
|
94
|
+
real axis).
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
z : complex
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
complex
|
|
103
|
+
"""
|
|
104
|
+
z = complex(z)
|
|
105
|
+
return (z - np.sqrt(z**2 - 4)) / 2.0
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def r_transform_semicircle(w: float) -> float:
|
|
109
|
+
"""Exact R-transform of the standard (variance 1) semicircle law:
|
|
110
|
+
R(w) = w. See module docstring for the direct derivation (from
|
|
111
|
+
``stieltjes_transform_semicircle``'s own functional inverse) and its
|
|
112
|
+
numerical verification.
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
w : float
|
|
117
|
+
|
|
118
|
+
Returns
|
|
119
|
+
-------
|
|
120
|
+
float
|
|
121
|
+
"""
|
|
122
|
+
return w
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def r_transform_marchenko_pastur(w: float, gamma: float) -> float:
|
|
126
|
+
"""R-transform of the Marchenko-Pastur law at aspect ratio gamma:
|
|
127
|
+
R(w) = 1 / (1 - gamma*w). Verified numerically against the exact MP
|
|
128
|
+
density via ``r_transform_numerical`` -- see module docstring.
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
w : float
|
|
133
|
+
gamma : float
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
float
|
|
138
|
+
"""
|
|
139
|
+
return 1.0 / (1.0 - gamma * w)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def invert_stieltjes_transform_numerical(
|
|
143
|
+
stieltjes_transform: Callable[[complex], complex],
|
|
144
|
+
w: float,
|
|
145
|
+
z_bracket: tuple[float, float],
|
|
146
|
+
) -> float:
|
|
147
|
+
"""Numerically find z such that ``stieltjes_transform(z) == w``, for
|
|
148
|
+
real z in ``z_bracket`` (bisection/Brent's method) -- the functional
|
|
149
|
+
inverse K(w) needed to build an R-transform from an arbitrary
|
|
150
|
+
Stieltjes transform, with no distribution-specific formula assumed.
|
|
151
|
+
|
|
152
|
+
Only valid where the Stieltjes transform is real, finite, and
|
|
153
|
+
monotonic on ``z_bracket`` (e.g. real z strictly outside the
|
|
154
|
+
distribution's support) -- a ``ValueError`` from the underlying
|
|
155
|
+
root-finder (mismatched signs at the bracket ends) generally means
|
|
156
|
+
``w`` is outside the transform's range on that bracket, not a bug.
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
stieltjes_transform : callable
|
|
161
|
+
``stieltjes_transform(z) -> complex``, real-valued for real z in
|
|
162
|
+
``z_bracket``.
|
|
163
|
+
w : float
|
|
164
|
+
z_bracket : tuple of float
|
|
165
|
+
``(z_lo, z_hi)`` search bracket, e.g. just above the
|
|
166
|
+
distribution's upper edge to a large value.
|
|
167
|
+
|
|
168
|
+
Returns
|
|
169
|
+
-------
|
|
170
|
+
float
|
|
171
|
+
"""
|
|
172
|
+
z_lo, z_hi = z_bracket
|
|
173
|
+
|
|
174
|
+
def residual(z: float) -> float:
|
|
175
|
+
return stieltjes_transform(z).real - w
|
|
176
|
+
|
|
177
|
+
return brentq(residual, z_lo, z_hi)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def r_transform_numerical(
|
|
181
|
+
stieltjes_transform: Callable[[complex], complex],
|
|
182
|
+
w: float,
|
|
183
|
+
z_bracket: tuple[float, float],
|
|
184
|
+
) -> float:
|
|
185
|
+
"""R-transform at ``w``, computed directly from the definition
|
|
186
|
+
R(w) = K(w) - 1/w, K the functional inverse of the given Stieltjes
|
|
187
|
+
transform (see ``invert_stieltjes_transform_numerical``). Works for
|
|
188
|
+
any Stieltjes transform (empirical or exact), with no
|
|
189
|
+
distribution-specific closed form assumed.
|
|
190
|
+
|
|
191
|
+
Parameters
|
|
192
|
+
----------
|
|
193
|
+
stieltjes_transform : callable
|
|
194
|
+
w : float
|
|
195
|
+
z_bracket : tuple of float
|
|
196
|
+
|
|
197
|
+
Returns
|
|
198
|
+
-------
|
|
199
|
+
float
|
|
200
|
+
"""
|
|
201
|
+
z = invert_stieltjes_transform_numerical(stieltjes_transform, w, z_bracket)
|
|
202
|
+
return z - 1.0 / w
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
"""Eigenvector localization statistics: the inverse participation ratio
|
|
2
|
+
(IPR) and its exact value for Haar-distributed (fully delocalized)
|
|
3
|
+
eigenvectors.
|
|
4
|
+
|
|
5
|
+
Unlike every other statistic in this package, these operate on
|
|
6
|
+
eigenVECTORS rather than eigenvalues, so they require a ``Spectrum``
|
|
7
|
+
sampled with ``ensemble.sample(return_eigenvectors=True)`` (see
|
|
8
|
+
``physicskit.rmt.ensembles.base.MatrixEnsemble.sample``) -- not every ensemble
|
|
9
|
+
supports this (dense diagonalization is required; the fast tridiagonal-
|
|
10
|
+
model ensembles' eigenvalues are exact in distribution but their raw
|
|
11
|
+
eigenvectors are not Haar-distributed, so eigenvector support is only
|
|
12
|
+
implemented where it's been verified to give genuinely Haar-distributed
|
|
13
|
+
(GOE/GUE) or physically meaningful (``PowerLawBandedEnsemble``,
|
|
14
|
+
Anderson localization) eigenvectors -- see each ensemble's docstring).
|
|
15
|
+
|
|
16
|
+
For a normalized eigenvector psi (``sum_i |psi_i|^2 = 1``), the inverse
|
|
17
|
+
participation ratio is
|
|
18
|
+
|
|
19
|
+
``IPR(psi) = sum_i |psi_i|^4``
|
|
20
|
+
|
|
21
|
+
IPR ~ O(1/n) for a fully delocalized (extended) state spread evenly over
|
|
22
|
+
all n sites, and IPR ~ O(1) (n-independent) for a localized state
|
|
23
|
+
concentrated on a handful of sites -- the standard order parameter for
|
|
24
|
+
the Anderson localization transition.
|
|
25
|
+
|
|
26
|
+
Exact theory for a Haar-distributed (rotationally/unitarily/
|
|
27
|
+
symplectically invariant, i.e. GOE/GUE/GSE-type) unit vector: writing
|
|
28
|
+
each component's squared magnitude as a "beta real dimensions per site"
|
|
29
|
+
weight, ``(|psi_1|^2, ..., |psi_n|^2)`` is exactly Dirichlet(beta/2, ...,
|
|
30
|
+
beta/2) distributed, giving the closed-form moment
|
|
31
|
+
|
|
32
|
+
E[IPR] = (beta/2 + 1) / (n*beta/2 + 1)
|
|
33
|
+
|
|
34
|
+
(reduces to 3/(n+2) at beta=1, 2/(n+1) at beta=2, 3/(2n+1) at beta=4 --
|
|
35
|
+
verified numerically here against direct Haar-vector Monte Carlo at all
|
|
36
|
+
three beta, and independently against the Dirichlet-moment formula's own
|
|
37
|
+
derivation, before being trusted -- see ``tests/test_localization.py``).
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
from collections.abc import Callable
|
|
43
|
+
|
|
44
|
+
import numpy as np
|
|
45
|
+
|
|
46
|
+
from ..ensembles.base import MatrixEnsemble
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def inverse_participation_ratio(eigenvectors: np.ndarray) -> np.ndarray:
|
|
50
|
+
"""Inverse participation ratio of each eigenvector (column).
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
eigenvectors : numpy.ndarray, shape (..., m, n)
|
|
55
|
+
Eigenvectors as columns (as returned in
|
|
56
|
+
``Spectrum.eigenvectors``); the leading ``...`` axes (e.g. a
|
|
57
|
+
sample axis) are preserved.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
numpy.ndarray, shape (..., n)
|
|
62
|
+
IPR of each column, in (0, 1].
|
|
63
|
+
"""
|
|
64
|
+
eigenvectors = np.asarray(eigenvectors)
|
|
65
|
+
weights = np.abs(eigenvectors) ** 2
|
|
66
|
+
weights = weights / np.sum(weights, axis=-2, keepdims=True)
|
|
67
|
+
return np.sum(weights**2, axis=-2)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def inverse_participation_ratio_quaternionic(eigenvectors: np.ndarray) -> np.ndarray:
|
|
71
|
+
"""Inverse participation ratio for GSE-type (beta=4) eigenvectors,
|
|
72
|
+
folding pairs of complex components into per-site quaternion
|
|
73
|
+
weights first.
|
|
74
|
+
|
|
75
|
+
GSE eigenvectors (as returned by
|
|
76
|
+
``physicskit.rmt.ensembles.gaussian.GSE.sample(return_eigenvectors=True)``)
|
|
77
|
+
are naturally 2n-dimensional complex vectors representing n
|
|
78
|
+
quaternionic "sites" (rows ``2i, 2i+1`` are one quaternion's two
|
|
79
|
+
complex components) -- calling the plain
|
|
80
|
+
``inverse_participation_ratio`` on them directly would treat all 2n
|
|
81
|
+
complex components as independent sites, which is not the physically
|
|
82
|
+
meaningful per-site statistic and does not match
|
|
83
|
+
``ipr_theory(n, beta=4)``. This function folds pairs first:
|
|
84
|
+
``weight_i = |v[2i]|^2 + |v[2i+1]|^2``, matching the definition used
|
|
85
|
+
to verify ``ipr_theory`` for beta=4 (see
|
|
86
|
+
``physicskit.rmt.ensembles.gaussian._dense_hermite_quaternion``).
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
eigenvectors : numpy.ndarray, shape (..., 2n, n)
|
|
91
|
+
GSE-type eigenvectors as columns (as returned in
|
|
92
|
+
``Spectrum.eigenvectors`` for ``GSE``).
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
numpy.ndarray, shape (..., n)
|
|
97
|
+
IPR of each column, computed over the n quaternionic sites.
|
|
98
|
+
"""
|
|
99
|
+
eigenvectors = np.asarray(eigenvectors)
|
|
100
|
+
weights = np.abs(eigenvectors[..., 0::2, :]) ** 2 + np.abs(eigenvectors[..., 1::2, :]) ** 2
|
|
101
|
+
weights = weights / np.sum(weights, axis=-2, keepdims=True)
|
|
102
|
+
return np.sum(weights**2, axis=-2)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def generalized_ipr(eigenvectors: np.ndarray, q: float) -> np.ndarray:
|
|
106
|
+
"""Generalized inverse participation ratio I_q = sum_i p_i^q, for
|
|
107
|
+
normalized site weights ``p_i = |psi_i|^2``. Reduces to
|
|
108
|
+
``inverse_participation_ratio`` at q=2.
|
|
109
|
+
|
|
110
|
+
The building block for multifractal analysis (see
|
|
111
|
+
``multifractal_dimension``): at a genuinely multifractal critical
|
|
112
|
+
point (e.g. ``PowerLawBandedEnsemble`` at alpha=1), ``E[I_q]``
|
|
113
|
+
scales as ``n**(-D_q*(q-1))`` for a nontrivial, q-dependent D_q,
|
|
114
|
+
rather than the fully-delocalized ``D_q=1`` (``E[I_q] ~ n**-(q-1)``)
|
|
115
|
+
or fully-localized ``D_q=0`` (``E[I_q]`` roughly n-independent).
|
|
116
|
+
|
|
117
|
+
Parameters
|
|
118
|
+
----------
|
|
119
|
+
eigenvectors : numpy.ndarray, shape (..., m, n)
|
|
120
|
+
q : float
|
|
121
|
+
Moment order (q != 1; q=1 is the special "information dimension"
|
|
122
|
+
case, requiring a different limiting definition, not implemented
|
|
123
|
+
here).
|
|
124
|
+
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
numpy.ndarray, shape (..., n)
|
|
128
|
+
"""
|
|
129
|
+
if q == 1:
|
|
130
|
+
raise ValueError("q=1 (information dimension) needs a different limiting definition (based on sum p_i*log(p_i)), not implemented here")
|
|
131
|
+
eigenvectors = np.asarray(eigenvectors)
|
|
132
|
+
weights = np.abs(eigenvectors) ** 2
|
|
133
|
+
weights = weights / np.sum(weights, axis=-2, keepdims=True)
|
|
134
|
+
return np.sum(weights**q, axis=-2)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def mass_exponent(
|
|
138
|
+
ensemble_factory: Callable[..., MatrixEnsemble],
|
|
139
|
+
n_values: list[int],
|
|
140
|
+
q: float,
|
|
141
|
+
n_samples: int = 10,
|
|
142
|
+
seed: int | np.random.Generator | None = None,
|
|
143
|
+
) -> tuple[float, float]:
|
|
144
|
+
"""Estimate the multifractal mass exponent tau(q) by fitting the
|
|
145
|
+
scaling of ``E[generalized_ipr(., q)]`` with system size n:
|
|
146
|
+
|
|
147
|
+
E[I_q](n) ~ n^(-tau(q)) => tau(q) = -slope
|
|
148
|
+
|
|
149
|
+
for a log-log linear regression of mean I_q against n across
|
|
150
|
+
``n_values``. Unlike ``generalized_ipr``, q=1 is supported directly:
|
|
151
|
+
I_1 = sum_i p_i = 1 identically (site weights are already
|
|
152
|
+
normalized probabilities), so tau(1) = 0 exactly, for any ensemble,
|
|
153
|
+
at any n -- no separate "information dimension" limiting definition
|
|
154
|
+
is needed for tau itself (only for D_q = tau(q)/(q-1), which has a
|
|
155
|
+
removable singularity at q=1).
|
|
156
|
+
|
|
157
|
+
``multifractal_dimension`` and ``singularity_spectrum`` are both
|
|
158
|
+
built on this.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
ensemble_factory : callable
|
|
163
|
+
``ensemble_factory(n, seed=...)`` returning a fresh
|
|
164
|
+
``MatrixEnsemble`` instance of size n that supports
|
|
165
|
+
``sample(return_eigenvectors=True)``.
|
|
166
|
+
n_values : list of int
|
|
167
|
+
System sizes to sample at, in increasing order.
|
|
168
|
+
q : float
|
|
169
|
+
Moment order.
|
|
170
|
+
n_samples : int, optional
|
|
171
|
+
Independent matrix draws to pool at each n.
|
|
172
|
+
seed : int, numpy.random.Generator, or None, optional
|
|
173
|
+
|
|
174
|
+
Returns
|
|
175
|
+
-------
|
|
176
|
+
tau_q : float
|
|
177
|
+
r_squared : float
|
|
178
|
+
Goodness of fit of the log-log linear regression (close to 1
|
|
179
|
+
indicates clean power-law scaling over the given n_values).
|
|
180
|
+
"""
|
|
181
|
+
from scipy.stats import linregress
|
|
182
|
+
|
|
183
|
+
if q == 1.0:
|
|
184
|
+
return 0.0, 1.0
|
|
185
|
+
|
|
186
|
+
rng = np.random.default_rng(seed)
|
|
187
|
+
means = []
|
|
188
|
+
for n in n_values:
|
|
189
|
+
ensemble = ensemble_factory(n, seed=int(rng.integers(1 << 31)))
|
|
190
|
+
spectrum = ensemble.sample(n_samples=n_samples, return_eigenvectors=True)
|
|
191
|
+
assert spectrum.eigenvectors is not None
|
|
192
|
+
means.append(generalized_ipr(spectrum.eigenvectors, q).mean())
|
|
193
|
+
fit = linregress(np.log(n_values), np.log(means))
|
|
194
|
+
return -fit.slope, fit.rvalue**2
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def multifractal_dimension(
|
|
198
|
+
ensemble_factory: Callable[..., MatrixEnsemble],
|
|
199
|
+
n_values: list[int],
|
|
200
|
+
q: float,
|
|
201
|
+
n_samples: int = 10,
|
|
202
|
+
seed: int | np.random.Generator | None = None,
|
|
203
|
+
) -> tuple[float, float]:
|
|
204
|
+
"""Estimate the multifractal dimension D_q = tau(q) / (q-1) (see
|
|
205
|
+
``mass_exponent``). Verified during development against the two
|
|
206
|
+
limiting cases on ``PowerLawBandedEnsemble``: D_2 ~ 1 (delocalized,
|
|
207
|
+
large band-width b) and D_2 ~ 0 (localized, small b), both matching
|
|
208
|
+
to within Monte Carlo noise.
|
|
209
|
+
|
|
210
|
+
Parameters
|
|
211
|
+
----------
|
|
212
|
+
ensemble_factory : callable
|
|
213
|
+
``ensemble_factory(n, seed=...)`` returning a fresh
|
|
214
|
+
``MatrixEnsemble`` instance of size n that supports
|
|
215
|
+
``sample(return_eigenvectors=True)``.
|
|
216
|
+
n_values : list of int
|
|
217
|
+
System sizes to sample at, in increasing order.
|
|
218
|
+
q : float
|
|
219
|
+
Moment order (q != 1; q=1 is the special "information dimension"
|
|
220
|
+
case, requiring a different limiting definition, not implemented
|
|
221
|
+
here).
|
|
222
|
+
n_samples : int, optional
|
|
223
|
+
Independent matrix draws to pool at each n.
|
|
224
|
+
seed : int, numpy.random.Generator, or None, optional
|
|
225
|
+
|
|
226
|
+
Returns
|
|
227
|
+
-------
|
|
228
|
+
d_q : float
|
|
229
|
+
r_squared : float
|
|
230
|
+
Goodness of fit of the log-log linear regression (close to 1
|
|
231
|
+
indicates clean power-law scaling over the given n_values).
|
|
232
|
+
"""
|
|
233
|
+
if q == 1:
|
|
234
|
+
raise ValueError("q=1 (information dimension) needs a different limiting definition (based on sum p_i*log(p_i)), not implemented here")
|
|
235
|
+
tau_q, r_squared = mass_exponent(ensemble_factory, n_values, q, n_samples, seed)
|
|
236
|
+
return tau_q / (q - 1.0), r_squared
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def singularity_spectrum(
|
|
240
|
+
ensemble_factory: Callable[..., MatrixEnsemble],
|
|
241
|
+
n_values: list[int],
|
|
242
|
+
q_values: np.ndarray,
|
|
243
|
+
n_samples: int = 10,
|
|
244
|
+
seed: int | np.random.Generator | None = None,
|
|
245
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
246
|
+
"""Estimate the multifractal singularity spectrum f(alpha) via the
|
|
247
|
+
Legendre transform of the mass exponent tau(q) (see
|
|
248
|
+
``mass_exponent``):
|
|
249
|
+
|
|
250
|
+
alpha(q) = d(tau)/dq f(alpha) = q*alpha(q) - tau(q)
|
|
251
|
+
|
|
252
|
+
computed here by evaluating ``mass_exponent`` at each q in
|
|
253
|
+
``q_values`` and numerically differentiating (``numpy.gradient``)
|
|
254
|
+
the resulting tau(q) curve -- exact given tau(q), but tau(q) itself
|
|
255
|
+
is only as reliable as the underlying finite-size scaling fit,
|
|
256
|
+
which needs a wide enough ``n_values`` range and enough statistics
|
|
257
|
+
per point, especially at large |q| (dominated by rare, extreme
|
|
258
|
+
eigenvector configurations that converge more slowly with n than
|
|
259
|
+
the bulk of the distribution -- a well-known practical difficulty in
|
|
260
|
+
multifractal numerics, not specific to this implementation).
|
|
261
|
+
|
|
262
|
+
Numerically observed during development (``PowerLawBandedEnsemble``
|
|
263
|
+
at its multifractal critical point, alpha=1): f(alpha) comes out
|
|
264
|
+
cleanly positive and concave for q roughly in [0, 1.5], but goes
|
|
265
|
+
negative for q gtrsim 2 at the system sizes/sample counts tractable
|
|
266
|
+
here. This MAY be a genuine "negative dimension" branch (a
|
|
267
|
+
documented phenomenon in multifractal analysis, associated with
|
|
268
|
+
rare fluctuations whose probability decays as a negative power of
|
|
269
|
+
system size) rather than an error, but was not independently
|
|
270
|
+
confirmed against a literature reference value -- treat q gtrsim 2
|
|
271
|
+
results as indicative rather than exact, and prefer a wide
|
|
272
|
+
``n_values`` range and large ``n_samples`` there.
|
|
273
|
+
|
|
274
|
+
Parameters
|
|
275
|
+
----------
|
|
276
|
+
ensemble_factory : callable
|
|
277
|
+
n_values : list of int
|
|
278
|
+
q_values : numpy.ndarray
|
|
279
|
+
Moment orders to evaluate tau(q) at (need not exclude q=1).
|
|
280
|
+
n_samples : int, optional
|
|
281
|
+
seed : int, numpy.random.Generator, or None, optional
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
alpha : numpy.ndarray
|
|
286
|
+
f_alpha : numpy.ndarray
|
|
287
|
+
"""
|
|
288
|
+
q_values = np.asarray(q_values, dtype=float)
|
|
289
|
+
rng = np.random.default_rng(seed)
|
|
290
|
+
taus = np.empty_like(q_values)
|
|
291
|
+
for i, q in enumerate(q_values):
|
|
292
|
+
sub_seed = int(rng.integers(1 << 31))
|
|
293
|
+
taus[i], _ = mass_exponent(ensemble_factory, n_values, q, n_samples, seed=sub_seed)
|
|
294
|
+
alpha = np.gradient(taus, q_values)
|
|
295
|
+
f_alpha = q_values * alpha - taus
|
|
296
|
+
return alpha, f_alpha
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def participation_ratio(eigenvectors: np.ndarray) -> np.ndarray:
|
|
300
|
+
"""Participation ratio PR = 1/IPR of each eigenvector (column): the
|
|
301
|
+
effective number of sites a state is spread over -- O(n) for a fully
|
|
302
|
+
delocalized state, O(1) for a localized one.
|
|
303
|
+
|
|
304
|
+
Parameters
|
|
305
|
+
----------
|
|
306
|
+
eigenvectors : numpy.ndarray, shape (..., m, n)
|
|
307
|
+
|
|
308
|
+
Returns
|
|
309
|
+
-------
|
|
310
|
+
numpy.ndarray, shape (..., n)
|
|
311
|
+
"""
|
|
312
|
+
return 1.0 / inverse_participation_ratio(eigenvectors)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def ipr_theory(n: int, beta: float) -> float:
|
|
316
|
+
"""Exact mean IPR of a Haar-distributed (fully delocalized) unit
|
|
317
|
+
vector of dimension ``n`` at Dyson index ``beta``:
|
|
318
|
+
|
|
319
|
+
E[IPR] = (beta/2 + 1) / (n*beta/2 + 1)
|
|
320
|
+
|
|
321
|
+
The delocalized reference value that a localized ensemble's
|
|
322
|
+
empirical IPR (see ``inverse_participation_ratio``) is contrasted
|
|
323
|
+
against -- analogous to ``number_variance_poisson`` as the
|
|
324
|
+
uncorrelated baseline for spectral rigidity.
|
|
325
|
+
|
|
326
|
+
Parameters
|
|
327
|
+
----------
|
|
328
|
+
n : int
|
|
329
|
+
Vector dimension.
|
|
330
|
+
beta : float
|
|
331
|
+
Dyson index (1, 2, or 4 for GOE/GUE/GSE; any beta > 0 valid).
|
|
332
|
+
|
|
333
|
+
Returns
|
|
334
|
+
-------
|
|
335
|
+
float
|
|
336
|
+
"""
|
|
337
|
+
alpha = beta / 2.0
|
|
338
|
+
return (alpha + 1.0) / (n * alpha + 1.0)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""The Marchenko-Pastur law: limiting eigenvalue density of the Wishart
|
|
2
|
+
ensembles.
|
|
3
|
+
|
|
4
|
+
Reference: V. A. Marchenko, L. A. Pastur, "Distribution of eigenvalues
|
|
5
|
+
for some sets of random matrices", Mat. Sb. 72 (1967) 507.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
from scipy.integrate import quad
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def mp_support(gamma: float, sigma2: float = 1.0) -> tuple[float, float]:
|
|
13
|
+
"""Support edges [lambda_minus, lambda_plus] of the Marchenko-Pastur
|
|
14
|
+
density, for aspect ratio gamma = n/m (n variables, m samples,
|
|
15
|
+
m >= n so 0 < gamma <= 1) and entry variance sigma2."""
|
|
16
|
+
lo = sigma2 * (1.0 - np.sqrt(gamma)) ** 2
|
|
17
|
+
hi = sigma2 * (1.0 + np.sqrt(gamma)) ** 2
|
|
18
|
+
return lo, hi
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def mp_pdf(x: np.ndarray, gamma: float, sigma2: float = 1.0) -> np.ndarray:
|
|
22
|
+
"""Marchenko-Pastur probability density at x, for aspect ratio
|
|
23
|
+
gamma = n/m (0 < gamma <= 1; the m >= n regime relevant to the
|
|
24
|
+
``LaguerreBetaEnsemble`` convention here, which has no point mass at
|
|
25
|
+
zero)."""
|
|
26
|
+
lo, hi = mp_support(gamma, sigma2)
|
|
27
|
+
x = np.asarray(x, dtype=float)
|
|
28
|
+
out = np.zeros_like(x)
|
|
29
|
+
mask = (x > lo) & (x < hi)
|
|
30
|
+
xm = x[mask]
|
|
31
|
+
out[mask] = np.sqrt((hi - xm) * (xm - lo)) / (2.0 * np.pi * gamma * sigma2 * xm)
|
|
32
|
+
return out
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def mp_cdf(x: np.ndarray, gamma: float, sigma2: float = 1.0) -> np.ndarray:
|
|
36
|
+
"""Marchenko-Pastur CDF at x (0 < gamma <= 1 regime, no point mass).
|
|
37
|
+
|
|
38
|
+
No elementary closed form for general x, so integrated numerically
|
|
39
|
+
from the lower edge; ``scipy.integrate.quad`` is called per point,
|
|
40
|
+
which is fine for the (typically small) grids this is evaluated on
|
|
41
|
+
directly, but ``validation.marchenko_pastur.MarchenkoPastur`` caches
|
|
42
|
+
a fast interpolated version for use inside a KS test.
|
|
43
|
+
"""
|
|
44
|
+
lo, hi = mp_support(gamma, sigma2)
|
|
45
|
+
x = np.atleast_1d(np.asarray(x, dtype=float))
|
|
46
|
+
out = np.zeros_like(x)
|
|
47
|
+
for i, xi in enumerate(x):
|
|
48
|
+
if xi <= lo:
|
|
49
|
+
out[i] = 0.0
|
|
50
|
+
elif xi >= hi:
|
|
51
|
+
out[i] = 1.0
|
|
52
|
+
else:
|
|
53
|
+
val, _ = quad(mp_pdf, lo, xi, args=(gamma, sigma2))
|
|
54
|
+
out[i] = val
|
|
55
|
+
return out
|