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,181 @@
|
|
|
1
|
+
"""Tests for the random density matrix ensembles (InducedMeasureEnsemble,
|
|
2
|
+
HilbertSchmidtEnsemble, BuresHallEnsemble) and the Page-curve entropy
|
|
3
|
+
helpers.
|
|
4
|
+
|
|
5
|
+
Every formula used for validation here (mean purity for both measures,
|
|
6
|
+
Page's average-entropy formula, and -- most importantly -- the
|
|
7
|
+
Bures-Hall construction itself) was independently checked against exact
|
|
8
|
+
theory or independent numerical integration during development, not
|
|
9
|
+
assumed from a remembered citation; see the module docstrings in
|
|
10
|
+
``physicskit.rmt/ensembles/density_matrix.py`` and
|
|
11
|
+
``physicskit.rmt/stats/entanglement.py``.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
import pytest
|
|
16
|
+
from cache_utils import cached_sample
|
|
17
|
+
from scipy import integrate
|
|
18
|
+
|
|
19
|
+
import physicskit.rmt as rmt
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _mean_purity(spectrum):
|
|
23
|
+
return np.mean(np.sum(spectrum.eigenvalues**2, axis=1))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# --- structural checks common to all three ensembles ---
|
|
27
|
+
|
|
28
|
+
ALL_DM_ENSEMBLES = [
|
|
29
|
+
(
|
|
30
|
+
"InducedMeasure",
|
|
31
|
+
lambda n, seed: rmt.ensembles.InducedMeasureEnsemble(n=n, k=n + 2, seed=seed),
|
|
32
|
+
),
|
|
33
|
+
("HilbertSchmidt", lambda n, seed: rmt.ensembles.HilbertSchmidtEnsemble(n=n, seed=seed)),
|
|
34
|
+
("BuresHall", lambda n, seed: rmt.ensembles.BuresHallEnsemble(n=n, seed=seed)),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.mark.parametrize("name,factory", ALL_DM_ENSEMBLES)
|
|
39
|
+
def test_eigenvalues_are_valid_probability_distribution(name, factory):
|
|
40
|
+
ens = factory(8, 0)
|
|
41
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
42
|
+
assert np.all(spectrum.eigenvalues >= -1e-10)
|
|
43
|
+
assert np.all(spectrum.eigenvalues <= 1.0 + 1e-10)
|
|
44
|
+
np.testing.assert_allclose(spectrum.eigenvalues.sum(axis=1), 1.0, atol=1e-8)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.mark.parametrize("name,factory", ALL_DM_ENSEMBLES)
|
|
48
|
+
def test_reproducibility(name, factory):
|
|
49
|
+
ens_a = factory(6, 42)
|
|
50
|
+
ens_b = factory(6, 42)
|
|
51
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
52
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
53
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_induced_measure_rejects_invalid_k():
|
|
57
|
+
with pytest.raises(ValueError):
|
|
58
|
+
rmt.ensembles.InducedMeasureEnsemble(n=5, k=0, seed=0)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_hilbert_schmidt_beta_is_two():
|
|
62
|
+
ens = rmt.ensembles.HilbertSchmidtEnsemble(n=5, seed=0)
|
|
63
|
+
assert ens.beta == 2
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_bures_hall_beta_is_none():
|
|
67
|
+
# Not one of Dyson's classical beta-ensembles -- extra 1/(li+lj)
|
|
68
|
+
# factor in the joint density beyond a pure Vandermonde power.
|
|
69
|
+
ens = rmt.ensembles.BuresHallEnsemble(n=5, seed=0)
|
|
70
|
+
assert ens.beta is None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_k_equals_one_gives_pure_states():
|
|
74
|
+
# k=1 forces rank-1 rho: exactly one eigenvalue = 1, rest = 0.
|
|
75
|
+
ens = rmt.ensembles.InducedMeasureEnsemble(n=6, k=1, seed=1)
|
|
76
|
+
spectrum = cached_sample(ens, n_samples=10)
|
|
77
|
+
for row in spectrum.eigenvalues:
|
|
78
|
+
assert np.sum(row > 1e-8) == 1
|
|
79
|
+
assert np.max(row) == pytest.approx(1.0, abs=1e-8)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# --- exact mean-purity formulas (Zyczkowski-Sommers 2001) ---
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@pytest.mark.parametrize("n", [2, 3, 5, 10])
|
|
86
|
+
def test_hilbert_schmidt_mean_purity_matches_exact_formula(n):
|
|
87
|
+
ens = rmt.ensembles.HilbertSchmidtEnsemble(n=n, seed=2)
|
|
88
|
+
spectrum = cached_sample(ens, n_samples=20000)
|
|
89
|
+
theory = 2.0 * n / (n**2 + 1)
|
|
90
|
+
assert _mean_purity(spectrum) == pytest.approx(theory, rel=0.03)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@pytest.mark.parametrize("n,k", [(3, 3), (3, 6), (3, 2), (4, 10)])
|
|
94
|
+
def test_induced_measure_mean_purity_matches_exact_formula(n, k):
|
|
95
|
+
ens = rmt.ensembles.InducedMeasureEnsemble(n=n, k=k, seed=3)
|
|
96
|
+
spectrum = cached_sample(ens, n_samples=20000)
|
|
97
|
+
theory = (n + k) / (n * k + 1)
|
|
98
|
+
assert _mean_purity(spectrum) == pytest.approx(theory, rel=0.03)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# --- Bures-Hall: verified directly against its own joint eigenvalue
|
|
102
|
+
# density (not merely against a remembered matrix-model recipe) ---
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@pytest.mark.slow
|
|
106
|
+
def test_bures_hall_matches_exact_n2_marginal_density():
|
|
107
|
+
# For n=2, the exact Bures-Hall joint density on the simplex
|
|
108
|
+
# lambda1+lambda2=1 gives a closed-form 1-D density for the smaller
|
|
109
|
+
# eigenvalue: f(x) ~ (2x-1)^2 / sqrt(x(1-x)) on (0, 1), restricted
|
|
110
|
+
# to (0, 0.5] and doubled (by exchange symmetry) for the SMALLER
|
|
111
|
+
# eigenvalue's marginal CDF.
|
|
112
|
+
def unnorm_pdf(x):
|
|
113
|
+
return (2 * x - 1) ** 2 / np.sqrt(x * (1 - x))
|
|
114
|
+
|
|
115
|
+
z, _ = integrate.quad(unnorm_pdf, 0, 1)
|
|
116
|
+
|
|
117
|
+
def cdf_full(x):
|
|
118
|
+
val, _ = integrate.quad(unnorm_pdf, 0, x)
|
|
119
|
+
return val / z
|
|
120
|
+
|
|
121
|
+
def smaller_eig_cdf(x):
|
|
122
|
+
return np.clip(2.0 * np.vectorize(cdf_full)(np.clip(x, 0, 0.5)), 0.0, 1.0)
|
|
123
|
+
|
|
124
|
+
ens = rmt.ensembles.BuresHallEnsemble(n=2, seed=4)
|
|
125
|
+
spectrum = cached_sample(ens, n_samples=5000)
|
|
126
|
+
smaller_eigs = spectrum.eigenvalues[:, 0] # eigvalsh ascending -> smaller first
|
|
127
|
+
|
|
128
|
+
from scipy.stats import kstest
|
|
129
|
+
|
|
130
|
+
# kstest's per-sample smaller_eig_cdf evaluation (a scipy.integrate.quad
|
|
131
|
+
# call each) dominates runtime, hence the smaller n_samples here vs. the
|
|
132
|
+
# 50000 used elsewhere in this file; the KS threshold is loosened by the
|
|
133
|
+
# matching ~sqrt(10) factor for the noisier statistic at this sample size.
|
|
134
|
+
ks = kstest(smaller_eigs, smaller_eig_cdf)
|
|
135
|
+
assert ks.statistic < 0.06
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_bures_hall_matches_exact_n3_mean_purity_via_joint_density_integration():
|
|
139
|
+
# For n=3, integrate the exact joint density over the 2-D simplex
|
|
140
|
+
# directly (independent of the matrix construction) to get the
|
|
141
|
+
# theoretical mean purity, and compare to Monte Carlo.
|
|
142
|
+
def unnorm_density(l1, l2):
|
|
143
|
+
l3 = 1.0 - l1 - l2
|
|
144
|
+
if l3 <= 0 or l1 <= 0 or l2 <= 0:
|
|
145
|
+
return 0.0
|
|
146
|
+
vand = (l1 - l2) ** 2 * (l1 - l3) ** 2 * (l2 - l3) ** 2
|
|
147
|
+
denom = (l1 + l2) * (l1 + l3) * (l2 + l3)
|
|
148
|
+
weight = (l1 * l2 * l3) ** (-0.5)
|
|
149
|
+
return vand / denom * weight
|
|
150
|
+
|
|
151
|
+
def integrand_z(l2, l1):
|
|
152
|
+
return unnorm_density(l1, l2)
|
|
153
|
+
|
|
154
|
+
def integrand_purity(l2, l1):
|
|
155
|
+
l3 = 1.0 - l1 - l2
|
|
156
|
+
return unnorm_density(l1, l2) * (l1**2 + l2**2 + l3**2)
|
|
157
|
+
|
|
158
|
+
z, _ = integrate.dblquad(integrand_z, 0, 1, lambda l1: 0, lambda l1: 1 - l1)
|
|
159
|
+
p, _ = integrate.dblquad(integrand_purity, 0, 1, lambda l1: 0, lambda l1: 1 - l1)
|
|
160
|
+
theory_mean_purity = p / z
|
|
161
|
+
|
|
162
|
+
ens = rmt.ensembles.BuresHallEnsemble(n=3, seed=5)
|
|
163
|
+
spectrum = cached_sample(ens, n_samples=40000)
|
|
164
|
+
assert _mean_purity(spectrum) == pytest.approx(theory_mean_purity, rel=0.02)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# --- Page curve (bipartite / entanglement) ---
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def test_von_neumann_entropy_handles_zero_eigenvalues():
|
|
171
|
+
assert rmt.stats.von_neumann_entropy([1.0, 0.0, 0.0]) == pytest.approx(0.0)
|
|
172
|
+
assert rmt.stats.von_neumann_entropy([0.5, 0.5]) == pytest.approx(np.log(2.0))
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@pytest.mark.parametrize("n,k", [(2, 2), (2, 8), (3, 3), (3, 10)])
|
|
176
|
+
def test_page_curve_matches_induced_measure_ensemble(n, k):
|
|
177
|
+
ens = rmt.ensembles.InducedMeasureEnsemble(n=n, k=k, seed=6)
|
|
178
|
+
spectrum = cached_sample(ens, n_samples=15000)
|
|
179
|
+
empirical = np.mean([rmt.stats.von_neumann_entropy(row) for row in spectrum.eigenvalues])
|
|
180
|
+
theory = rmt.stats.page_curve_average_entropy(n, k)
|
|
181
|
+
assert empirical == pytest.approx(theory, rel=0.02)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Tests for the non-Hermitian effective Hamiltonian ensembles (EffGOE,
|
|
2
|
+
EffGUE, EffGSE) -- Feshbach-projection/chaotic-scattering resonance
|
|
3
|
+
ensembles built on GOE/GUE/GSE.
|
|
4
|
+
|
|
5
|
+
Like BdG (see ``tests/test_bdg.py``), there is no simple closed-form
|
|
6
|
+
bulk density to benchmark here, so validation is structural: causality
|
|
7
|
+
(widths never negative -- a property proved directly from Hermiticity
|
|
8
|
+
and positive semi-definiteness in the module docstring, not merely
|
|
9
|
+
observed), the m=0 Hermitian limit, and beta=4's Kramers degeneracy.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
import pytest
|
|
14
|
+
from cache_utils import cached_sample
|
|
15
|
+
|
|
16
|
+
import physicskit.rmt as rmt
|
|
17
|
+
|
|
18
|
+
EFFECTIVE = [
|
|
19
|
+
("EffGOE", rmt.ensembles.EffGOE, 1),
|
|
20
|
+
("EffGUE", rmt.ensembles.EffGUE, 2),
|
|
21
|
+
("EffGSE", rmt.ensembles.EffGSE, 4),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
|
|
26
|
+
def test_beta_is_correct(name, cls, beta):
|
|
27
|
+
ens = cls(n=30, m=5, seed=0)
|
|
28
|
+
assert ens.beta == beta
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
|
|
32
|
+
def test_eigenvalues_are_complex(name, cls, beta):
|
|
33
|
+
ens = cls(n=40, m=5, seed=1)
|
|
34
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
35
|
+
assert np.iscomplexobj(spectrum.eigenvalues)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
|
|
39
|
+
def test_produces_n_eigenvalues(name, cls, beta):
|
|
40
|
+
# beta=4 internally builds a 2n x 2n embedding but de-duplicates the
|
|
41
|
+
# exact Kramers pairs, so all three classes return exactly n
|
|
42
|
+
# eigenvalues per sample -- see module docstring.
|
|
43
|
+
ens = cls(n=25, m=4, seed=2)
|
|
44
|
+
spectrum = cached_sample(ens, n_samples=6)
|
|
45
|
+
assert spectrum.eigenvalues.shape == (6, 25)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
|
|
49
|
+
def test_reproducibility(name, cls, beta):
|
|
50
|
+
ens_a = cls(n=30, m=5, seed=42)
|
|
51
|
+
ens_b = cls(n=30, m=5, seed=42)
|
|
52
|
+
spec_a = ens_a.sample(n_samples=3)
|
|
53
|
+
spec_b = ens_b.sample(n_samples=3)
|
|
54
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
|
|
58
|
+
def test_widths_are_never_positive_causality(name, cls, beta):
|
|
59
|
+
# Gamma_k = -2*Im(lambda_k) >= 0 for every eigenvalue of every
|
|
60
|
+
# realization -- proved directly (not just observed) in the module
|
|
61
|
+
# docstring from H Hermitian + Gamma Hermitian PSD.
|
|
62
|
+
ens = cls(n=35, m=6, coupling=1.3, seed=3)
|
|
63
|
+
spectrum = cached_sample(ens, n_samples=20)
|
|
64
|
+
assert np.all(spectrum.eigenvalues.imag <= 1e-9)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
|
|
68
|
+
def test_zero_channels_recovers_hermitian_limit(name, cls, beta):
|
|
69
|
+
# m=0 -> Gamma=0 -> H_eff=H exactly -> real eigenvalues to machine
|
|
70
|
+
# precision, regardless of beta.
|
|
71
|
+
ens = cls(n=30, m=0, seed=4)
|
|
72
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
73
|
+
assert np.abs(spectrum.eigenvalues.imag).max() < 1e-9
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
|
|
77
|
+
def test_more_channels_increase_total_width(name, cls, beta):
|
|
78
|
+
# More open channels -> more total decay -> larger mean |Im(lambda)|
|
|
79
|
+
# (monotonic on average, not realization-by-realization).
|
|
80
|
+
total_widths = []
|
|
81
|
+
for m in (1, 4, 10):
|
|
82
|
+
ens = cls(n=40, m=m, seed=5)
|
|
83
|
+
spectrum = cached_sample(ens, n_samples=15)
|
|
84
|
+
total_widths.append(np.mean(-spectrum.eigenvalues.imag))
|
|
85
|
+
assert total_widths[0] < total_widths[1] < total_widths[2]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_effgse_eigenvalues_form_exact_kramers_pairs():
|
|
89
|
+
# Direct, un-cached check against the raw (non-deduplicated) 2n
|
|
90
|
+
# eigenvalues: EffGSE's Kramers degeneracy should be exact (machine
|
|
91
|
+
# precision), unlike GinSE's merely-conjugate (distinct) pairs.
|
|
92
|
+
from physicskit.rmt.ensembles.effective_hamiltonian import (
|
|
93
|
+
_sample_coupling,
|
|
94
|
+
_sample_hamiltonian,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
rng = np.random.default_rng(6)
|
|
98
|
+
n, m = 15, 3
|
|
99
|
+
h = _sample_hamiltonian(n, rng, beta=4)
|
|
100
|
+
v = _sample_coupling(n, m, rng, beta=4)
|
|
101
|
+
gamma = v @ v.conj().T
|
|
102
|
+
h_eff = h - 0.5j * gamma
|
|
103
|
+
|
|
104
|
+
eigs = np.linalg.eigvals(h_eff)
|
|
105
|
+
order = np.lexsort((eigs.imag, eigs.real))
|
|
106
|
+
sorted_eigs = eigs[order]
|
|
107
|
+
pair_diffs = np.abs(sorted_eigs[0::2] - sorted_eigs[1::2])
|
|
108
|
+
assert pair_diffs.max() < 1e-8
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_zero_coupling_is_equivalent_to_zero_channels():
|
|
112
|
+
# coupling=0 with m>0 should give the same Hermitian-limit behavior
|
|
113
|
+
# as m=0 (Gamma=0 either way).
|
|
114
|
+
ens = rmt.ensembles.EffGUE(n=25, m=6, coupling=0.0, seed=7)
|
|
115
|
+
spectrum = cached_sample(ens, n_samples=5)
|
|
116
|
+
assert np.abs(spectrum.eigenvalues.imag).max() < 1e-9
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_zero_channels_fresh_sample_recovers_hermitian_limit():
|
|
120
|
+
# A fresh (uncached) direct .sample() call, so the m=0 -> Gamma=0
|
|
121
|
+
# branch is actually exercised rather than risking a disk-cache hit.
|
|
122
|
+
ens = rmt.ensembles.EffGOE(n=6, m=0, seed=555)
|
|
123
|
+
spectrum = ens.sample(n_samples=2)
|
|
124
|
+
assert np.abs(spectrum.eigenvalues.imag).max() < 1e-9
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_sample_hamiltonian_and_coupling_reject_invalid_beta():
|
|
128
|
+
from physicskit.rmt.ensembles.effective_hamiltonian import _sample_coupling, _sample_hamiltonian
|
|
129
|
+
|
|
130
|
+
with pytest.raises(ValueError):
|
|
131
|
+
_sample_hamiltonian(5, np.random.default_rng(0), beta=3)
|
|
132
|
+
with pytest.raises(ValueError):
|
|
133
|
+
_sample_coupling(5, 3, np.random.default_rng(0), beta=3)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_effective_hamiltonian_ensemble_rejects_invalid_beta_and_negative_m():
|
|
137
|
+
with pytest.raises(ValueError):
|
|
138
|
+
rmt.ensembles.EffectiveHamiltonianEnsemble(n=5, m=1, beta=3, seed=0)
|
|
139
|
+
with pytest.raises(ValueError):
|
|
140
|
+
rmt.ensembles.EffectiveHamiltonianEnsemble(n=5, m=-1, beta=2, seed=0)
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""Tests for the embedded Gaussian ensembles (EmbeddedGaussianEnsemble,
|
|
2
|
+
TwoBodyRandomEnsemble).
|
|
3
|
+
|
|
4
|
+
Unlike every classical ensemble in this package, the many-body
|
|
5
|
+
Hamiltonian here is built by embedding a k-body random interaction into
|
|
6
|
+
a Fock space, via hand-rolled Jordan-Wigner fermionic operators -- a
|
|
7
|
+
genuinely new piece of machinery with real correctness risk (an initial
|
|
8
|
+
implementation had the raising/lowering matrices swapped, caught only
|
|
9
|
+
by the k=m exact-match check below, not by the Hermiticity or particle-
|
|
10
|
+
number-conservation checks, which both silently passed anyway). These
|
|
11
|
+
tests reproduce that verification chain directly rather than only
|
|
12
|
+
trusting the module docstring's account of it.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
import pytest
|
|
17
|
+
from cache_utils import cached_sample
|
|
18
|
+
|
|
19
|
+
import physicskit.rmt as rmt
|
|
20
|
+
from physicskit.rmt.ensembles.embedded import _fermion_ladder_operators
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_ladder_operators_satisfy_fermionic_algebra():
|
|
24
|
+
n = 5
|
|
25
|
+
creators = _fermion_ladder_operators(n)
|
|
26
|
+
annihilators = [c.conj().T for c in creators]
|
|
27
|
+
dim = 2**n
|
|
28
|
+
identity = np.eye(dim, dtype=complex)
|
|
29
|
+
for i in range(n):
|
|
30
|
+
for j in range(n):
|
|
31
|
+
anticomm_ac = annihilators[i] @ creators[j] + creators[j] @ annihilators[i]
|
|
32
|
+
target = identity if i == j else np.zeros((dim, dim))
|
|
33
|
+
assert np.abs(anticomm_ac - target).max() < 1e-10
|
|
34
|
+
|
|
35
|
+
anticomm_aa = annihilators[i] @ annihilators[j] + annihilators[j] @ annihilators[i]
|
|
36
|
+
assert np.abs(anticomm_aa).max() < 1e-10
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@pytest.mark.parametrize("k,m,n_levels", [(2, 2, 4), (3, 3, 6)])
|
|
40
|
+
def test_k_equals_m_reduces_exactly_to_the_interaction_matrix(k, m, n_levels):
|
|
41
|
+
# The construction's most important structural check: with only m=k
|
|
42
|
+
# particles present, the embedding is trivial and H, restricted to
|
|
43
|
+
# the m-particle sector, must equal the k-body interaction matrix V
|
|
44
|
+
# EXACTLY (not merely statistically) -- this is precisely the check
|
|
45
|
+
# that caught an operator-ordering sign bug during development.
|
|
46
|
+
from itertools import combinations
|
|
47
|
+
|
|
48
|
+
from physicskit.rmt.ensembles.embedded import _fermion_ladder_operators
|
|
49
|
+
|
|
50
|
+
creators = _fermion_ladder_operators(n_levels)
|
|
51
|
+
tuples = list(combinations(range(n_levels), k))
|
|
52
|
+
n_tuples = len(tuples)
|
|
53
|
+
rng = np.random.default_rng(0)
|
|
54
|
+
x = rng.standard_normal((n_tuples, n_tuples))
|
|
55
|
+
v = (x + x.T) / np.sqrt(2.0)
|
|
56
|
+
|
|
57
|
+
def multi_create(idxs):
|
|
58
|
+
op = creators[idxs[0]]
|
|
59
|
+
for idx in idxs[1:]:
|
|
60
|
+
op = op @ creators[idx]
|
|
61
|
+
return op
|
|
62
|
+
|
|
63
|
+
p_ops = [multi_create(t) for t in tuples]
|
|
64
|
+
dim = p_ops[0].shape[0]
|
|
65
|
+
h = np.zeros((dim, dim), dtype=complex)
|
|
66
|
+
for a_idx in range(n_tuples):
|
|
67
|
+
q = sum(v[a_idx, b_idx] * p_ops[b_idx].conj().T for b_idx in range(n_tuples))
|
|
68
|
+
h += p_ops[a_idx] @ q
|
|
69
|
+
|
|
70
|
+
def occ_to_index(occ, n):
|
|
71
|
+
idx = 0
|
|
72
|
+
for site in occ:
|
|
73
|
+
idx |= 1 << (n - 1 - site)
|
|
74
|
+
return idx
|
|
75
|
+
|
|
76
|
+
basis = [occ_to_index(t, n_levels) for t in tuples]
|
|
77
|
+
h_sub = h[np.ix_(basis, basis)].real
|
|
78
|
+
np.testing.assert_allclose(h_sub, v, atol=1e-10)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.mark.parametrize("beta", [1, 2])
|
|
82
|
+
def test_hermiticity_and_particle_number_conservation(beta):
|
|
83
|
+
n_levels = 6
|
|
84
|
+
rng = np.random.default_rng(1)
|
|
85
|
+
# Directly rebuild the dense (pre-restriction) Hamiltonian to check
|
|
86
|
+
# Hermiticity and particle-number conservation on the FULL Fock
|
|
87
|
+
# space, not just the already-restricted eigenvalue output.
|
|
88
|
+
from itertools import combinations
|
|
89
|
+
|
|
90
|
+
from physicskit.rmt.ensembles.embedded import _fermion_ladder_operators
|
|
91
|
+
|
|
92
|
+
creators = _fermion_ladder_operators(n_levels)
|
|
93
|
+
tuples = list(combinations(range(n_levels), 2))
|
|
94
|
+
n_tuples = len(tuples)
|
|
95
|
+
if beta == 1:
|
|
96
|
+
x = rng.standard_normal((n_tuples, n_tuples))
|
|
97
|
+
v = (x + x.T) / np.sqrt(2.0)
|
|
98
|
+
else:
|
|
99
|
+
real_part = rng.standard_normal((n_tuples, n_tuples))
|
|
100
|
+
imag_part = rng.standard_normal((n_tuples, n_tuples))
|
|
101
|
+
x = (real_part + 1j * imag_part) / np.sqrt(2.0)
|
|
102
|
+
v = (x + x.conj().T) / 2.0
|
|
103
|
+
|
|
104
|
+
def multi_create(idxs):
|
|
105
|
+
op = creators[idxs[0]]
|
|
106
|
+
for idx in idxs[1:]:
|
|
107
|
+
op = op @ creators[idx]
|
|
108
|
+
return op
|
|
109
|
+
|
|
110
|
+
p_ops = [multi_create(t) for t in tuples]
|
|
111
|
+
dim = p_ops[0].shape[0]
|
|
112
|
+
h = np.zeros((dim, dim), dtype=complex)
|
|
113
|
+
for a_idx in range(n_tuples):
|
|
114
|
+
q = sum(v[a_idx, b_idx] * p_ops[b_idx].conj().T for b_idx in range(n_tuples))
|
|
115
|
+
h += p_ops[a_idx] @ q
|
|
116
|
+
|
|
117
|
+
assert np.abs(h - h.conj().T).max() < 1e-10
|
|
118
|
+
|
|
119
|
+
annihilators = [c.conj().T for c in creators]
|
|
120
|
+
n_total = sum(creators[i] @ annihilators[i] for i in range(n_levels))
|
|
121
|
+
assert np.abs(h @ n_total - n_total @ h).max() < 1e-8
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def test_beta_and_k_are_stored():
|
|
125
|
+
ens = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, beta=2, seed=0)
|
|
126
|
+
assert ens.k == 2
|
|
127
|
+
assert ens.beta == 2
|
|
128
|
+
assert ens.n_levels == 6
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_invalid_parameters_rejected():
|
|
132
|
+
with pytest.raises(ValueError):
|
|
133
|
+
rmt.ensembles.EmbeddedGaussianEnsemble(n_particles=3, n_levels=6, beta=3, seed=0)
|
|
134
|
+
with pytest.raises(ValueError):
|
|
135
|
+
rmt.ensembles.EmbeddedGaussianEnsemble(n_particles=3, n_levels=6, k=1, seed=0)
|
|
136
|
+
with pytest.raises(ValueError):
|
|
137
|
+
rmt.ensembles.EmbeddedGaussianEnsemble(n_particles=8, n_levels=6, k=2, seed=0)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_produces_binomial_n_levels_choose_m_eigenvalues():
|
|
141
|
+
from math import comb
|
|
142
|
+
|
|
143
|
+
ens = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, seed=2)
|
|
144
|
+
spectrum = cached_sample(ens, n_samples=3)
|
|
145
|
+
assert spectrum.eigenvalues.shape == (3, comb(6, 3))
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_eigenvalues_are_real():
|
|
149
|
+
ens = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, beta=2, seed=3)
|
|
150
|
+
spectrum = cached_sample(ens, n_samples=3)
|
|
151
|
+
assert not np.iscomplexobj(spectrum.eigenvalues)
|
|
152
|
+
assert np.all(np.isfinite(spectrum.eigenvalues))
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_beta_2_fresh_sample_is_real_and_finite():
|
|
156
|
+
# A fresh (uncached) direct .sample() call, to actually exercise the
|
|
157
|
+
# complex-construction (beta != 1) branch rather than risk a cache hit.
|
|
158
|
+
ens = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=2, n_levels=4, beta=2, seed=777)
|
|
159
|
+
spectrum = ens.sample(n_samples=2)
|
|
160
|
+
assert not np.iscomplexobj(spectrum.eigenvalues)
|
|
161
|
+
assert np.all(np.isfinite(spectrum.eigenvalues))
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def test_reproducibility():
|
|
165
|
+
ens_a = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, seed=42)
|
|
166
|
+
ens_b = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, seed=42)
|
|
167
|
+
spec_a = ens_a.sample(n_samples=2)
|
|
168
|
+
spec_b = ens_b.sample(n_samples=2)
|
|
169
|
+
np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Tests for the free probability module (Stieltjes/R-transform, free
|
|
2
|
+
additive convolution).
|
|
3
|
+
|
|
4
|
+
The semicircle R-transform (R(w) = w) was derived directly here (solving
|
|
5
|
+
w = G(z) for z from the semicircle's own Stieltjes transform), not
|
|
6
|
+
recalled, and the generic numerical inversion pipeline
|
|
7
|
+
(``r_transform_numerical``) was checked to reproduce it before being
|
|
8
|
+
trusted to derive/verify the Marchenko-Pastur R-transform
|
|
9
|
+
(R(w) = 1/(1-gamma*w)) against the already-validated exact MP density.
|
|
10
|
+
The free additive convolution theorem itself (R_{A+B} = R_A + R_B for
|
|
11
|
+
independent, asymptotically free random matrices) is checked directly
|
|
12
|
+
against real matrix simulation (independent GOE + Wishart matrices
|
|
13
|
+
added together), not just asserted from the individual closed forms.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
import physicskit.rmt as rmt
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_stieltjes_transform_semicircle_matches_empirical():
|
|
23
|
+
ens = rmt.ensembles.GOE(n=2000, seed=0)
|
|
24
|
+
spectrum = ens.sample(n_samples=1)
|
|
25
|
+
eigs = spectrum.rescaled[0]
|
|
26
|
+
for z in [3.0, 5.0, 10.0]:
|
|
27
|
+
empirical = rmt.stats.stieltjes_transform_empirical(eigs, z)
|
|
28
|
+
exact = rmt.stats.stieltjes_transform_semicircle(z)
|
|
29
|
+
assert empirical.real == pytest.approx(exact.real, abs=0.02)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_numerical_inversion_recovers_semicircle_r_transform():
|
|
33
|
+
# The pipeline itself, exercised on a Stieltjes transform with a
|
|
34
|
+
# known-exact R-transform (see module docstring for the derivation).
|
|
35
|
+
for w in [0.1, 0.3, 0.6, 0.9]:
|
|
36
|
+
r_numerical = rmt.stats.r_transform_numerical(rmt.stats.stieltjes_transform_semicircle, w, z_bracket=(2.0001, 100.0))
|
|
37
|
+
assert r_numerical == pytest.approx(rmt.stats.r_transform_semicircle(w), rel=1e-4)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_numerical_inversion_recovers_marchenko_pastur_r_transform():
|
|
41
|
+
gamma = 0.5
|
|
42
|
+
lo, hi = rmt.stats.mp_support(gamma)
|
|
43
|
+
|
|
44
|
+
def stieltjes_mp(z):
|
|
45
|
+
from scipy.integrate import quad
|
|
46
|
+
|
|
47
|
+
real, _ = quad(lambda x: rmt.stats.mp_pdf(np.array([x]), gamma)[0] / (z - x), lo, hi, limit=200)
|
|
48
|
+
return real
|
|
49
|
+
|
|
50
|
+
for w in [0.1, 0.3, 0.6]:
|
|
51
|
+
r_numerical = rmt.stats.r_transform_numerical(stieltjes_mp, w, z_bracket=(hi + 1e-6, hi + 50.0))
|
|
52
|
+
assert r_numerical == pytest.approx(rmt.stats.r_transform_marchenko_pastur(w, gamma), rel=1e-3)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_free_additive_convolution_for_goe_plus_wishart():
|
|
56
|
+
# The genuine content of free probability's additive convolution
|
|
57
|
+
# theorem: for independent (hence asymptotically free) GOE and
|
|
58
|
+
# Wishart matrices A, B, the R-transform of A+B's spectral
|
|
59
|
+
# distribution should equal R_A + R_B -- checked here against DIRECT
|
|
60
|
+
# matrix simulation, not just the two closed forms in isolation.
|
|
61
|
+
rng = np.random.default_rng(0)
|
|
62
|
+
n = 800
|
|
63
|
+
gamma = 0.5
|
|
64
|
+
m = int(n / gamma)
|
|
65
|
+
|
|
66
|
+
x = rng.standard_normal((n, n))
|
|
67
|
+
a = (x + x.T) / np.sqrt(2.0) / np.sqrt(n) # semicircle normalization, variance 1
|
|
68
|
+
|
|
69
|
+
y = rng.standard_normal((n, m)) / np.sqrt(m)
|
|
70
|
+
b = y @ y.T # Marchenko-Pastur normalization at aspect ratio gamma
|
|
71
|
+
|
|
72
|
+
c_eigs = np.linalg.eigvalsh(a + b)
|
|
73
|
+
|
|
74
|
+
def stieltjes_c(z):
|
|
75
|
+
return rmt.stats.stieltjes_transform_empirical(c_eigs, z)
|
|
76
|
+
|
|
77
|
+
z_bracket = (c_eigs.max() + 0.05, c_eigs.max() + 50.0)
|
|
78
|
+
for w in [0.1, 0.2, 0.3]:
|
|
79
|
+
r_c = rmt.stats.r_transform_numerical(stieltjes_c, w, z_bracket)
|
|
80
|
+
r_sum = rmt.stats.r_transform_semicircle(w) + rmt.stats.r_transform_marchenko_pastur(w, gamma)
|
|
81
|
+
assert r_c == pytest.approx(r_sum, rel=0.01)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Coverage for physicskit.rmt.ensembles.gaussian.HermiteBetaEnsemble
|
|
2
|
+
(previously untested directly): the return_eigenvectors=True guard for
|
|
3
|
+
continuum (non-classical) beta values."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
import physicskit.rmt as rmt
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_return_eigenvectors_rejects_continuum_beta():
|
|
14
|
+
ens = rmt.ensembles.HermiteBetaEnsemble(n=10, beta=1.5, seed=0)
|
|
15
|
+
with pytest.raises(NotImplementedError):
|
|
16
|
+
ens.sample(n_samples=2, return_eigenvectors=True)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_return_eigenvectors_works_for_classical_beta():
|
|
20
|
+
ens = rmt.ensembles.GOE(n=10, seed=0)
|
|
21
|
+
spectrum = ens.sample(n_samples=2, return_eigenvectors=True)
|
|
22
|
+
assert np.all(np.isfinite(spectrum.eigenvalues))
|