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,462 @@
|
|
|
1
|
+
"""Numba-accelerated Monte Carlo kernels for lattice spin models.
|
|
2
|
+
|
|
3
|
+
This module holds the hot inner loops shared by :mod:`physicskit.statphys.chapters.ising_lattice`:
|
|
4
|
+
single-spin-flip Metropolis-Hastings sweeps for the Ising and Potts models, a
|
|
5
|
+
continuous-angle Metropolis sweep for the XY model, and the Wolff single-cluster
|
|
6
|
+
algorithm for the Ising model. Functions are JIT-compiled with :func:`numba.njit`
|
|
7
|
+
so that a full lattice sweep of :math:`L \\times L` sites costs a handful of
|
|
8
|
+
microseconds rather than a Python-loop pass.
|
|
9
|
+
|
|
10
|
+
All lattices use periodic boundary conditions.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
from numba import njit
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"ising_total_energy",
|
|
20
|
+
"ising_total_magnetization",
|
|
21
|
+
"metropolis_sweep_ising",
|
|
22
|
+
"metropolis_sweep_potts",
|
|
23
|
+
"metropolis_sweep_sk",
|
|
24
|
+
"metropolis_sweep_spin_glass",
|
|
25
|
+
"metropolis_sweep_xy",
|
|
26
|
+
"potts_total_energy",
|
|
27
|
+
"seed_numba_random",
|
|
28
|
+
"sk_total_energy",
|
|
29
|
+
"spin_glass_total_energy",
|
|
30
|
+
"wolff_step_ising",
|
|
31
|
+
"xy_plaquette_vorticity",
|
|
32
|
+
"xy_total_energy",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@njit(cache=True)
|
|
37
|
+
def seed_numba_random(seed):
|
|
38
|
+
"""Seed the random-number generator used by every ``@njit`` kernel in physicskit.statphys.
|
|
39
|
+
|
|
40
|
+
Plain ``numpy.random.seed`` only reseeds NumPy's own global generator
|
|
41
|
+
and has **no effect** on Numba-compiled (``@njit``) code, which
|
|
42
|
+
maintains a single separate internal RNG state shared by every
|
|
43
|
+
``@njit`` function in the process (regardless of which module defines
|
|
44
|
+
them). Calling ``np.random.seed`` from *inside* jitted code, as this
|
|
45
|
+
thin wrapper does, is the only way to obtain reproducible dynamics from
|
|
46
|
+
any of physicskit.statphys's Monte Carlo sweep or random-walk kernels.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
seed : int
|
|
51
|
+
Seed value.
|
|
52
|
+
"""
|
|
53
|
+
np.random.seed(seed)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@njit(cache=True)
|
|
57
|
+
def _ising_neighbor_sum(spins, i, j, L):
|
|
58
|
+
top = spins[(i - 1) % L, j]
|
|
59
|
+
bottom = spins[(i + 1) % L, j]
|
|
60
|
+
left = spins[i, (j - 1) % L]
|
|
61
|
+
right = spins[i, (j + 1) % L]
|
|
62
|
+
return top + bottom + left + right
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@njit(cache=True)
|
|
66
|
+
def metropolis_sweep_ising(spins, beta, J):
|
|
67
|
+
"""Perform one Metropolis-Hastings sweep of an Ising lattice, in place.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
spins : ndarray of shape (L, L), dtype int64
|
|
72
|
+
Spin configuration with values in ``{-1, +1}``. Modified in place.
|
|
73
|
+
beta : float
|
|
74
|
+
Inverse temperature :math:`1 / (k_B T)`.
|
|
75
|
+
J : float
|
|
76
|
+
Ferromagnetic (``J > 0``) or antiferromagnetic (``J < 0``) coupling.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
ndarray of shape (L, L)
|
|
81
|
+
The same array passed in (returned for convenience).
|
|
82
|
+
|
|
83
|
+
Notes
|
|
84
|
+
-----
|
|
85
|
+
One sweep proposes :math:`L^2` single-spin flips at randomly chosen sites,
|
|
86
|
+
each accepted with probability :math:`\\min(1, e^{-\\beta \\Delta E})`, where
|
|
87
|
+
:math:`\\Delta E = 2 J s_i \\sum_{\\langle i,j \\rangle} s_j`.
|
|
88
|
+
"""
|
|
89
|
+
L = spins.shape[0]
|
|
90
|
+
n = L * L
|
|
91
|
+
for _ in range(n):
|
|
92
|
+
i = np.random.randint(0, L)
|
|
93
|
+
j = np.random.randint(0, L)
|
|
94
|
+
s = spins[i, j]
|
|
95
|
+
neighbor_sum = _ising_neighbor_sum(spins, i, j, L)
|
|
96
|
+
dE = 2.0 * J * s * neighbor_sum
|
|
97
|
+
if dE <= 0.0 or np.random.random() < np.exp(-beta * dE):
|
|
98
|
+
spins[i, j] = -s
|
|
99
|
+
return spins
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@njit(cache=True)
|
|
103
|
+
def wolff_step_ising(spins, beta, J):
|
|
104
|
+
"""Grow and flip a single Wolff cluster on an Ising lattice, in place.
|
|
105
|
+
|
|
106
|
+
The Wolff algorithm adds a same-spin neighbor to the growing cluster with
|
|
107
|
+
probability :math:`p_{\\text{add}} = 1 - e^{-2 \\beta J}`, then flips the
|
|
108
|
+
entire cluster at once. It suppresses the critical slowing down that
|
|
109
|
+
afflicts single-spin-flip Metropolis dynamics near :math:`T_c`.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
spins : ndarray of shape (L, L), dtype int64
|
|
114
|
+
Spin configuration with values in ``{-1, +1}``. Modified in place.
|
|
115
|
+
beta : float
|
|
116
|
+
Inverse temperature.
|
|
117
|
+
J : float
|
|
118
|
+
Ferromagnetic coupling constant (should be positive).
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
int
|
|
123
|
+
Number of spins flipped in this cluster update.
|
|
124
|
+
"""
|
|
125
|
+
L = spins.shape[0]
|
|
126
|
+
p_add = 1.0 - np.exp(-2.0 * beta * J)
|
|
127
|
+
|
|
128
|
+
stack_i = np.empty(L * L, dtype=np.int64)
|
|
129
|
+
stack_j = np.empty(L * L, dtype=np.int64)
|
|
130
|
+
top = 0
|
|
131
|
+
|
|
132
|
+
i0 = np.random.randint(0, L)
|
|
133
|
+
j0 = np.random.randint(0, L)
|
|
134
|
+
cluster_spin = spins[i0, j0]
|
|
135
|
+
|
|
136
|
+
in_cluster = np.zeros((L, L), dtype=np.bool_)
|
|
137
|
+
in_cluster[i0, j0] = True
|
|
138
|
+
spins[i0, j0] = -cluster_spin
|
|
139
|
+
stack_i[top] = i0
|
|
140
|
+
stack_j[top] = j0
|
|
141
|
+
top += 1
|
|
142
|
+
cluster_size = 1
|
|
143
|
+
|
|
144
|
+
while top > 0:
|
|
145
|
+
top -= 1
|
|
146
|
+
i = stack_i[top]
|
|
147
|
+
j = stack_j[top]
|
|
148
|
+
for di, dj in ((-1, 0), (1, 0), (0, -1), (0, 1)):
|
|
149
|
+
ni = (i + di) % L
|
|
150
|
+
nj = (j + dj) % L
|
|
151
|
+
if (not in_cluster[ni, nj]) and spins[ni, nj] == cluster_spin and np.random.random() < p_add:
|
|
152
|
+
in_cluster[ni, nj] = True
|
|
153
|
+
spins[ni, nj] = -cluster_spin
|
|
154
|
+
stack_i[top] = ni
|
|
155
|
+
stack_j[top] = nj
|
|
156
|
+
top += 1
|
|
157
|
+
cluster_size += 1
|
|
158
|
+
return cluster_size
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@njit(cache=True)
|
|
162
|
+
def metropolis_sweep_potts(spins, beta, J, q):
|
|
163
|
+
"""Perform one Metropolis-Hastings sweep of a q-state Potts lattice, in place.
|
|
164
|
+
|
|
165
|
+
Parameters
|
|
166
|
+
----------
|
|
167
|
+
spins : ndarray of shape (L, L), dtype int64
|
|
168
|
+
Spin configuration with values in ``{0, ..., q-1}``. Modified in place.
|
|
169
|
+
beta : float
|
|
170
|
+
Inverse temperature.
|
|
171
|
+
J : float
|
|
172
|
+
Coupling constant. The bond energy is :math:`-J` when neighboring
|
|
173
|
+
spins agree and ``0`` otherwise (Potts Hamiltonian).
|
|
174
|
+
q : int
|
|
175
|
+
Number of Potts states.
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
ndarray of shape (L, L)
|
|
180
|
+
The same array passed in.
|
|
181
|
+
"""
|
|
182
|
+
L = spins.shape[0]
|
|
183
|
+
n = L * L
|
|
184
|
+
for _ in range(n):
|
|
185
|
+
i = np.random.randint(0, L)
|
|
186
|
+
j = np.random.randint(0, L)
|
|
187
|
+
s = spins[i, j]
|
|
188
|
+
top = spins[(i - 1) % L, j]
|
|
189
|
+
bottom = spins[(i + 1) % L, j]
|
|
190
|
+
left = spins[i, (j - 1) % L]
|
|
191
|
+
right = spins[i, (j + 1) % L]
|
|
192
|
+
new_s = np.random.randint(0, q)
|
|
193
|
+
old_matches = (s == top) + (s == bottom) + (s == left) + (s == right)
|
|
194
|
+
new_matches = (new_s == top) + (new_s == bottom) + (new_s == left) + (new_s == right)
|
|
195
|
+
dE = -J * (new_matches - old_matches)
|
|
196
|
+
if dE <= 0.0 or np.random.random() < np.exp(-beta * dE):
|
|
197
|
+
spins[i, j] = new_s
|
|
198
|
+
return spins
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@njit(cache=True)
|
|
202
|
+
def metropolis_sweep_xy(theta, beta, J, delta=1.0):
|
|
203
|
+
"""Perform one Metropolis-Hastings sweep of a 2D XY lattice, in place.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
theta : ndarray of shape (L, L), dtype float64
|
|
208
|
+
Planar spin angles in radians, :math:`\\theta_i \\in [0, 2\\pi)`.
|
|
209
|
+
Modified in place.
|
|
210
|
+
beta : float
|
|
211
|
+
Inverse temperature.
|
|
212
|
+
J : float
|
|
213
|
+
Coupling constant. Bond energy is :math:`-J \\cos(\\theta_i - \\theta_j)`.
|
|
214
|
+
delta : float, default=1.0
|
|
215
|
+
Maximum angular step of a trial move, drawn uniformly from
|
|
216
|
+
``[-delta, delta]``.
|
|
217
|
+
|
|
218
|
+
Returns
|
|
219
|
+
-------
|
|
220
|
+
ndarray of shape (L, L)
|
|
221
|
+
The same array passed in.
|
|
222
|
+
"""
|
|
223
|
+
L = theta.shape[0]
|
|
224
|
+
n = L * L
|
|
225
|
+
two_pi = 2.0 * np.pi
|
|
226
|
+
for _ in range(n):
|
|
227
|
+
i = np.random.randint(0, L)
|
|
228
|
+
j = np.random.randint(0, L)
|
|
229
|
+
old = theta[i, j]
|
|
230
|
+
new = old + (2.0 * np.random.random() - 1.0) * delta
|
|
231
|
+
|
|
232
|
+
top = theta[(i - 1) % L, j]
|
|
233
|
+
bottom = theta[(i + 1) % L, j]
|
|
234
|
+
left = theta[i, (j - 1) % L]
|
|
235
|
+
right = theta[i, (j + 1) % L]
|
|
236
|
+
|
|
237
|
+
old_energy = -J * (np.cos(old - top) + np.cos(old - bottom) + np.cos(old - left) + np.cos(old - right))
|
|
238
|
+
new_energy = -J * (np.cos(new - top) + np.cos(new - bottom) + np.cos(new - left) + np.cos(new - right))
|
|
239
|
+
dE = new_energy - old_energy
|
|
240
|
+
if dE <= 0.0 or np.random.random() < np.exp(-beta * dE):
|
|
241
|
+
spin = new % two_pi
|
|
242
|
+
theta[i, j] = spin
|
|
243
|
+
return theta
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@njit(cache=True)
|
|
247
|
+
def ising_total_energy(spins, J):
|
|
248
|
+
"""Total Ising Hamiltonian :math:`E = -J \\sum_{\\langle i,j \\rangle} s_i s_j`.
|
|
249
|
+
|
|
250
|
+
Each bond is counted once (only the right and bottom neighbor of every
|
|
251
|
+
site), giving the physical extensive energy for a periodic :math:`L
|
|
252
|
+
\\times L` lattice.
|
|
253
|
+
"""
|
|
254
|
+
L = spins.shape[0]
|
|
255
|
+
E = 0.0
|
|
256
|
+
for i in range(L):
|
|
257
|
+
for j in range(L):
|
|
258
|
+
s = spins[i, j]
|
|
259
|
+
right = spins[i, (j + 1) % L]
|
|
260
|
+
bottom = spins[(i + 1) % L, j]
|
|
261
|
+
E += -J * s * (right + bottom)
|
|
262
|
+
return E
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@njit(cache=True)
|
|
266
|
+
def ising_total_magnetization(spins):
|
|
267
|
+
"""Total magnetization :math:`M = \\sum_i s_i`."""
|
|
268
|
+
return spins.sum()
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@njit(cache=True)
|
|
272
|
+
def potts_total_energy(spins, J):
|
|
273
|
+
"""Total Potts Hamiltonian :math:`E = -J \\sum_{\\langle i,j \\rangle} \\delta(s_i, s_j)`."""
|
|
274
|
+
L = spins.shape[0]
|
|
275
|
+
E = 0.0
|
|
276
|
+
for i in range(L):
|
|
277
|
+
for j in range(L):
|
|
278
|
+
s = spins[i, j]
|
|
279
|
+
right = spins[i, (j + 1) % L]
|
|
280
|
+
bottom = spins[(i + 1) % L, j]
|
|
281
|
+
E += -J * ((s == right) + (s == bottom))
|
|
282
|
+
return E
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@njit(cache=True)
|
|
286
|
+
def xy_total_energy(theta, J):
|
|
287
|
+
"""Total XY Hamiltonian :math:`E = -J \\sum_{\\langle i,j \\rangle} \\cos(\\theta_i - \\theta_j)`."""
|
|
288
|
+
L = theta.shape[0]
|
|
289
|
+
E = 0.0
|
|
290
|
+
for i in range(L):
|
|
291
|
+
for j in range(L):
|
|
292
|
+
t = theta[i, j]
|
|
293
|
+
right = theta[i, (j + 1) % L]
|
|
294
|
+
bottom = theta[(i + 1) % L, j]
|
|
295
|
+
E += -J * (np.cos(t - right) + np.cos(t - bottom))
|
|
296
|
+
return E
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@njit(cache=True)
|
|
300
|
+
def xy_plaquette_vorticity(theta):
|
|
301
|
+
"""Topological charge of every elementary plaquette of an XY lattice.
|
|
302
|
+
|
|
303
|
+
The vorticity of the plaquette with lower-left corner ``(i, j)`` is
|
|
304
|
+
|
|
305
|
+
.. math::
|
|
306
|
+
|
|
307
|
+
q_{ij} = \\frac{1}{2\\pi} \\oint \\nabla \\theta \\cdot d\\mathbf{l}
|
|
308
|
+
= \\frac{1}{2\\pi} \\sum_{k} \\text{wrap}(\\theta_{k+1} - \\theta_k)
|
|
309
|
+
|
|
310
|
+
summed counter-clockwise around the four bonds of the plaquette, where
|
|
311
|
+
``wrap`` maps angle differences into :math:`(-\\pi, \\pi]`. It is close to
|
|
312
|
+
an integer (:math:`0` in the bulk, :math:`\\pm 1` at a vortex core).
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
theta : ndarray of shape (L, L), dtype float64
|
|
317
|
+
Planar spin angles.
|
|
318
|
+
|
|
319
|
+
Returns
|
|
320
|
+
-------
|
|
321
|
+
ndarray of shape (L, L), dtype float64
|
|
322
|
+
Vorticity charge attached to each plaquette (periodic lattice, so
|
|
323
|
+
every site indexes one plaquette).
|
|
324
|
+
"""
|
|
325
|
+
L = theta.shape[0]
|
|
326
|
+
q = np.zeros((L, L), dtype=np.float64)
|
|
327
|
+
two_pi = 2.0 * np.pi
|
|
328
|
+
for i in range(L):
|
|
329
|
+
for j in range(L):
|
|
330
|
+
t00 = theta[i, j]
|
|
331
|
+
t10 = theta[i, (j + 1) % L]
|
|
332
|
+
t11 = theta[(i + 1) % L, (j + 1) % L]
|
|
333
|
+
t01 = theta[(i + 1) % L, j]
|
|
334
|
+
total = 0.0
|
|
335
|
+
for a, b in ((t00, t10), (t10, t11), (t11, t01), (t01, t00)):
|
|
336
|
+
d = b - a
|
|
337
|
+
d = d - two_pi * np.floor((d + np.pi) / two_pi)
|
|
338
|
+
total += d
|
|
339
|
+
q[i, j] = total / two_pi
|
|
340
|
+
return q
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@njit(cache=True)
|
|
344
|
+
def metropolis_sweep_spin_glass(spins, beta, J_right, J_down):
|
|
345
|
+
"""Perform one Metropolis-Hastings sweep of an Edwards-Anderson Ising spin glass, in place.
|
|
346
|
+
|
|
347
|
+
Unlike :func:`metropolis_sweep_ising`, the bond coupling is a quenched,
|
|
348
|
+
site-dependent random variable rather than a single constant: ``J_right[i,
|
|
349
|
+
j]`` is the coupling between site ``(i, j)`` and its right neighbor
|
|
350
|
+
``(i, j+1)``, and ``J_down[i, j]`` is the coupling between ``(i, j)`` and
|
|
351
|
+
its neighbor below, ``(i+1, j)`` (both periodic). A site's left and top
|
|
352
|
+
bonds are read from its neighbor's ``J_right``/``J_down`` entries.
|
|
353
|
+
|
|
354
|
+
Parameters
|
|
355
|
+
----------
|
|
356
|
+
spins : ndarray of shape (L, L), dtype int64
|
|
357
|
+
Spin configuration with values in ``{-1, +1}``. Modified in place.
|
|
358
|
+
beta : float
|
|
359
|
+
Inverse temperature.
|
|
360
|
+
J_right : ndarray of shape (L, L), dtype float64
|
|
361
|
+
Quenched rightward bond couplings.
|
|
362
|
+
J_down : ndarray of shape (L, L), dtype float64
|
|
363
|
+
Quenched downward bond couplings.
|
|
364
|
+
|
|
365
|
+
Returns
|
|
366
|
+
-------
|
|
367
|
+
ndarray of shape (L, L)
|
|
368
|
+
The same array passed in.
|
|
369
|
+
"""
|
|
370
|
+
L = spins.shape[0]
|
|
371
|
+
n = L * L
|
|
372
|
+
for _ in range(n):
|
|
373
|
+
i = np.random.randint(0, L)
|
|
374
|
+
j = np.random.randint(0, L)
|
|
375
|
+
s = spins[i, j]
|
|
376
|
+
|
|
377
|
+
ip = (i + 1) % L
|
|
378
|
+
im = (i - 1) % L
|
|
379
|
+
jp = (j + 1) % L
|
|
380
|
+
jm = (j - 1) % L
|
|
381
|
+
|
|
382
|
+
dE = 2.0 * s * (J_right[i, j] * spins[i, jp] + J_right[i, jm] * spins[i, jm] + J_down[i, j] * spins[ip, j] + J_down[im, j] * spins[im, j])
|
|
383
|
+
if dE <= 0.0 or np.random.random() < np.exp(-beta * dE):
|
|
384
|
+
spins[i, j] = -s
|
|
385
|
+
return spins
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
@njit(cache=True)
|
|
389
|
+
def spin_glass_total_energy(spins, J_right, J_down):
|
|
390
|
+
"""Total Edwards-Anderson Hamiltonian :math:`E = -\\sum_{\\langle i,j \\rangle} J_{ij} s_i s_j`.
|
|
391
|
+
|
|
392
|
+
Each bond is counted once, using the same ``J_right``/``J_down``
|
|
393
|
+
indexing convention as :func:`metropolis_sweep_spin_glass`.
|
|
394
|
+
"""
|
|
395
|
+
L = spins.shape[0]
|
|
396
|
+
E = 0.0
|
|
397
|
+
for i in range(L):
|
|
398
|
+
for j in range(L):
|
|
399
|
+
s = spins[i, j]
|
|
400
|
+
right = spins[i, (j + 1) % L]
|
|
401
|
+
bottom = spins[(i + 1) % L, j]
|
|
402
|
+
E += -J_right[i, j] * s * right - J_down[i, j] * s * bottom
|
|
403
|
+
return E
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
@njit(cache=True)
|
|
407
|
+
def metropolis_sweep_sk(spins, beta, J):
|
|
408
|
+
"""Perform one Metropolis-Hastings sweep of a fully-connected Sherrington-Kirkpatrick spin glass, in place.
|
|
409
|
+
|
|
410
|
+
Unlike the nearest-neighbor lattice models, every spin couples to every
|
|
411
|
+
other spin: flipping site ``i`` requires the full local field
|
|
412
|
+
:math:`\\sum_k J_{ik} s_k`, an :math:`O(N)` sum, so one sweep of
|
|
413
|
+
:math:`N` attempted flips costs :math:`O(N^2)` -- the price of the
|
|
414
|
+
model's infinite-range connectivity.
|
|
415
|
+
|
|
416
|
+
Parameters
|
|
417
|
+
----------
|
|
418
|
+
spins : ndarray of shape (N,), dtype int64
|
|
419
|
+
Spin configuration with values in ``{-1, +1}``. Modified in place.
|
|
420
|
+
beta : float
|
|
421
|
+
Inverse temperature.
|
|
422
|
+
J : ndarray of shape (N, N), dtype float64
|
|
423
|
+
Quenched, symmetric coupling matrix with zero diagonal.
|
|
424
|
+
|
|
425
|
+
Returns
|
|
426
|
+
-------
|
|
427
|
+
ndarray of shape (N,)
|
|
428
|
+
The same array passed in.
|
|
429
|
+
"""
|
|
430
|
+
N = spins.shape[0]
|
|
431
|
+
for _ in range(N):
|
|
432
|
+
i = np.random.randint(0, N)
|
|
433
|
+
field = 0.0
|
|
434
|
+
for k in range(N):
|
|
435
|
+
field += J[i, k] * spins[k]
|
|
436
|
+
dE = 2.0 * spins[i] * field
|
|
437
|
+
if dE <= 0.0 or np.random.random() < np.exp(-beta * dE):
|
|
438
|
+
spins[i] = -spins[i]
|
|
439
|
+
return spins
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
@njit(cache=True)
|
|
443
|
+
def sk_total_energy(spins, J):
|
|
444
|
+
"""Total Sherrington-Kirkpatrick Hamiltonian :math:`E = -\\sum_{i<j} J_{ij} s_i s_j`.
|
|
445
|
+
|
|
446
|
+
Parameters
|
|
447
|
+
----------
|
|
448
|
+
spins : ndarray of shape (N,), dtype int64
|
|
449
|
+
Spin configuration with values in ``{-1, +1}``.
|
|
450
|
+
J : ndarray of shape (N, N), dtype float64
|
|
451
|
+
Quenched, symmetric coupling matrix with zero diagonal.
|
|
452
|
+
|
|
453
|
+
Returns
|
|
454
|
+
-------
|
|
455
|
+
float
|
|
456
|
+
"""
|
|
457
|
+
N = spins.shape[0]
|
|
458
|
+
total = 0.0
|
|
459
|
+
for i in range(N):
|
|
460
|
+
for k in range(N):
|
|
461
|
+
total += J[i, k] * spins[i] * spins[k]
|
|
462
|
+
return -0.5 * total
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Numba-accelerated random walk trajectory generation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numba import njit
|
|
7
|
+
|
|
8
|
+
__all__ = ["simulate_gaussian_walks", "simulate_lattice_walks"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@njit(cache=True)
|
|
12
|
+
def simulate_lattice_walks(n_walkers, n_steps, dim):
|
|
13
|
+
"""Simulate independent nearest-neighbor random walks on a hypercubic lattice.
|
|
14
|
+
|
|
15
|
+
Each step picks one of the ``dim`` axes uniformly at random and moves
|
|
16
|
+
:math:`\\pm 1` along it.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
n_walkers : int
|
|
21
|
+
Number of independent walkers.
|
|
22
|
+
n_steps : int
|
|
23
|
+
Number of steps per walker.
|
|
24
|
+
dim : int
|
|
25
|
+
Spatial dimension.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
ndarray of shape (n_steps + 1, n_walkers, dim), dtype int64
|
|
30
|
+
Walker positions at every time, starting from the origin at ``t=0``.
|
|
31
|
+
"""
|
|
32
|
+
positions = np.zeros((n_steps + 1, n_walkers, dim), dtype=np.int64)
|
|
33
|
+
for w in range(n_walkers):
|
|
34
|
+
pos = np.zeros(dim, dtype=np.int64)
|
|
35
|
+
for t in range(1, n_steps + 1):
|
|
36
|
+
axis = np.random.randint(0, dim)
|
|
37
|
+
step = 1 if np.random.random() < 0.5 else -1
|
|
38
|
+
pos[axis] += step
|
|
39
|
+
positions[t, w, :] = pos
|
|
40
|
+
return positions
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@njit(cache=True)
|
|
44
|
+
def simulate_gaussian_walks(n_walkers, n_steps, dim, step_std):
|
|
45
|
+
"""Simulate independent continuous Brownian walks with Gaussian steps.
|
|
46
|
+
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
n_walkers : int
|
|
50
|
+
Number of independent walkers.
|
|
51
|
+
n_steps : int
|
|
52
|
+
Number of steps per walker.
|
|
53
|
+
dim : int
|
|
54
|
+
Spatial dimension.
|
|
55
|
+
step_std : float
|
|
56
|
+
Standard deviation of each per-axis Gaussian step.
|
|
57
|
+
|
|
58
|
+
Returns
|
|
59
|
+
-------
|
|
60
|
+
ndarray of shape (n_steps + 1, n_walkers, dim), dtype float64
|
|
61
|
+
Walker positions at every time, starting from the origin at ``t=0``.
|
|
62
|
+
"""
|
|
63
|
+
positions = np.zeros((n_steps + 1, n_walkers, dim), dtype=np.float64)
|
|
64
|
+
for w in range(n_walkers):
|
|
65
|
+
for t in range(1, n_steps + 1):
|
|
66
|
+
for d in range(dim):
|
|
67
|
+
positions[t, w, d] = positions[t - 1, w, d] + np.random.normal(0.0, step_std)
|
|
68
|
+
return positions
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Numba-accelerated toppling dynamics for the Bak-Tang-Wiesenfeld sandpile."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from numba import njit
|
|
6
|
+
|
|
7
|
+
__all__ = ["topple_to_stability"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@njit(cache=True)
|
|
11
|
+
def topple_to_stability(heights, threshold=4):
|
|
12
|
+
"""Relax a sandpile height grid to stability by repeated toppling, in place.
|
|
13
|
+
|
|
14
|
+
Open boundary conditions: grains toppled off the edge are lost from the
|
|
15
|
+
system. A site with height >= ``threshold`` topples, losing
|
|
16
|
+
``threshold`` grains and giving one grain to each of its (up to four)
|
|
17
|
+
orthogonal neighbors.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
heights : ndarray of shape (L, L), dtype int64
|
|
22
|
+
Grid of pile heights. Modified in place.
|
|
23
|
+
threshold : int, default=4
|
|
24
|
+
Critical height at which a site topples (4 is the standard BTW
|
|
25
|
+
value on the square lattice, one grain per neighbor direction).
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
int
|
|
30
|
+
Total number of individual topplings that occurred during this
|
|
31
|
+
relaxation (the avalanche size).
|
|
32
|
+
"""
|
|
33
|
+
L0, L1 = heights.shape
|
|
34
|
+
n_topplings = 0
|
|
35
|
+
unstable = True
|
|
36
|
+
while unstable:
|
|
37
|
+
unstable = False
|
|
38
|
+
for i in range(L0):
|
|
39
|
+
for j in range(L1):
|
|
40
|
+
if heights[i, j] >= threshold:
|
|
41
|
+
unstable = True
|
|
42
|
+
heights[i, j] -= threshold
|
|
43
|
+
n_topplings += 1
|
|
44
|
+
if i > 0:
|
|
45
|
+
heights[i - 1, j] += 1
|
|
46
|
+
if i < L0 - 1:
|
|
47
|
+
heights[i + 1, j] += 1
|
|
48
|
+
if j > 0:
|
|
49
|
+
heights[i, j - 1] += 1
|
|
50
|
+
if j < L1 - 1:
|
|
51
|
+
heights[i, j + 1] += 1
|
|
52
|
+
return n_topplings
|
|
File without changes
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from physicskit.statphys.utils.dynamics import autocorrelation_function, integrated_autocorrelation_time
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_autocorrelation_function_zero_lag_is_one():
|
|
8
|
+
rng = np.random.default_rng(0)
|
|
9
|
+
x = rng.normal(size=2000)
|
|
10
|
+
rho = autocorrelation_function(x)
|
|
11
|
+
assert rho[0] == pytest.approx(1.0)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_autocorrelation_decays_for_white_noise():
|
|
15
|
+
rng = np.random.default_rng(1)
|
|
16
|
+
x = rng.normal(size=5000)
|
|
17
|
+
rho = autocorrelation_function(x, max_lag=50)
|
|
18
|
+
assert abs(rho[20]) < 0.2
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_autocorrelation_function_high_for_slow_series():
|
|
22
|
+
rng = np.random.default_rng(2)
|
|
23
|
+
# a slowly varying (highly autocorrelated) random walk
|
|
24
|
+
x = np.cumsum(rng.normal(size=2000))
|
|
25
|
+
rho = autocorrelation_function(x, max_lag=10)
|
|
26
|
+
assert rho[5] > 0.5
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_integrated_autocorrelation_time_small_for_independent_samples():
|
|
30
|
+
rng = np.random.default_rng(3)
|
|
31
|
+
x = rng.normal(size=5000)
|
|
32
|
+
tau = integrated_autocorrelation_time(x)
|
|
33
|
+
assert 0.0 < tau < 3.0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_integrated_autocorrelation_time_larger_for_correlated_series():
|
|
37
|
+
rng = np.random.default_rng(4)
|
|
38
|
+
n = 5000
|
|
39
|
+
# AR(1) process with strong positive autocorrelation
|
|
40
|
+
x = np.empty(n)
|
|
41
|
+
x[0] = rng.normal()
|
|
42
|
+
phi = 0.9
|
|
43
|
+
for i in range(1, n):
|
|
44
|
+
x[i] = phi * x[i - 1] + rng.normal()
|
|
45
|
+
|
|
46
|
+
tau_correlated = integrated_autocorrelation_time(x)
|
|
47
|
+
tau_independent = integrated_autocorrelation_time(rng.normal(size=n))
|
|
48
|
+
assert tau_correlated > tau_independent
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_integrated_autocorrelation_time_falls_back_when_window_never_closes():
|
|
52
|
+
# A strongly autocorrelated AR(1) series (tau grows large), restricted
|
|
53
|
+
# to a small max_lag: the automatic-windowing condition c*tau <= M is
|
|
54
|
+
# never satisfied within that short lag range, so the function should
|
|
55
|
+
# fall back to the full-sum estimate instead of raising or looping
|
|
56
|
+
# forever.
|
|
57
|
+
rng = np.random.default_rng(4)
|
|
58
|
+
n = 5000
|
|
59
|
+
x = np.empty(n)
|
|
60
|
+
x[0] = rng.normal()
|
|
61
|
+
phi = 0.95
|
|
62
|
+
for i in range(1, n):
|
|
63
|
+
x[i] = phi * x[i - 1] + rng.normal()
|
|
64
|
+
|
|
65
|
+
tau = integrated_autocorrelation_time(x, max_lag=3)
|
|
66
|
+
assert tau > 0.0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from physicskit.statphys.chapters.ehrenfest_urn import EhrenfestUrn
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_default_starts_full():
|
|
5
|
+
urn = EhrenfestUrn(n_balls=50, seed=0)
|
|
6
|
+
assert urn.n_left == 50
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_step_changes_n_left_by_one():
|
|
10
|
+
urn = EhrenfestUrn(n_balls=50, seed=1)
|
|
11
|
+
before = urn.n_left
|
|
12
|
+
after = urn.step()
|
|
13
|
+
assert abs(after - before) == 1
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_n_left_bounded():
|
|
17
|
+
urn = EhrenfestUrn(n_balls=30, seed=2)
|
|
18
|
+
for _ in range(500):
|
|
19
|
+
urn.step()
|
|
20
|
+
assert 0 <= urn.n_left <= 30
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_entropy_maximal_at_half_full():
|
|
24
|
+
urn = EhrenfestUrn(n_balls=40, n_left_init=20, seed=3)
|
|
25
|
+
S_half = urn.entropy()
|
|
26
|
+
urn2 = EhrenfestUrn(n_balls=40, n_left_init=40, seed=3)
|
|
27
|
+
S_full = urn2.entropy()
|
|
28
|
+
assert S_half > S_full
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_relaxation_toward_equilibrium():
|
|
32
|
+
urn = EhrenfestUrn(n_balls=200, seed=4)
|
|
33
|
+
history = urn.run(3000)
|
|
34
|
+
early = history["n_left"][:50].mean()
|
|
35
|
+
late = history["n_left"][-500:].mean()
|
|
36
|
+
assert abs(late - 100) < abs(early - 100)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_run_history_shapes():
|
|
40
|
+
urn = EhrenfestUrn(n_balls=50, seed=5)
|
|
41
|
+
history = urn.run(100)
|
|
42
|
+
assert history["n_left"].shape == (101,)
|
|
43
|
+
assert history["entropy"].shape == (101,)
|
|
44
|
+
assert history["n_left"][0] == 50
|