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,594 @@
|
|
|
1
|
+
r"""Feynman path integrals and their reduction to classical mechanics as :math:`\hbar\to 0`.
|
|
2
|
+
|
|
3
|
+
Dirac's 1933 paper "The Lagrangian in Quantum Mechanics" observed that the
|
|
4
|
+
quantum propagator ought to be built from :math:`\exp(iS/\hbar)`, one
|
|
5
|
+
factor per infinitesimal time step; Feynman (1948), and later Feynman &
|
|
6
|
+
Hibbs (1965) in their textbook *Quantum Mechanics and Path Integrals*,
|
|
7
|
+
turned that observation into a full reformulation of quantum mechanics:
|
|
8
|
+
the amplitude to go from :math:`(x_0,0)` to :math:`(x_f,T)` is a sum over
|
|
9
|
+
*every* continuous path :math:`x(t)` connecting the two endpoints, each
|
|
10
|
+
weighted by a phase built from the classical action functional
|
|
11
|
+
:math:`S[x(t)]=\int_0^T L(x,\dot x)\,dt` of that path,
|
|
12
|
+
|
|
13
|
+
.. math::
|
|
14
|
+
|
|
15
|
+
K(x_f,T;x_0,0) = \int \mathcal{D}[x(t)]\;
|
|
16
|
+
\exp\!\left(\frac{i}{\hbar}S[x(t)]\right).
|
|
17
|
+
|
|
18
|
+
This module implements that sum directly, by Monte Carlo sampling a large
|
|
19
|
+
ensemble of candidate paths and adding up their phasors
|
|
20
|
+
:math:`\exp(iS/\hbar)` one at a time, ordered from the path closest to the
|
|
21
|
+
true classical (stationary-action) trajectory outward. Two systems are
|
|
22
|
+
exactly solvable end to end here -- the free particle
|
|
23
|
+
(:func:`free_particle_classical_path`,
|
|
24
|
+
:func:`free_particle_classical_action`) and the harmonic oscillator
|
|
25
|
+
(:func:`harmonic_oscillator_classical_path`,
|
|
26
|
+
:func:`harmonic_oscillator_classical_action`) -- so every piece of the
|
|
27
|
+
machinery can be checked against a closed form.
|
|
28
|
+
|
|
29
|
+
The physical content is the emergence of the principle of stationary
|
|
30
|
+
action itself. Near the classical path, :math:`S` is stationary
|
|
31
|
+
(:math:`\delta S=0` to first order in the deformation), so nearby paths
|
|
32
|
+
all have nearly the same action and their phasors stay nearly aligned:
|
|
33
|
+
they interfere constructively. Far from the classical path, :math:`S`
|
|
34
|
+
varies rapidly from one path to a neighboring one, so
|
|
35
|
+
:math:`\exp(iS/\hbar)` spins rapidly through many full turns as the path
|
|
36
|
+
is varied, and the contributions of an ensemble of such paths cancel
|
|
37
|
+
almost completely by destructive interference (this is Feynman's own
|
|
38
|
+
"arrow and stopwatch" picture, reproduced here as the phasor spiral built
|
|
39
|
+
by :func:`feynman_phasor_partial_sums`). Shrinking :math:`\hbar` makes the
|
|
40
|
+
phase :math:`S/\hbar` more sensitive to path deformations, so the
|
|
41
|
+
"nearly aligned" neighborhood of the classical path shrinks -- in the
|
|
42
|
+
:math:`\hbar\to 0` limit only the classical path itself survives, and
|
|
43
|
+
quantum mechanics' sum over histories reduces exactly to the classical
|
|
44
|
+
principle of stationary (least) action, :math:`\delta S=0`.
|
|
45
|
+
|
|
46
|
+
Paths here are represented by their positions at :math:`N+1` uniformly
|
|
47
|
+
spaced times over :math:`[0,T]` (:math:`N` time slices,
|
|
48
|
+
:math:`\mathrm{d}t=T/N`), and the action of a discretized path is
|
|
49
|
+
computed with the standard midpoint-rule time slicing,
|
|
50
|
+
|
|
51
|
+
.. math::
|
|
52
|
+
|
|
53
|
+
S[x] \approx \sum_{i=0}^{N-1}\left[\frac{1}{2}m
|
|
54
|
+
\left(\frac{x_{i+1}-x_i}{\mathrm{d}t}\right)^2
|
|
55
|
+
- V\!\left(\frac{x_i+x_{i+1}}{2}\right)\right]\mathrm{d}t
|
|
56
|
+
\;\xrightarrow[N\to\infty]{}\; \int_0^T\!\left[\frac{1}{2}m\dot x^2
|
|
57
|
+
- V(x)\right]dt.
|
|
58
|
+
|
|
59
|
+
References
|
|
60
|
+
----------
|
|
61
|
+
P. A. M. Dirac, "The Lagrangian in Quantum Mechanics," Physikalische
|
|
62
|
+
Zeitschrift der Sowjetunion 3, 64-72 (1933).
|
|
63
|
+
|
|
64
|
+
R. P. Feynman and A. R. Hibbs, *Quantum Mechanics and Path Integrals*,
|
|
65
|
+
McGraw-Hill (1965).
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
from __future__ import annotations
|
|
69
|
+
|
|
70
|
+
from collections.abc import Callable
|
|
71
|
+
|
|
72
|
+
import numpy as np
|
|
73
|
+
|
|
74
|
+
__all__ = [
|
|
75
|
+
"free_particle_classical_path",
|
|
76
|
+
"free_particle_classical_action",
|
|
77
|
+
"harmonic_oscillator_classical_path",
|
|
78
|
+
"harmonic_oscillator_classical_action",
|
|
79
|
+
"discretized_action",
|
|
80
|
+
"sample_random_paths",
|
|
81
|
+
"feynman_phasor_partial_sums",
|
|
82
|
+
"build_phasor_diagram",
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _check_not_conjugate(omega: float, T: float) -> None:
|
|
87
|
+
if np.isclose(np.sin(omega * T), 0.0, atol=1e-9):
|
|
88
|
+
raise ValueError(
|
|
89
|
+
f"omega*T = {omega * T:.6g} is a multiple of pi: the two endpoints are "
|
|
90
|
+
"conjugate points of the harmonic oscillator, where the classical path "
|
|
91
|
+
"connecting them is non-unique (or does not exist). Choose a T not equal "
|
|
92
|
+
"to n*pi/omega for integer n."
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def free_particle_classical_path(x0: float, xf: float, T: float, m: float, n_slices: int):
|
|
97
|
+
r"""Exact classical trajectory of a free particle between fixed endpoints.
|
|
98
|
+
|
|
99
|
+
With :math:`V=0` the Euler-Lagrange equation :math:`\ddot x=0` has the
|
|
100
|
+
unique solution connecting :math:`(x_0,0)` and :math:`(x_f,T)`: the
|
|
101
|
+
straight line :math:`x_{\rm cl}(t) = x_0 + (x_f-x_0)\,t/T`.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
x0 : float
|
|
106
|
+
Initial position, at :math:`t=0`.
|
|
107
|
+
xf : float
|
|
108
|
+
Final position, at :math:`t=T`.
|
|
109
|
+
T : float
|
|
110
|
+
Total elapsed time (must be positive).
|
|
111
|
+
m : float
|
|
112
|
+
Particle mass (unused for the free-particle trajectory itself,
|
|
113
|
+
kept for signature symmetry with :func:`discretized_action` and
|
|
114
|
+
the harmonic-oscillator counterpart).
|
|
115
|
+
n_slices : int
|
|
116
|
+
Number of time slices :math:`N`; the returned arrays have
|
|
117
|
+
:math:`N+1` points.
|
|
118
|
+
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
t_array : ndarray, shape (n_slices + 1,)
|
|
122
|
+
Uniformly spaced times over :math:`[0,T]`.
|
|
123
|
+
x_array : ndarray, shape (n_slices + 1,)
|
|
124
|
+
Classical trajectory :math:`x_{\rm cl}(t)`.
|
|
125
|
+
|
|
126
|
+
Raises
|
|
127
|
+
------
|
|
128
|
+
ValueError
|
|
129
|
+
If ``T <= 0`` or ``n_slices < 1``.
|
|
130
|
+
|
|
131
|
+
Examples
|
|
132
|
+
--------
|
|
133
|
+
>>> t, x = free_particle_classical_path(x0=0.0, xf=2.0, T=1.0, m=1.0, n_slices=4)
|
|
134
|
+
>>> x
|
|
135
|
+
array([0. , 0.5, 1. , 1.5, 2. ])
|
|
136
|
+
"""
|
|
137
|
+
if T <= 0:
|
|
138
|
+
raise ValueError(f"T must be positive, got {T}.")
|
|
139
|
+
if n_slices < 1:
|
|
140
|
+
raise ValueError(f"n_slices must be >= 1, got {n_slices}.")
|
|
141
|
+
t_array = np.linspace(0.0, T, n_slices + 1)
|
|
142
|
+
x_array = x0 + (xf - x0) * t_array / T
|
|
143
|
+
return t_array, x_array
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def free_particle_classical_action(x0: float, xf: float, T: float, m: float) -> float:
|
|
147
|
+
r"""Exact classical (Hamilton's principal function) action of a free particle.
|
|
148
|
+
|
|
149
|
+
.. math::
|
|
150
|
+
|
|
151
|
+
S_{\rm cl} = \frac{m(x_f-x_0)^2}{2T}.
|
|
152
|
+
|
|
153
|
+
Parameters
|
|
154
|
+
----------
|
|
155
|
+
x0, xf : float
|
|
156
|
+
Initial and final positions.
|
|
157
|
+
T : float
|
|
158
|
+
Total elapsed time (must be positive).
|
|
159
|
+
m : float
|
|
160
|
+
Particle mass.
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
float
|
|
165
|
+
The classical action :math:`S_{\rm cl}`.
|
|
166
|
+
|
|
167
|
+
Raises
|
|
168
|
+
------
|
|
169
|
+
ValueError
|
|
170
|
+
If ``T <= 0``.
|
|
171
|
+
|
|
172
|
+
Examples
|
|
173
|
+
--------
|
|
174
|
+
>>> free_particle_classical_action(x0=0.0, xf=2.0, T=1.0, m=1.0)
|
|
175
|
+
2.0
|
|
176
|
+
"""
|
|
177
|
+
if T <= 0:
|
|
178
|
+
raise ValueError(f"T must be positive, got {T}.")
|
|
179
|
+
return m * (xf - x0) ** 2 / (2.0 * T)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def harmonic_oscillator_classical_path(x0: float, xf: float, T: float, m: float, omega: float, n_slices: int):
|
|
183
|
+
r"""Exact classical trajectory of a harmonic oscillator between fixed endpoints.
|
|
184
|
+
|
|
185
|
+
The Euler-Lagrange equation :math:`\ddot x = -\omega^2 x` has the
|
|
186
|
+
unique solution matching both endpoints
|
|
187
|
+
|
|
188
|
+
.. math::
|
|
189
|
+
|
|
190
|
+
x_{\rm cl}(t) = \frac{x_0\sin(\omega(T-t)) + x_f\sin(\omega t)}
|
|
191
|
+
{\sin(\omega T)},
|
|
192
|
+
|
|
193
|
+
valid as long as :math:`\sin(\omega T)\neq 0`; at a *conjugate point*
|
|
194
|
+
(:math:`\omega T` an integer multiple of :math:`\pi`) every path
|
|
195
|
+
through both endpoints has the same action to first order and the
|
|
196
|
+
classical path is not unique, so this raises instead of silently
|
|
197
|
+
dividing by zero.
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
x0, xf : float
|
|
202
|
+
Initial and final positions.
|
|
203
|
+
T : float
|
|
204
|
+
Total elapsed time (must be positive).
|
|
205
|
+
m : float
|
|
206
|
+
Particle mass (unused for the trajectory itself, kept for
|
|
207
|
+
signature symmetry with :func:`harmonic_oscillator_classical_action`).
|
|
208
|
+
omega : float
|
|
209
|
+
Angular frequency of the oscillator.
|
|
210
|
+
n_slices : int
|
|
211
|
+
Number of time slices :math:`N`; the returned arrays have
|
|
212
|
+
:math:`N+1` points.
|
|
213
|
+
|
|
214
|
+
Returns
|
|
215
|
+
-------
|
|
216
|
+
t_array : ndarray, shape (n_slices + 1,)
|
|
217
|
+
Uniformly spaced times over :math:`[0,T]`.
|
|
218
|
+
x_array : ndarray, shape (n_slices + 1,)
|
|
219
|
+
Classical trajectory :math:`x_{\rm cl}(t)`.
|
|
220
|
+
|
|
221
|
+
Raises
|
|
222
|
+
------
|
|
223
|
+
ValueError
|
|
224
|
+
If ``T <= 0``, ``n_slices < 1``, or ``omega*T`` is (numerically) a
|
|
225
|
+
multiple of :math:`\pi` (a conjugate point).
|
|
226
|
+
|
|
227
|
+
Examples
|
|
228
|
+
--------
|
|
229
|
+
>>> t, x = harmonic_oscillator_classical_path(x0=0.0, xf=1.0, T=1.0, m=1.0, omega=1.0, n_slices=4)
|
|
230
|
+
>>> bool(np.isclose(x[0], 0.0)) and bool(np.isclose(x[-1], 1.0))
|
|
231
|
+
True
|
|
232
|
+
"""
|
|
233
|
+
if T <= 0:
|
|
234
|
+
raise ValueError(f"T must be positive, got {T}.")
|
|
235
|
+
if n_slices < 1:
|
|
236
|
+
raise ValueError(f"n_slices must be >= 1, got {n_slices}.")
|
|
237
|
+
_check_not_conjugate(omega, T)
|
|
238
|
+
t_array = np.linspace(0.0, T, n_slices + 1)
|
|
239
|
+
x_array = (x0 * np.sin(omega * (T - t_array)) + xf * np.sin(omega * t_array)) / np.sin(omega * T)
|
|
240
|
+
return t_array, x_array
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def harmonic_oscillator_classical_action(x0: float, xf: float, T: float, m: float, omega: float) -> float:
|
|
244
|
+
r"""Exact classical (Hamilton's principal function) action of a harmonic oscillator.
|
|
245
|
+
|
|
246
|
+
.. math::
|
|
247
|
+
|
|
248
|
+
S_{\rm cl} = \frac{m\omega}{2\sin(\omega T)}
|
|
249
|
+
\left[(x_0^2+x_f^2)\cos(\omega T) - 2x_0 x_f\right].
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
x0, xf : float
|
|
254
|
+
Initial and final positions.
|
|
255
|
+
T : float
|
|
256
|
+
Total elapsed time (must be positive).
|
|
257
|
+
m : float
|
|
258
|
+
Particle mass.
|
|
259
|
+
omega : float
|
|
260
|
+
Angular frequency of the oscillator.
|
|
261
|
+
|
|
262
|
+
Returns
|
|
263
|
+
-------
|
|
264
|
+
float
|
|
265
|
+
The classical action :math:`S_{\rm cl}`.
|
|
266
|
+
|
|
267
|
+
Raises
|
|
268
|
+
------
|
|
269
|
+
ValueError
|
|
270
|
+
If ``T <= 0`` or ``omega*T`` is (numerically) a multiple of
|
|
271
|
+
:math:`\pi` (a conjugate point; see
|
|
272
|
+
:func:`harmonic_oscillator_classical_path`).
|
|
273
|
+
|
|
274
|
+
Examples
|
|
275
|
+
--------
|
|
276
|
+
>>> round(harmonic_oscillator_classical_action(x0=0.0, xf=0.0, T=1.0, m=1.0, omega=0.5), 6)
|
|
277
|
+
0.0
|
|
278
|
+
"""
|
|
279
|
+
if T <= 0:
|
|
280
|
+
raise ValueError(f"T must be positive, got {T}.")
|
|
281
|
+
_check_not_conjugate(omega, T)
|
|
282
|
+
return float((m * omega / (2.0 * np.sin(omega * T))) * ((x0**2 + xf**2) * np.cos(omega * T) - 2.0 * x0 * xf))
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def discretized_action(x_array: np.ndarray, dt: float, m: float, V: Callable[[np.ndarray], np.ndarray]) -> float:
|
|
286
|
+
r"""Midpoint-rule discretized action of a single time-sliced path.
|
|
287
|
+
|
|
288
|
+
.. math::
|
|
289
|
+
|
|
290
|
+
S[x] = \sum_{i=0}^{N-1}\left[\frac{1}{2}m
|
|
291
|
+
\left(\frac{x_{i+1}-x_i}{\mathrm{d}t}\right)^2
|
|
292
|
+
- V\!\left(\frac{x_i+x_{i+1}}{2}\right)\right]\mathrm{d}t.
|
|
293
|
+
|
|
294
|
+
Parameters
|
|
295
|
+
----------
|
|
296
|
+
x_array : ndarray, shape (N + 1,)
|
|
297
|
+
Path positions :math:`x_0,\dots,x_N` at :math:`N+1` uniformly
|
|
298
|
+
spaced times.
|
|
299
|
+
dt : float
|
|
300
|
+
Time-slice width.
|
|
301
|
+
m : float
|
|
302
|
+
Particle mass.
|
|
303
|
+
V : callable
|
|
304
|
+
Potential energy function ``V(x) -> array_like``, evaluated at
|
|
305
|
+
the midpoint of each slice; must accept a NumPy array.
|
|
306
|
+
|
|
307
|
+
Returns
|
|
308
|
+
-------
|
|
309
|
+
float
|
|
310
|
+
The discretized action :math:`S[x]`.
|
|
311
|
+
|
|
312
|
+
Examples
|
|
313
|
+
--------
|
|
314
|
+
>>> import numpy as np
|
|
315
|
+
>>> x = np.array([0.0, 0.5, 1.0, 1.5, 2.0])
|
|
316
|
+
>>> V = lambda x: 0.0 * x
|
|
317
|
+
>>> round(discretized_action(x, dt=0.25, m=1.0, V=V), 6)
|
|
318
|
+
2.0
|
|
319
|
+
"""
|
|
320
|
+
x_array = np.asarray(x_array, dtype=float)
|
|
321
|
+
x_i = x_array[:-1]
|
|
322
|
+
x_ip1 = x_array[1:]
|
|
323
|
+
kinetic = 0.5 * m * ((x_ip1 - x_i) / dt) ** 2
|
|
324
|
+
potential = V(0.5 * (x_i + x_ip1))
|
|
325
|
+
return float(np.sum((kinetic - potential) * dt))
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def sample_random_paths(
|
|
329
|
+
x0: float,
|
|
330
|
+
xf: float,
|
|
331
|
+
T: float,
|
|
332
|
+
n_slices: int,
|
|
333
|
+
n_paths: int,
|
|
334
|
+
sigma: float,
|
|
335
|
+
n_modes: int = 8,
|
|
336
|
+
seed: int | None = None,
|
|
337
|
+
) -> np.ndarray:
|
|
338
|
+
r"""Sample random paths between fixed endpoints as sine-series Brownian bridges.
|
|
339
|
+
|
|
340
|
+
Each path is the straight-line interpolation between the endpoints
|
|
341
|
+
plus a random wiggle built from a discrete sine series,
|
|
342
|
+
|
|
343
|
+
.. math::
|
|
344
|
+
|
|
345
|
+
x_i = x_0 + (x_f-x_0)\frac{i}{N} + \sigma\sum_{k=1}^{K}
|
|
346
|
+
\frac{a_k}{k}\sin\!\left(\frac{k\pi i}{N}\right),
|
|
347
|
+
\qquad a_k\sim\mathcal{N}(0,1)\ \text{i.i.d. per path},
|
|
348
|
+
|
|
349
|
+
where :math:`N` is ``n_slices`` and :math:`K` is ``n_modes``. Every
|
|
350
|
+
term of the sine series vanishes at :math:`i=0` and :math:`i=N`
|
|
351
|
+
identically, so every sampled path exactly satisfies the fixed
|
|
352
|
+
endpoint conditions :math:`x_0` and :math:`x_f` regardless of the
|
|
353
|
+
random coefficients drawn -- this is what makes it a valid "Brownian
|
|
354
|
+
bridge" construction. Paths are built around the straight line (not
|
|
355
|
+
around any particular classical trajectory), so the ensemble
|
|
356
|
+
generically explores the space of continuous paths between the
|
|
357
|
+
endpoints, and any special concentration of the phasor sum near the
|
|
358
|
+
true classical path is a genuine result rather than built in by
|
|
359
|
+
construction.
|
|
360
|
+
|
|
361
|
+
Parameters
|
|
362
|
+
----------
|
|
363
|
+
x0, xf : float
|
|
364
|
+
Fixed initial and final positions shared by every sampled path.
|
|
365
|
+
T : float
|
|
366
|
+
Total elapsed time (must be positive).
|
|
367
|
+
n_slices : int
|
|
368
|
+
Number of time slices :math:`N`; each path has :math:`N+1` points.
|
|
369
|
+
n_paths : int
|
|
370
|
+
Number of random paths to draw.
|
|
371
|
+
sigma : float
|
|
372
|
+
Overall amplitude of the random wiggle.
|
|
373
|
+
n_modes : int, default=8
|
|
374
|
+
Number of sine modes :math:`K` used to build each path's wiggle;
|
|
375
|
+
higher modes are automatically suppressed by the :math:`1/k`
|
|
376
|
+
weighting, so this mainly controls the finest wiggle scale
|
|
377
|
+
resolved.
|
|
378
|
+
seed : int or None, optional
|
|
379
|
+
Seed for the random number generator, for reproducibility.
|
|
380
|
+
|
|
381
|
+
Returns
|
|
382
|
+
-------
|
|
383
|
+
ndarray, shape (n_paths, n_slices + 1)
|
|
384
|
+
Sampled paths, each row a full path :math:`x_0,\dots,x_N`.
|
|
385
|
+
|
|
386
|
+
Examples
|
|
387
|
+
--------
|
|
388
|
+
>>> paths = sample_random_paths(x0=0.0, xf=1.0, T=1.0, n_slices=10, n_paths=5, sigma=0.3, seed=0)
|
|
389
|
+
>>> paths.shape
|
|
390
|
+
(5, 11)
|
|
391
|
+
>>> bool(np.allclose(paths[:, 0], 0.0)) and bool(np.allclose(paths[:, -1], 1.0))
|
|
392
|
+
True
|
|
393
|
+
"""
|
|
394
|
+
if T <= 0:
|
|
395
|
+
raise ValueError(f"T must be positive, got {T}.")
|
|
396
|
+
if n_slices < 1:
|
|
397
|
+
raise ValueError(f"n_slices must be >= 1, got {n_slices}.")
|
|
398
|
+
if n_paths < 1:
|
|
399
|
+
raise ValueError(f"n_paths must be >= 1, got {n_paths}.")
|
|
400
|
+
|
|
401
|
+
rng = np.random.default_rng(seed)
|
|
402
|
+
N = n_slices
|
|
403
|
+
i = np.arange(N + 1, dtype=float)
|
|
404
|
+
straight = x0 + (xf - x0) * i / N
|
|
405
|
+
|
|
406
|
+
k = np.arange(1, n_modes + 1, dtype=float)
|
|
407
|
+
sin_matrix = np.sin(np.outer(k, np.pi * i / N)) # shape (n_modes, N+1)
|
|
408
|
+
|
|
409
|
+
a = rng.standard_normal((n_paths, n_modes)) / k[None, :]
|
|
410
|
+
noise = sigma * (a @ sin_matrix) # shape (n_paths, N+1)
|
|
411
|
+
|
|
412
|
+
return straight[None, :] + noise
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def feynman_phasor_partial_sums(
|
|
416
|
+
paths: np.ndarray,
|
|
417
|
+
actions: np.ndarray,
|
|
418
|
+
hbar: float,
|
|
419
|
+
classical_action: float | None = None,
|
|
420
|
+
) -> np.ndarray:
|
|
421
|
+
r"""Feynman's phasor ("arrow and stopwatch") partial sums, ordered closest-to-classical first.
|
|
422
|
+
|
|
423
|
+
Sorts the given ensemble of paths by :math:`|S-S_{\rm cl}|` (ascending)
|
|
424
|
+
and accumulates the running sum of unit phasors
|
|
425
|
+
:math:`\exp(iS/\hbar)`, one path at a time, in that order. Because
|
|
426
|
+
:math:`S` is stationary at the classical path, paths near it have
|
|
427
|
+
nearly equal action and their phasors reinforce (the sum's magnitude
|
|
428
|
+
grows quickly at first); paths far from it have rapidly varying
|
|
429
|
+
action and their phasors point in essentially random directions, so
|
|
430
|
+
later additions contribute a slowly-converging random walk instead
|
|
431
|
+
of steady growth. This is exactly the data behind Feynman's
|
|
432
|
+
arrow-and-stopwatch phasor-spiral diagram.
|
|
433
|
+
|
|
434
|
+
Parameters
|
|
435
|
+
----------
|
|
436
|
+
paths : ndarray, shape (n_paths, n_points)
|
|
437
|
+
Ensemble of paths (only used to determine ``n_paths``; the
|
|
438
|
+
ordering and summation depend only on ``actions``).
|
|
439
|
+
actions : ndarray, shape (n_paths,)
|
|
440
|
+
Discretized action of each path, e.g. from :func:`discretized_action`.
|
|
441
|
+
hbar : float
|
|
442
|
+
Reduced Planck constant (or an effective value thereof); must be
|
|
443
|
+
nonzero.
|
|
444
|
+
classical_action : float or None, optional
|
|
445
|
+
Reference action :math:`S_{\rm cl}` used to sort paths by
|
|
446
|
+
proximity. If None, the minimum action found in ``actions`` is
|
|
447
|
+
used instead.
|
|
448
|
+
|
|
449
|
+
Returns
|
|
450
|
+
-------
|
|
451
|
+
ndarray of complex, shape (n_paths + 1,)
|
|
452
|
+
Partial sums :math:`\sum_{j\le n}\exp(iS_j/\hbar)`, starting from
|
|
453
|
+
0 (index 0) up to the full sum over all paths (index ``n_paths``),
|
|
454
|
+
accumulated in closest-to-classical-first order.
|
|
455
|
+
|
|
456
|
+
Raises
|
|
457
|
+
------
|
|
458
|
+
ValueError
|
|
459
|
+
If ``hbar == 0`` or ``actions`` is empty.
|
|
460
|
+
|
|
461
|
+
Examples
|
|
462
|
+
--------
|
|
463
|
+
>>> import numpy as np
|
|
464
|
+
>>> actions = np.array([0.0, 0.1, -3.0])
|
|
465
|
+
>>> paths = np.zeros((3, 2))
|
|
466
|
+
>>> partial = feynman_phasor_partial_sums(paths, actions, hbar=1.0, classical_action=0.0)
|
|
467
|
+
>>> partial.shape
|
|
468
|
+
(4,)
|
|
469
|
+
>>> bool(np.isclose(partial[0], 0.0))
|
|
470
|
+
True
|
|
471
|
+
>>> bool(np.isclose(partial[-1], np.sum(np.exp(1j * actions))))
|
|
472
|
+
True
|
|
473
|
+
"""
|
|
474
|
+
actions = np.asarray(actions, dtype=float)
|
|
475
|
+
if actions.size == 0:
|
|
476
|
+
raise ValueError("actions must be non-empty.")
|
|
477
|
+
if hbar == 0:
|
|
478
|
+
raise ValueError("hbar must be nonzero.")
|
|
479
|
+
|
|
480
|
+
reference = float(np.min(actions)) if classical_action is None else float(classical_action)
|
|
481
|
+
order = np.argsort(np.abs(actions - reference))
|
|
482
|
+
terms = np.exp(1j * actions[order] / hbar)
|
|
483
|
+
cumulative = np.cumsum(terms)
|
|
484
|
+
return np.concatenate([[0.0 + 0.0j], cumulative])
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
def build_phasor_diagram(
|
|
488
|
+
x0: float,
|
|
489
|
+
xf: float,
|
|
490
|
+
T: float,
|
|
491
|
+
m: float,
|
|
492
|
+
hbar: float,
|
|
493
|
+
potential: str = "free",
|
|
494
|
+
omega: float | None = None,
|
|
495
|
+
n_slices: int = 60,
|
|
496
|
+
n_paths: int = 400,
|
|
497
|
+
sigma: float = 0.5,
|
|
498
|
+
seed: int | None = None,
|
|
499
|
+
):
|
|
500
|
+
r"""Build a complete Feynman phasor-spiral dataset for the free particle or harmonic oscillator.
|
|
501
|
+
|
|
502
|
+
Ties together the classical trajectory/action, a random ensemble of
|
|
503
|
+
candidate paths (:func:`sample_random_paths`), their discretized
|
|
504
|
+
actions (:func:`discretized_action`), and the resulting phasor
|
|
505
|
+
partial sums (:func:`feynman_phasor_partial_sums`) -- everything
|
|
506
|
+
:func:`~physicskit.semiclassical.visualizers.path_integral.animate_feynman_phasor_spiral`
|
|
507
|
+
needs to draw. The exact classical path is explicitly included as one
|
|
508
|
+
member of the returned ensemble, since it is the single most
|
|
509
|
+
important path in the whole construction.
|
|
510
|
+
|
|
511
|
+
Parameters
|
|
512
|
+
----------
|
|
513
|
+
x0, xf : float
|
|
514
|
+
Fixed initial and final positions.
|
|
515
|
+
T : float
|
|
516
|
+
Total elapsed time (must be positive).
|
|
517
|
+
m : float
|
|
518
|
+
Particle mass.
|
|
519
|
+
hbar : float
|
|
520
|
+
Reduced Planck constant (or an effective value thereof); must be
|
|
521
|
+
nonzero. Smaller ``hbar`` concentrates the phasor sum more
|
|
522
|
+
tightly around the classical path.
|
|
523
|
+
potential : {"free", "harmonic"}, default="free"
|
|
524
|
+
Which exactly-solvable system to use.
|
|
525
|
+
omega : float or None, optional
|
|
526
|
+
Angular frequency; required if ``potential="harmonic"``.
|
|
527
|
+
n_slices : int, default=60
|
|
528
|
+
Number of time slices per path.
|
|
529
|
+
n_paths : int, default=400
|
|
530
|
+
Number of random paths to sample (in addition to the classical
|
|
531
|
+
path itself).
|
|
532
|
+
sigma : float, default=0.5
|
|
533
|
+
Amplitude of the random path wiggles, passed to
|
|
534
|
+
:func:`sample_random_paths`.
|
|
535
|
+
seed : int or None, optional
|
|
536
|
+
Seed for reproducible path sampling.
|
|
537
|
+
|
|
538
|
+
Returns
|
|
539
|
+
-------
|
|
540
|
+
paths : ndarray, shape (n_paths + 1, n_slices + 1)
|
|
541
|
+
The random ensemble with the classical path appended as the last row.
|
|
542
|
+
actions : ndarray, shape (n_paths + 1,)
|
|
543
|
+
Discretized action of every path in ``paths`` (including the
|
|
544
|
+
classical path's discretized action, which need not exactly
|
|
545
|
+
equal ``classical_action`` at finite ``n_slices``).
|
|
546
|
+
classical_path : ndarray, shape (n_slices + 1,)
|
|
547
|
+
The exact classical trajectory.
|
|
548
|
+
classical_action : float
|
|
549
|
+
The exact (closed-form) classical action.
|
|
550
|
+
partial_sums : ndarray of complex, shape (n_paths + 2,)
|
|
551
|
+
Phasor partial sums from :func:`feynman_phasor_partial_sums`,
|
|
552
|
+
ordered closest-to-classical-action first.
|
|
553
|
+
|
|
554
|
+
Raises
|
|
555
|
+
------
|
|
556
|
+
ValueError
|
|
557
|
+
If ``potential`` is not one of ``"free"``/``"harmonic"``, or if
|
|
558
|
+
``potential="harmonic"`` and ``omega`` is not given.
|
|
559
|
+
|
|
560
|
+
Examples
|
|
561
|
+
--------
|
|
562
|
+
>>> paths, actions, x_cl, S_cl, partial = build_phasor_diagram(
|
|
563
|
+
... x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.05, potential="free",
|
|
564
|
+
... n_slices=20, n_paths=50, sigma=0.3, seed=0)
|
|
565
|
+
>>> paths.shape[0] == actions.shape[0] == 51
|
|
566
|
+
True
|
|
567
|
+
>>> partial.shape
|
|
568
|
+
(52,)
|
|
569
|
+
"""
|
|
570
|
+
if T <= 0:
|
|
571
|
+
raise ValueError(f"T must be positive, got {T}.")
|
|
572
|
+
|
|
573
|
+
if potential == "free":
|
|
574
|
+
_, classical_path = free_particle_classical_path(x0, xf, T, m, n_slices)
|
|
575
|
+
classical_action = free_particle_classical_action(x0, xf, T, m)
|
|
576
|
+
V = lambda x: np.zeros_like(x)
|
|
577
|
+
elif potential == "harmonic":
|
|
578
|
+
if omega is None:
|
|
579
|
+
raise ValueError('omega must be given when potential="harmonic".')
|
|
580
|
+
_, classical_path = harmonic_oscillator_classical_path(x0, xf, T, m, omega, n_slices)
|
|
581
|
+
classical_action = harmonic_oscillator_classical_action(x0, xf, T, m, omega)
|
|
582
|
+
V = lambda x: 0.5 * m * omega**2 * x**2
|
|
583
|
+
else:
|
|
584
|
+
raise ValueError(f'potential must be "free" or "harmonic", got {potential!r}.')
|
|
585
|
+
|
|
586
|
+
random_paths = sample_random_paths(x0, xf, T, n_slices, n_paths, sigma, seed=seed)
|
|
587
|
+
paths = np.vstack([random_paths, classical_path[None, :]])
|
|
588
|
+
|
|
589
|
+
dt = T / n_slices
|
|
590
|
+
actions = np.array([discretized_action(p, dt, m, V) for p in paths])
|
|
591
|
+
|
|
592
|
+
partial_sums = feynman_phasor_partial_sums(paths, actions, hbar, classical_action=classical_action)
|
|
593
|
+
|
|
594
|
+
return paths, actions, classical_path, classical_action, partial_sums
|