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.
Files changed (484) hide show
  1. physicskit/__init__.py +51 -0
  2. physicskit/astro/__init__.py +66 -0
  3. physicskit/astro/cosmic_web.py +395 -0
  4. physicskit/astro/galactic_dynamics.py +137 -0
  5. physicskit/astro/nbody.py +208 -0
  6. physicskit/astro/orbital_mechanics.py +220 -0
  7. physicskit/astro/stellar_dynamo.py +628 -0
  8. physicskit/astro/stellar_structure.py +198 -0
  9. physicskit/astro/tests/__init__.py +0 -0
  10. physicskit/astro/tests/conftest.py +7 -0
  11. physicskit/astro/tests/test_cosmic_web.py +159 -0
  12. physicskit/astro/tests/test_galactic_dynamics.py +46 -0
  13. physicskit/astro/tests/test_nbody.py +81 -0
  14. physicskit/astro/tests/test_orbital_mechanics.py +73 -0
  15. physicskit/astro/tests/test_stellar_dynamo.py +198 -0
  16. physicskit/astro/tests/test_stellar_structure.py +52 -0
  17. physicskit/astro/tests/test_visualizers.py +159 -0
  18. physicskit/astro/visualizers.py +628 -0
  19. physicskit/chaos/__init__.py +55 -0
  20. physicskit/chaos/core/__init__.py +3 -0
  21. physicskit/chaos/core/base_system.py +342 -0
  22. physicskit/chaos/core/integrators.py +40 -0
  23. physicskit/chaos/exceptions.py +24 -0
  24. physicskit/chaos/quantum/__init__.py +38 -0
  25. physicskit/chaos/quantum/billiards.py +274 -0
  26. physicskit/chaos/quantum/husimi.py +85 -0
  27. physicskit/chaos/quantum/maps.py +366 -0
  28. physicskit/chaos/systems/__init__.py +38 -0
  29. physicskit/chaos/systems/billiards.py +1131 -0
  30. physicskit/chaos/systems/continuous.py +1276 -0
  31. physicskit/chaos/systems/maps.py +557 -0
  32. physicskit/chaos/tests/__init__.py +0 -0
  33. physicskit/chaos/tests/test_basins.py +76 -0
  34. physicskit/chaos/tests/test_bifurcation.py +132 -0
  35. physicskit/chaos/tests/test_billiards.py +115 -0
  36. physicskit/chaos/tests/test_continuous.py +224 -0
  37. physicskit/chaos/tests/test_dimension.py +69 -0
  38. physicskit/chaos/tests/test_divergence.py +90 -0
  39. physicskit/chaos/tests/test_dynamic_plots.py +269 -0
  40. physicskit/chaos/tests/test_integrators.py +96 -0
  41. physicskit/chaos/tests/test_io.py +41 -0
  42. physicskit/chaos/tests/test_maps.py +110 -0
  43. physicskit/chaos/tests/test_metrics.py +115 -0
  44. physicskit/chaos/tests/test_phase_space.py +73 -0
  45. physicskit/chaos/tests/test_properties.py +116 -0
  46. physicskit/chaos/tests/test_quantum_billiards.py +94 -0
  47. physicskit/chaos/tests/test_quantum_maps.py +144 -0
  48. physicskit/chaos/tests/test_recurrence.py +51 -0
  49. physicskit/chaos/tests/test_repr_and_api_consistency.py +134 -0
  50. physicskit/chaos/tests/test_section.py +49 -0
  51. physicskit/chaos/tests/test_spectral.py +48 -0
  52. physicskit/chaos/tests/test_streamlit_app.py +45 -0
  53. physicskit/chaos/tests/test_timeseries.py +131 -0
  54. physicskit/chaos/tests/test_viewer3d.py +41 -0
  55. physicskit/chaos/utils/__init__.py +46 -0
  56. physicskit/chaos/utils/dimension.py +139 -0
  57. physicskit/chaos/utils/io.py +95 -0
  58. physicskit/chaos/utils/metrics.py +304 -0
  59. physicskit/chaos/utils/recurrence.py +122 -0
  60. physicskit/chaos/utils/spectral.py +69 -0
  61. physicskit/chaos/utils/timeseries.py +303 -0
  62. physicskit/chaos/visualizers/__init__.py +85 -0
  63. physicskit/chaos/visualizers/basins.py +185 -0
  64. physicskit/chaos/visualizers/bifurcation.py +273 -0
  65. physicskit/chaos/visualizers/divergence.py +374 -0
  66. physicskit/chaos/visualizers/dynamic_plots.py +1372 -0
  67. physicskit/chaos/visualizers/phase_space.py +133 -0
  68. physicskit/chaos/visualizers/quantum.py +299 -0
  69. physicskit/chaos/visualizers/recurrence.py +91 -0
  70. physicskit/chaos/visualizers/section.py +161 -0
  71. physicskit/chaos/visualizers/theme.py +31 -0
  72. physicskit/chaos/visualizers/viewer3d.py +82 -0
  73. physicskit/classical/__init__.py +55 -0
  74. physicskit/classical/core/__init__.py +17 -0
  75. physicskit/classical/core/base_system.py +510 -0
  76. physicskit/classical/core/integrators.py +397 -0
  77. physicskit/classical/systems/__init__.py +32 -0
  78. physicskit/classical/systems/chains.py +334 -0
  79. physicskit/classical/systems/hamiltonian.py +215 -0
  80. physicskit/classical/systems/lagrangian.py +308 -0
  81. physicskit/classical/systems/newtonian.py +536 -0
  82. physicskit/classical/systems/rotations.py +614 -0
  83. physicskit/classical/tests/__init__.py +0 -0
  84. physicskit/classical/tests/conftest.py +7 -0
  85. physicskit/classical/tests/test_base_system.py +113 -0
  86. physicskit/classical/tests/test_chains.py +84 -0
  87. physicskit/classical/tests/test_conservation.py +244 -0
  88. physicskit/classical/tests/test_conservation_utils.py +47 -0
  89. physicskit/classical/tests/test_hamiltonian.py +44 -0
  90. physicskit/classical/tests/test_integrators.py +123 -0
  91. physicskit/classical/tests/test_lagrangian.py +69 -0
  92. physicskit/classical/tests/test_newtonian.py +45 -0
  93. physicskit/classical/tests/test_rotations.py +160 -0
  94. physicskit/classical/tests/test_stepsize.py +149 -0
  95. physicskit/classical/tests/test_symbolic.py +125 -0
  96. physicskit/classical/tests/test_visualizers.py +172 -0
  97. physicskit/classical/utils/__init__.py +20 -0
  98. physicskit/classical/utils/conservation.py +126 -0
  99. physicskit/classical/utils/stepsize.py +187 -0
  100. physicskit/classical/utils/symbolic.py +235 -0
  101. physicskit/classical/visualizers/__init__.py +25 -0
  102. physicskit/classical/visualizers/animations.py +508 -0
  103. physicskit/classical/visualizers/interactive.py +113 -0
  104. physicskit/classical/visualizers/modal_analysis.py +97 -0
  105. physicskit/classical/visualizers/phase_space.py +214 -0
  106. physicskit/condensed/__init__.py +122 -0
  107. physicskit/condensed/anderson_localization.py +155 -0
  108. physicskit/condensed/correlated.py +284 -0
  109. physicskit/condensed/ginzburg_landau.py +220 -0
  110. physicskit/condensed/landau_levels.py +246 -0
  111. physicskit/condensed/laughlin.py +229 -0
  112. physicskit/condensed/models.py +627 -0
  113. physicskit/condensed/tests/__init__.py +0 -0
  114. physicskit/condensed/tests/test_condensed.py +518 -0
  115. physicskit/condensed/tests/test_visualizers.py +87 -0
  116. physicskit/condensed/tight_binding.py +445 -0
  117. physicskit/condensed/topological_insulator_3d.py +178 -0
  118. physicskit/condensed/topology.py +217 -0
  119. physicskit/condensed/visualizers.py +296 -0
  120. physicskit/condensed/weyl.py +180 -0
  121. physicskit/constants.py +184 -0
  122. physicskit/fields/__init__.py +111 -0
  123. physicskit/fields/electrodynamics.py +671 -0
  124. physicskit/fields/quantum_fields.py +510 -0
  125. physicskit/fields/solitons.py +527 -0
  126. physicskit/fields/tests/__init__.py +0 -0
  127. physicskit/fields/tests/conftest.py +7 -0
  128. physicskit/fields/tests/test_field_animations.py +154 -0
  129. physicskit/fields/tests/test_fields.py +439 -0
  130. physicskit/fields/tests/test_visualizers.py +101 -0
  131. physicskit/fields/visualizers.py +503 -0
  132. physicskit/fluids/__init__.py +134 -0
  133. physicskit/fluids/core/__init__.py +23 -0
  134. physicskit/fluids/core/grid.py +165 -0
  135. physicskit/fluids/core/timestepping.py +231 -0
  136. physicskit/fluids/exceptions.py +26 -0
  137. physicskit/fluids/systems/__init__.py +70 -0
  138. physicskit/fluids/systems/compressible_flow.py +281 -0
  139. physicskit/fluids/systems/instabilities.py +343 -0
  140. physicskit/fluids/systems/navier_stokes.py +221 -0
  141. physicskit/fluids/systems/potential_flow.py +440 -0
  142. physicskit/fluids/systems/viscous_flow.py +425 -0
  143. physicskit/fluids/systems/vortex_dynamics.py +304 -0
  144. physicskit/fluids/tests/__init__.py +0 -0
  145. physicskit/fluids/tests/conftest.py +7 -0
  146. physicskit/fluids/tests/test_compressible_flow.py +66 -0
  147. physicskit/fluids/tests/test_instabilities.py +115 -0
  148. physicskit/fluids/tests/test_navier_stokes.py +67 -0
  149. physicskit/fluids/tests/test_potential_flow.py +92 -0
  150. physicskit/fluids/tests/test_static_visualizers.py +91 -0
  151. physicskit/fluids/tests/test_utils.py +100 -0
  152. physicskit/fluids/tests/test_viscous_flow.py +110 -0
  153. physicskit/fluids/tests/test_visualizers.py +34 -0
  154. physicskit/fluids/tests/test_vortex_dynamics.py +88 -0
  155. physicskit/fluids/utils/__init__.py +18 -0
  156. physicskit/fluids/utils/dimensionless.py +239 -0
  157. physicskit/fluids/utils/spectral_analysis.py +142 -0
  158. physicskit/fluids/visualizers/__init__.py +14 -0
  159. physicskit/fluids/visualizers/compressible.py +39 -0
  160. physicskit/fluids/visualizers/flow_fields.py +252 -0
  161. physicskit/fluids/visualizers/potential_flow.py +51 -0
  162. physicskit/fluids/visualizers/spectra.py +62 -0
  163. physicskit/fluids/visualizers/theme.py +38 -0
  164. physicskit/integrators/__init__.py +52 -0
  165. physicskit/integrators/adaptive.py +199 -0
  166. physicskit/integrators/fixed_step.py +360 -0
  167. physicskit/integrators/tests/__init__.py +0 -0
  168. physicskit/integrators/tests/test_integrators.py +101 -0
  169. physicskit/optics/__init__.py +124 -0
  170. physicskit/optics/_compat.py +5 -0
  171. physicskit/optics/gaussian.py +382 -0
  172. physicskit/optics/quantum_optics.py +428 -0
  173. physicskit/optics/ray.py +469 -0
  174. physicskit/optics/tests/__init__.py +0 -0
  175. physicskit/optics/tests/test_diffraction_animation.py +38 -0
  176. physicskit/optics/tests/test_gaussian.py +170 -0
  177. physicskit/optics/tests/test_quantum_optics.py +147 -0
  178. physicskit/optics/tests/test_ray.py +177 -0
  179. physicskit/optics/tests/test_visualizers.py +58 -0
  180. physicskit/optics/tests/test_wave.py +146 -0
  181. physicskit/optics/visualizers.py +264 -0
  182. physicskit/optics/wave.py +365 -0
  183. physicskit/particle/__init__.py +152 -0
  184. physicskit/particle/collider.py +382 -0
  185. physicskit/particle/confinement.py +125 -0
  186. physicskit/particle/decays.py +357 -0
  187. physicskit/particle/electroweak.py +300 -0
  188. physicskit/particle/kinematics.py +271 -0
  189. physicskit/particle/neutrinos.py +84 -0
  190. physicskit/particle/nuclear.py +100 -0
  191. physicskit/particle/scattering.py +159 -0
  192. physicskit/particle/tests/__init__.py +0 -0
  193. physicskit/particle/tests/conftest.py +7 -0
  194. physicskit/particle/tests/test_collider.py +119 -0
  195. physicskit/particle/tests/test_confinement.py +42 -0
  196. physicskit/particle/tests/test_decays.py +112 -0
  197. physicskit/particle/tests/test_electroweak.py +97 -0
  198. physicskit/particle/tests/test_kinematics.py +138 -0
  199. physicskit/particle/tests/test_neutrinos.py +36 -0
  200. physicskit/particle/tests/test_nuclear.py +45 -0
  201. physicskit/particle/tests/test_scattering.py +64 -0
  202. physicskit/particle/tests/test_visualizers.py +214 -0
  203. physicskit/particle/visualizers/__init__.py +38 -0
  204. physicskit/particle/visualizers/animations.py +705 -0
  205. physicskit/particle/visualizers/static.py +101 -0
  206. physicskit/plasma/__init__.py +176 -0
  207. physicskit/plasma/acceleration.py +152 -0
  208. physicskit/plasma/instabilities.py +417 -0
  209. physicskit/plasma/kinetic.py +588 -0
  210. physicskit/plasma/mhd.py +463 -0
  211. physicskit/plasma/single_particle.py +562 -0
  212. physicskit/plasma/tests/__init__.py +0 -0
  213. physicskit/plasma/tests/conftest.py +7 -0
  214. physicskit/plasma/tests/test_new_time_domain_features.py +222 -0
  215. physicskit/plasma/tests/test_plasma.py +232 -0
  216. physicskit/plasma/tests/test_visualizers.py +79 -0
  217. physicskit/plasma/turbulence.py +219 -0
  218. physicskit/plasma/visualizers.py +868 -0
  219. physicskit/plasma/waves.py +549 -0
  220. physicskit/quantum/__init__.py +180 -0
  221. physicskit/quantum/_compat.py +20 -0
  222. physicskit/quantum/chapters/__init__.py +0 -0
  223. physicskit/quantum/chapters/entanglement.py +489 -0
  224. physicskit/quantum/chapters/harmonic_spin.py +517 -0
  225. physicskit/quantum/chapters/hydrogen_am.py +292 -0
  226. physicskit/quantum/chapters/perturbation.py +350 -0
  227. physicskit/quantum/chapters/potentials.py +997 -0
  228. physicskit/quantum/chapters/spin.py +306 -0
  229. physicskit/quantum/chapters/wave_packets.py +541 -0
  230. physicskit/quantum/core/__init__.py +0 -0
  231. physicskit/quantum/core/eigensolvers.py +311 -0
  232. physicskit/quantum/core/operators.py +296 -0
  233. physicskit/quantum/core/solvers.py +271 -0
  234. physicskit/quantum/tests/__init__.py +0 -0
  235. physicskit/quantum/tests/conftest.py +7 -0
  236. physicskit/quantum/tests/test_animations.py +225 -0
  237. physicskit/quantum/tests/test_compat.py +43 -0
  238. physicskit/quantum/tests/test_eigensolvers.py +24 -0
  239. physicskit/quantum/tests/test_entanglement.py +127 -0
  240. physicskit/quantum/tests/test_harmonic_spin.py +140 -0
  241. physicskit/quantum/tests/test_hydrogen_am.py +48 -0
  242. physicskit/quantum/tests/test_measure.py +110 -0
  243. physicskit/quantum/tests/test_operators.py +105 -0
  244. physicskit/quantum/tests/test_perturbation.py +112 -0
  245. physicskit/quantum/tests/test_physics_checks.py +131 -0
  246. physicskit/quantum/tests/test_potentials.py +191 -0
  247. physicskit/quantum/tests/test_solvers.py +70 -0
  248. physicskit/quantum/tests/test_spin.py +22 -0
  249. physicskit/quantum/tests/test_unitarity.py +84 -0
  250. physicskit/quantum/tests/test_wave_packets.py +53 -0
  251. physicskit/quantum/utils/__init__.py +0 -0
  252. physicskit/quantum/utils/measure.py +253 -0
  253. physicskit/quantum/visualizers/__init__.py +0 -0
  254. physicskit/quantum/visualizers/bloch_sphere.py +205 -0
  255. physicskit/quantum/visualizers/entanglement.py +58 -0
  256. physicskit/quantum/visualizers/orbitals.py +187 -0
  257. physicskit/quantum/visualizers/phase_space.py +179 -0
  258. physicskit/quantum/visualizers/wavefunctions.py +230 -0
  259. physicskit/relativity/__init__.py +61 -0
  260. physicskit/relativity/chapters/__init__.py +33 -0
  261. physicskit/relativity/chapters/cosmology.py +190 -0
  262. physicskit/relativity/chapters/gw_merger.py +399 -0
  263. physicskit/relativity/chapters/kerr.py +371 -0
  264. physicskit/relativity/chapters/lensing.py +196 -0
  265. physicskit/relativity/chapters/neutron_star.py +149 -0
  266. physicskit/relativity/chapters/schwarzschild.py +412 -0
  267. physicskit/relativity/chapters/timekeeping.py +133 -0
  268. physicskit/relativity/core/__init__.py +12 -0
  269. physicskit/relativity/core/geodesics.py +216 -0
  270. physicskit/relativity/core/kerr_raytracer.py +259 -0
  271. physicskit/relativity/core/raytracer.py +241 -0
  272. physicskit/relativity/core/tensors.py +468 -0
  273. physicskit/relativity/tests/__init__.py +0 -0
  274. physicskit/relativity/tests/test_conservations.py +54 -0
  275. physicskit/relativity/tests/test_constants.py +34 -0
  276. physicskit/relativity/tests/test_cosmology.py +61 -0
  277. physicskit/relativity/tests/test_gw_merger.py +117 -0
  278. physicskit/relativity/tests/test_kerr.py +116 -0
  279. physicskit/relativity/tests/test_kerr_raytracer.py +103 -0
  280. physicskit/relativity/tests/test_lensing.py +75 -0
  281. physicskit/relativity/tests/test_neutron_star.py +48 -0
  282. physicskit/relativity/tests/test_raytracer.py +67 -0
  283. physicskit/relativity/tests/test_schwarzschild.py +126 -0
  284. physicskit/relativity/tests/test_shadow_render.py +81 -0
  285. physicskit/relativity/tests/test_tensors.py +86 -0
  286. physicskit/relativity/tests/test_timekeeping.py +51 -0
  287. physicskit/relativity/tests/test_visualizers_misc.py +115 -0
  288. physicskit/relativity/utils/__init__.py +1 -0
  289. physicskit/relativity/utils/constants.py +232 -0
  290. physicskit/relativity/visualizers/__init__.py +46 -0
  291. physicskit/relativity/visualizers/interactive.py +127 -0
  292. physicskit/relativity/visualizers/shadow_render.py +367 -0
  293. physicskit/relativity/visualizers/spacetime_3d.py +92 -0
  294. physicskit/relativity/visualizers/spacetime_diagrams.py +198 -0
  295. physicskit/relativity/visualizers/wave_plots.py +185 -0
  296. physicskit/rmt/__init__.py +8 -0
  297. physicskit/rmt/ensembles/__init__.py +108 -0
  298. physicskit/rmt/ensembles/banded.py +114 -0
  299. physicskit/rmt/ensembles/base.py +135 -0
  300. physicskit/rmt/ensembles/bdg.py +218 -0
  301. physicskit/rmt/ensembles/chiral.py +308 -0
  302. physicskit/rmt/ensembles/circular.py +104 -0
  303. physicskit/rmt/ensembles/crossover.py +82 -0
  304. physicskit/rmt/ensembles/density_matrix.py +148 -0
  305. physicskit/rmt/ensembles/effective_hamiltonian.py +230 -0
  306. physicskit/rmt/ensembles/embedded.py +207 -0
  307. physicskit/rmt/ensembles/gaussian.py +153 -0
  308. physicskit/rmt/ensembles/ginibre.py +110 -0
  309. physicskit/rmt/ensembles/girko.py +190 -0
  310. physicskit/rmt/ensembles/graph_laplacian.py +92 -0
  311. physicskit/rmt/ensembles/haar.py +57 -0
  312. physicskit/rmt/ensembles/jacobi.py +182 -0
  313. physicskit/rmt/ensembles/poisson.py +77 -0
  314. physicskit/rmt/ensembles/polynomial.py +139 -0
  315. physicskit/rmt/ensembles/pt_symmetric.py +120 -0
  316. physicskit/rmt/ensembles/single_ring.py +170 -0
  317. physicskit/rmt/ensembles/sparse.py +95 -0
  318. physicskit/rmt/ensembles/syk.py +170 -0
  319. physicskit/rmt/ensembles/truncated_unitary.py +80 -0
  320. physicskit/rmt/ensembles/universality.py +92 -0
  321. physicskit/rmt/ensembles/wishart.py +88 -0
  322. physicskit/rmt/py.typed +0 -0
  323. physicskit/rmt/spectrum.py +82 -0
  324. physicskit/rmt/stats/__init__.py +160 -0
  325. physicskit/rmt/stats/characteristic_polynomial.py +77 -0
  326. physicskit/rmt/stats/circular_law.py +54 -0
  327. physicskit/rmt/stats/correlations.py +162 -0
  328. physicskit/rmt/stats/density.py +70 -0
  329. physicskit/rmt/stats/entanglement.py +36 -0
  330. physicskit/rmt/stats/free_probability.py +202 -0
  331. physicskit/rmt/stats/localization.py +338 -0
  332. physicskit/rmt/stats/marchenko_pastur.py +55 -0
  333. physicskit/rmt/stats/pt_symmetric.py +265 -0
  334. physicskit/rmt/stats/ratios.py +110 -0
  335. physicskit/rmt/stats/real_ginibre.py +134 -0
  336. physicskit/rmt/stats/rigidity.py +272 -0
  337. physicskit/rmt/stats/single_ring.py +95 -0
  338. physicskit/rmt/stats/spacing.py +150 -0
  339. physicskit/rmt/stats/tracy_widom.py +175 -0
  340. physicskit/rmt/stats/truncated_unitary.py +40 -0
  341. physicskit/rmt/stats/unfolding.py +37 -0
  342. physicskit/rmt/stats/wachter.py +67 -0
  343. physicskit/rmt/tests/__init__.py +0 -0
  344. physicskit/rmt/tests/cache_utils.py +107 -0
  345. physicskit/rmt/tests/conftest.py +8 -0
  346. physicskit/rmt/tests/test_banded.py +86 -0
  347. physicskit/rmt/tests/test_base.py +29 -0
  348. physicskit/rmt/tests/test_bdg.py +133 -0
  349. physicskit/rmt/tests/test_characteristic_polynomial.py +50 -0
  350. physicskit/rmt/tests/test_chiral.py +273 -0
  351. physicskit/rmt/tests/test_circular.py +225 -0
  352. physicskit/rmt/tests/test_crossover.py +72 -0
  353. physicskit/rmt/tests/test_density.py +23 -0
  354. physicskit/rmt/tests/test_density_matrix.py +181 -0
  355. physicskit/rmt/tests/test_effective_hamiltonian.py +140 -0
  356. physicskit/rmt/tests/test_embedded.py +169 -0
  357. physicskit/rmt/tests/test_free_probability.py +81 -0
  358. physicskit/rmt/tests/test_gaussian_ensembles.py +22 -0
  359. physicskit/rmt/tests/test_gaussian_semicircle.py +127 -0
  360. physicskit/rmt/tests/test_ginibre_circular_law.py +131 -0
  361. physicskit/rmt/tests/test_girko.py +178 -0
  362. physicskit/rmt/tests/test_graph_laplacian.py +102 -0
  363. physicskit/rmt/tests/test_haar.py +118 -0
  364. physicskit/rmt/tests/test_jacobi_wachter.py +136 -0
  365. physicskit/rmt/tests/test_localization.py +240 -0
  366. physicskit/rmt/tests/test_poisson.py +149 -0
  367. physicskit/rmt/tests/test_polynomial.py +107 -0
  368. physicskit/rmt/tests/test_pt_symmetric.py +178 -0
  369. physicskit/rmt/tests/test_random_state.py +19 -0
  370. physicskit/rmt/tests/test_real_ginibre.py +112 -0
  371. physicskit/rmt/tests/test_rigidity_universality.py +167 -0
  372. physicskit/rmt/tests/test_single_ring.py +132 -0
  373. physicskit/rmt/tests/test_spacing_and_ratios.py +122 -0
  374. physicskit/rmt/tests/test_sparse.py +71 -0
  375. physicskit/rmt/tests/test_spectrum.py +27 -0
  376. physicskit/rmt/tests/test_syk.py +136 -0
  377. physicskit/rmt/tests/test_tracy_widom.py +113 -0
  378. physicskit/rmt/tests/test_tridiagonal.py +41 -0
  379. physicskit/rmt/tests/test_truncated_unitary.py +80 -0
  380. physicskit/rmt/tests/test_validation_base.py +25 -0
  381. physicskit/rmt/tests/test_validation_misc.py +67 -0
  382. physicskit/rmt/tests/test_wishart_marchenko_pastur.py +120 -0
  383. physicskit/rmt/utils/__init__.py +0 -0
  384. physicskit/rmt/utils/haar.py +128 -0
  385. physicskit/rmt/utils/random_state.py +24 -0
  386. physicskit/rmt/utils/tridiagonal.py +167 -0
  387. physicskit/rmt/validation/__init__.py +36 -0
  388. physicskit/rmt/validation/base.py +126 -0
  389. physicskit/rmt/validation/circular_law.py +80 -0
  390. physicskit/rmt/validation/marchenko_pastur.py +53 -0
  391. physicskit/rmt/validation/ratio_distribution.py +53 -0
  392. physicskit/rmt/validation/real_ginibre.py +60 -0
  393. physicskit/rmt/validation/sine_kernel.py +57 -0
  394. physicskit/rmt/validation/single_ring.py +68 -0
  395. physicskit/rmt/validation/tracy_widom.py +89 -0
  396. physicskit/rmt/validation/universality.py +100 -0
  397. physicskit/rmt/validation/wachter.py +52 -0
  398. physicskit/rmt/validation/wigner_semicircle.py +40 -0
  399. physicskit/rmt/validation/wigner_surmise.py +58 -0
  400. physicskit/semiclassical/__init__.py +94 -0
  401. physicskit/semiclassical/_compat.py +5 -0
  402. physicskit/semiclassical/core/__init__.py +41 -0
  403. physicskit/semiclassical/core/gutzwiller.py +215 -0
  404. physicskit/semiclassical/core/path_integral.py +594 -0
  405. physicskit/semiclassical/core/propagators.py +579 -0
  406. physicskit/semiclassical/core/wkb.py +308 -0
  407. physicskit/semiclassical/systems/__init__.py +13 -0
  408. physicskit/semiclassical/systems/scarring.py +278 -0
  409. physicskit/semiclassical/tests/__init__.py +0 -0
  410. physicskit/semiclassical/tests/test_gutzwiller.py +35 -0
  411. physicskit/semiclassical/tests/test_path_integral.py +194 -0
  412. physicskit/semiclassical/tests/test_propagators.py +82 -0
  413. physicskit/semiclassical/tests/test_scarring.py +43 -0
  414. physicskit/semiclassical/tests/test_visualizers.py +89 -0
  415. physicskit/semiclassical/tests/test_wkb.py +30 -0
  416. physicskit/semiclassical/visualizers/__init__.py +17 -0
  417. physicskit/semiclassical/visualizers/gutzwiller.py +55 -0
  418. physicskit/semiclassical/visualizers/path_integral.py +195 -0
  419. physicskit/semiclassical/visualizers/propagators.py +89 -0
  420. physicskit/semiclassical/visualizers/scarring.py +146 -0
  421. physicskit/semiclassical/visualizers/wkb.py +55 -0
  422. physicskit/statphys/__init__.py +80 -0
  423. physicskit/statphys/chapters/__init__.py +43 -0
  424. physicskit/statphys/chapters/ehrenfest_urn.py +112 -0
  425. physicskit/statphys/chapters/ising_lattice.py +431 -0
  426. physicskit/statphys/chapters/kpz_growth.py +129 -0
  427. physicskit/statphys/chapters/molecular_dynamics.py +258 -0
  428. physicskit/statphys/chapters/nonequilibrium_work.py +146 -0
  429. physicskit/statphys/chapters/percolation.py +305 -0
  430. physicskit/statphys/chapters/random_walk.py +142 -0
  431. physicskit/statphys/chapters/renormalization.py +148 -0
  432. physicskit/statphys/chapters/sandpile.py +109 -0
  433. physicskit/statphys/chapters/spin_glass.py +275 -0
  434. physicskit/statphys/core/__init__.py +10 -0
  435. physicskit/statphys/core/kpz_engine.py +53 -0
  436. physicskit/statphys/core/md_engine.py +157 -0
  437. physicskit/statphys/core/monte_carlo.py +462 -0
  438. physicskit/statphys/core/random_walk_engine.py +68 -0
  439. physicskit/statphys/core/sandpile_engine.py +52 -0
  440. physicskit/statphys/tests/__init__.py +0 -0
  441. physicskit/statphys/tests/test_dynamics.py +66 -0
  442. physicskit/statphys/tests/test_ehrenfest_urn.py +44 -0
  443. physicskit/statphys/tests/test_finite_size_scaling.py +62 -0
  444. physicskit/statphys/tests/test_interactive.py +33 -0
  445. physicskit/statphys/tests/test_ising.py +68 -0
  446. physicskit/statphys/tests/test_kpz.py +55 -0
  447. physicskit/statphys/tests/test_landau_theory.py +49 -0
  448. physicskit/statphys/tests/test_md_engine.py +31 -0
  449. physicskit/statphys/tests/test_molecular_dynamics.py +72 -0
  450. physicskit/statphys/tests/test_nonequilibrium_work.py +33 -0
  451. physicskit/statphys/tests/test_partition_function.py +26 -0
  452. physicskit/statphys/tests/test_percolation.py +116 -0
  453. physicskit/statphys/tests/test_potts_model.py +46 -0
  454. physicskit/statphys/tests/test_random_walk.py +50 -0
  455. physicskit/statphys/tests/test_renormalization.py +44 -0
  456. physicskit/statphys/tests/test_sandpile.py +44 -0
  457. physicskit/statphys/tests/test_spin_glass.py +73 -0
  458. physicskit/statphys/tests/test_thermodynamics.py +121 -0
  459. physicskit/statphys/tests/test_xy_model.py +45 -0
  460. physicskit/statphys/utils/__init__.py +1 -0
  461. physicskit/statphys/utils/dynamics.py +100 -0
  462. physicskit/statphys/utils/finite_size_scaling.py +171 -0
  463. physicskit/statphys/utils/landau_theory.py +151 -0
  464. physicskit/statphys/utils/partition_function.py +109 -0
  465. physicskit/statphys/utils/thermodynamics.py +356 -0
  466. physicskit/statphys/visualizers/__init__.py +87 -0
  467. physicskit/statphys/visualizers/interactive.py +161 -0
  468. physicskit/statphys/visualizers/jarzynski_render.py +44 -0
  469. physicskit/statphys/visualizers/kpz_render.py +65 -0
  470. physicskit/statphys/visualizers/lattice_render.py +212 -0
  471. physicskit/statphys/visualizers/particle_render.py +121 -0
  472. physicskit/statphys/visualizers/random_walk_render.py +106 -0
  473. physicskit/statphys/visualizers/rg_render.py +45 -0
  474. physicskit/statphys/visualizers/sandpile_render.py +65 -0
  475. physicskit/statphys/visualizers/spin_glass_render.py +40 -0
  476. physicskit/statphys/visualizers/urn_render.py +38 -0
  477. physicskit/statphys/visualizers/vortex_render.py +84 -0
  478. physicskit/tests/__init__.py +0 -0
  479. physicskit/tests/test_constants.py +38 -0
  480. physicskit-0.1.0.dist-info/METADATA +196 -0
  481. physicskit-0.1.0.dist-info/RECORD +484 -0
  482. physicskit-0.1.0.dist-info/WHEEL +5 -0
  483. physicskit-0.1.0.dist-info/licenses/LICENSE +21 -0
  484. physicskit-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,308 @@
1
+ r"""1D WKB wavefunctions, classical turning points, and Bohr-Sommerfeld (EBK) quantization.
2
+
3
+ The Wentzel-Kramers-Brillouin (WKB) approximation writes the wavefunction
4
+ as :math:`\psi(x) \sim p(x)^{-1/2}\exp(\pm i\int p\,dx/\hbar)` -- an
5
+ :math:`\hbar\to 0` asymptotic expansion valid wherever the local
6
+ de Broglie wavelength :math:`2\pi\hbar/p(x)` varies slowly compared to
7
+ itself. The prefactor :math:`p(x)^{-1/2}` is exactly the classical
8
+ probability density of a particle oscillating in the potential (it spends
9
+ more time, and so is more likely to be found, where it moves slowest);
10
+ this is the one-dimensional seed of every semiclassical idea in
11
+ :mod:`physicskit.semiclassical` -- the Van Vleck-Morette
12
+ determinant in :mod:`~physicskit.semiclassical.core.propagators` is
13
+ the same classical-probability prefactor for a propagator instead of a
14
+ stationary state, and the periodic-orbit sum in
15
+ :mod:`~physicskit.semiclassical.core.gutzwiller` is built from the
16
+ same action integral used here for Bohr-Sommerfeld quantization.
17
+
18
+ At each classical turning point the WKB approximation itself breaks down
19
+ (:math:`p(x)\to 0`); matching the oscillatory interior solution through
20
+ that breakdown region (via the Airy function connection formulas) costs
21
+ each *soft* (linear) turning point a phase of :math:`\pi/4`. For a bound
22
+ state with two such turning points, the round-trip quantization condition
23
+ :math:`\oint p\,dx = 2\pi\hbar(n+\tfrac12)` -- equivalently
24
+ :math:`\int_{x_1}^{x_2}p\,dx=(n+\tfrac12)\pi\hbar` -- is the
25
+ one-dimensional Einstein-Brillouin-Keller (EBK) rule implemented by
26
+ :func:`bohr_sommerfeld_energies`.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import numpy as np
32
+ from scipy.integrate import cumulative_trapezoid, quad
33
+ from scipy.optimize import brentq
34
+
35
+ from .._compat import trapz
36
+
37
+ __all__ = [
38
+ "classical_momentum",
39
+ "turning_points",
40
+ "wkb_action",
41
+ "bohr_sommerfeld_energies",
42
+ "wkb_wavefunction",
43
+ ]
44
+
45
+
46
+ def classical_momentum(E: float, V, x: np.ndarray, m: float = 1.0) -> np.ndarray:
47
+ r"""Classical momentum :math:`p(x) = \sqrt{2m(E-V(x))}` in the allowed region.
48
+
49
+ Parameters
50
+ ----------
51
+ E : float
52
+ Total energy.
53
+ V : callable
54
+ Potential energy function ``V(x)``.
55
+ x : ndarray
56
+ Positions at which to evaluate :math:`p(x)`.
57
+ m : float, default=1.0
58
+ Particle mass.
59
+
60
+ Returns
61
+ -------
62
+ ndarray
63
+ :math:`p(x)`, same shape as ``x``; ``nan`` wherever :math:`V(x)>E`
64
+ (the classically forbidden region, where WKB oscillates into a
65
+ real exponential instead).
66
+
67
+ Examples
68
+ --------
69
+ >>> import numpy as np
70
+ >>> V = lambda x: 0.5 * x ** 2
71
+ >>> p = classical_momentum(E=2.0, V=V, x=np.array([0.0, 1.0, 3.0]))
72
+ >>> np.round(p, 4)
73
+ array([2. , 1.7321, nan])
74
+ """
75
+ x = np.asarray(x, dtype=float)
76
+ diff = 2.0 * m * (E - V(x))
77
+ return np.sqrt(np.where(diff >= 0, diff, np.nan))
78
+
79
+
80
+ def turning_points(E: float, V, x_min: float, x_max: float, n_search: int = 4000) -> list:
81
+ r"""Locate the classical turning points (roots of :math:`E=V(x)`) in :math:`[x_{min},x_{max}]`.
82
+
83
+ Scans a fine grid for sign changes of :math:`E-V(x)` and refines each
84
+ with Brent's method; returns every turning point found, not just the
85
+ innermost pair, so multi-well potentials are handled correctly.
86
+
87
+ Parameters
88
+ ----------
89
+ E : float
90
+ Total energy.
91
+ V : callable
92
+ Potential energy function ``V(x)``.
93
+ x_min, x_max : float
94
+ Search domain (should extend into the classically forbidden
95
+ region on both sides of the state of interest).
96
+ n_search : int, default=4000
97
+ Number of grid points used to bracket the roots; increase for
98
+ potentials with closely spaced turning points.
99
+
100
+ Returns
101
+ -------
102
+ list of float
103
+ Turning points, ascending.
104
+
105
+ See Also
106
+ --------
107
+ wkb_action : Integrates :func:`classical_momentum` between two turning points.
108
+
109
+ Examples
110
+ --------
111
+ >>> V = lambda x: 0.5 * x ** 2
112
+ >>> [round(t, 4) for t in turning_points(E=2.0, V=V, x_min=-10, x_max=10)]
113
+ [-2.0, 2.0]
114
+ """
115
+ xs = np.linspace(x_min, x_max, n_search)
116
+ f = E - V(xs)
117
+ roots = []
118
+ for i in range(n_search - 1):
119
+ if f[i] == 0:
120
+ roots.append(float(xs[i]))
121
+ elif f[i] * f[i + 1] < 0:
122
+ roots.append(brentq(lambda x: E - V(x), xs[i], xs[i + 1]))
123
+ return roots
124
+
125
+
126
+ def wkb_action(E: float, V, m: float, x1: float, x2: float, hbar: float = 1.0) -> float:
127
+ r"""WKB action integral :math:`S(E)=\int_{x_1}^{x_2} p(x)\,dx` between two turning points.
128
+
129
+ This is the classical action accumulated on one traversal of the
130
+ classically allowed region -- half of the full round-trip action
131
+ :math:`\oint p\,dx`, and (as a function of :math:`E`) exactly the
132
+ Hamilton principal function whose energy derivative gives the
133
+ classical period, :math:`T(E)=dS/dE`, used by
134
+ :func:`physicskit.semiclassical.core.gutzwiller.classical_period`.
135
+
136
+ Parameters
137
+ ----------
138
+ E : float
139
+ Total energy.
140
+ V : callable
141
+ Potential energy function ``V(x)``.
142
+ m : float
143
+ Particle mass.
144
+ x1, x2 : float
145
+ The two turning points (e.g. from :func:`turning_points`).
146
+ hbar : float, default=1.0
147
+ Value of :math:`\hbar` to use (only needed by callers converting
148
+ this to a phase; the integral itself is :math:`\hbar`-independent).
149
+
150
+ Returns
151
+ -------
152
+ float
153
+ The action :math:`S(E)`.
154
+
155
+ Examples
156
+ --------
157
+ For the harmonic oscillator, :math:`S(E)=\pi E/\omega` exactly:
158
+
159
+ >>> V = lambda x: 0.5 * x ** 2
160
+ >>> x1, x2 = turning_points(E=2.0, V=V, x_min=-10, x_max=10)
161
+ >>> round(wkb_action(E=2.0, V=V, m=1.0, x1=x1, x2=x2), 6)
162
+ 6.283185
163
+ """
164
+
165
+ def integrand(x):
166
+ return float(np.nan_to_num(classical_momentum(E, V, np.array([x]), m)[0], nan=0.0))
167
+
168
+ result, _ = quad(integrand, x1, x2, limit=200)
169
+ return result
170
+
171
+
172
+ def bohr_sommerfeld_energies(V, m: float, x_min: float, x_max: float, n_max: int, hbar: float = 1.0, E_min: float = 1e-3, E_max: float = 100.0) -> np.ndarray:
173
+ r"""Bohr-Sommerfeld (EBK) bound-state energies from the WKB quantization condition.
174
+
175
+ Solves :math:`\int_{x_1(E_n)}^{x_2(E_n)}p(x)\,dx=(n+\tfrac12)\pi\hbar`
176
+ for each :math:`n=0,\dots,n_{max}-1` by root-finding on :math:`E`,
177
+ re-locating the turning points at every trial energy. For the
178
+ harmonic oscillator this reproduces the exact spectrum
179
+ :math:`E_n=(n+\tfrac12)\hbar\omega` to machine precision, since the
180
+ WKB approximation is exact whenever the potential is exactly
181
+ quadratic.
182
+
183
+ Parameters
184
+ ----------
185
+ V : callable
186
+ Potential energy function ``V(x)``, with a single classically
187
+ allowed region containing its minimum for every energy searched.
188
+ m : float
189
+ Particle mass.
190
+ x_min, x_max : float
191
+ Search domain for :func:`turning_points`; must extend well into
192
+ the classically forbidden region at ``E_max``.
193
+ n_max : int
194
+ Number of levels to compute (:math:`n=0,\dots,n_{max}-1`).
195
+ hbar : float, default=1.0
196
+ Value of :math:`\hbar` to use.
197
+ E_min : float, default=1e-3
198
+ Lower bracket for the ground-state root search; must be small
199
+ enough that its turning points still resolve on the
200
+ :func:`turning_points` search grid.
201
+ E_max : float, default=100.0
202
+ Upper bracket for the highest level's root search.
203
+
204
+ Returns
205
+ -------
206
+ ndarray, shape (n_max,)
207
+ Quantized energies, ascending.
208
+
209
+ See Also
210
+ --------
211
+ wkb_action : The action integral this quantizes.
212
+ wkb_wavefunction : The corresponding approximate wavefunctions.
213
+
214
+ Examples
215
+ --------
216
+ >>> import numpy as np
217
+ >>> V = lambda x: 0.5 * x ** 2
218
+ >>> energies = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=5)
219
+ >>> np.round(energies, 6)
220
+ array([0.5, 1.5, 2.5, 3.5, 4.5])
221
+ """
222
+ energies = np.empty(n_max)
223
+ for n in range(n_max):
224
+
225
+ def condition(E, n=n):
226
+ tp = turning_points(E, V, x_min, x_max)
227
+ x1, x2 = tp[0], tp[-1]
228
+ return wkb_action(E, V, m, x1, x2, hbar) - (n + 0.5) * np.pi * hbar
229
+
230
+ energies[n] = brentq(condition, E_min, E_max)
231
+ return energies
232
+
233
+
234
+ def wkb_wavefunction(x: np.ndarray, E: float, V, m: float = 1.0, hbar: float = 1.0) -> np.ndarray:
235
+ r"""The (real-valued, standing-wave) WKB wavefunction in the classically allowed region.
236
+
237
+ .. math::
238
+
239
+ \psi(x) \approx \frac{C}{\sqrt{p(x)}}
240
+ \cos\!\left(\frac{1}{\hbar}\int_{x_1}^{x}p(x')\,dx' - \frac{\pi}{4}\right),
241
+
242
+ with the :math:`\pi/4` phase set by the Airy connection formula at
243
+ the left (soft) turning point :math:`x_1`, and :math:`C` fixed by
244
+ numerical normalization over the allowed region. Diverges (is not
245
+ valid) within a few de Broglie wavelengths of either turning point;
246
+ zero is returned in the classically forbidden region rather than the
247
+ (also invalid) naive imaginary-momentum continuation.
248
+
249
+ Parameters
250
+ ----------
251
+ x : ndarray
252
+ Positions at which to evaluate the wavefunction.
253
+ E : float
254
+ Energy (e.g. from :func:`bohr_sommerfeld_energies`, for a properly
255
+ quantized bound state).
256
+ V : callable
257
+ Potential energy function ``V(x)``.
258
+ m : float, default=1.0
259
+ Particle mass.
260
+ hbar : float, default=1.0
261
+ Value of :math:`\hbar` to use.
262
+
263
+ Returns
264
+ -------
265
+ ndarray
266
+ :math:`\psi(x)`, same shape as ``x``, normalized so
267
+ :math:`\int|\psi|^2\,dx=1` over ``x``'s range.
268
+
269
+ See Also
270
+ --------
271
+ bohr_sommerfeld_energies : Quantized energies this is evaluated at.
272
+
273
+ Examples
274
+ --------
275
+ The WKB wavefunction at the Bohr-Sommerfeld energy for quantum number
276
+ ``n`` has exactly ``n`` nodes, the standard node-counting theorem:
277
+
278
+ >>> import numpy as np
279
+ >>> V = lambda x: 0.5 * x ** 2
280
+ >>> E5 = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=6)[5]
281
+ >>> x = np.linspace(-10, 10, 4000)
282
+ >>> psi = wkb_wavefunction(x, E5, V, m=1.0)
283
+ >>> nonzero = psi[psi != 0]
284
+ >>> int(np.sum(np.diff(np.sign(nonzero)) != 0))
285
+ 5
286
+ """
287
+ x = np.asarray(x, dtype=float)
288
+ tp = turning_points(E, V, float(np.min(x)), float(np.max(x)))
289
+ x1, x2 = tp[0], tp[-1]
290
+ allowed = (x > x1) & (x < x2)
291
+
292
+ psi = np.zeros_like(x)
293
+ xa = x[allowed]
294
+ p = classical_momentum(E, V, xa, m)
295
+ order = np.argsort(xa)
296
+ xa_sorted = xa[order]
297
+ p_sorted = p[order]
298
+ phase_sorted = cumulative_trapezoid(p_sorted, xa_sorted, initial=0.0) / hbar
299
+ unsort = np.argsort(order)
300
+ phase = phase_sorted[unsort]
301
+
302
+ psi_allowed = np.cos(phase - np.pi / 4.0) / np.sqrt(p)
303
+ psi[allowed] = psi_allowed
304
+
305
+ norm = np.sqrt(trapz(psi**2, x))
306
+ if norm > 0:
307
+ psi = psi / norm
308
+ return psi
@@ -0,0 +1,13 @@
1
+ from physicskit.semiclassical.systems.scarring import (
2
+ bouncing_ball_energies,
3
+ bouncing_ball_orbit_points,
4
+ husimi_projection_1d,
5
+ scar_enhancement,
6
+ )
7
+
8
+ __all__ = [
9
+ "bouncing_ball_energies",
10
+ "bouncing_ball_orbit_points",
11
+ "scar_enhancement",
12
+ "husimi_projection_1d",
13
+ ]
@@ -0,0 +1,278 @@
1
+ r"""Quantum scars: eigenstate density concentrated on unstable classical periodic orbits.
2
+
3
+ Heller (1984) discovered that individual eigenstates of a classically
4
+ chaotic system are not always the featureless, ergodically-spread blobs
5
+ random-matrix intuition suggests: a small but robust fraction instead
6
+ show enhanced probability density in a tube around one particular
7
+ unstable classical periodic orbit -- a *scar* -- even though almost
8
+ every orbit nearby diverges from it exponentially fast. The bridge to
9
+ :mod:`physicskit.semiclassical.core.gutzwiller` is direct: the same
10
+ unstable periodic orbits that weight the Gutzwiller trace formula's
11
+ oscillating sum are exactly the orbits that scar individual eigenstates,
12
+ since eigenstates are (schematically) superpositions of trace-formula
13
+ terms.
14
+
15
+ :func:`bouncing_ball_energies` and :func:`bouncing_ball_orbit_points`
16
+ concern the single most famous scarred family in the Bunimovich stadium
17
+ billiard (:class:`physicskit.quantum.chapters.potentials.StadiumBilliard2D`):
18
+ the "bouncing ball" orbits bouncing straight up and down between the
19
+ flat top and bottom walls, which -- unlike a generic stadium orbit --
20
+ are only marginally unstable, so many low-lying eigenstates concentrate
21
+ along them. :func:`scar_enhancement` quantifies that concentration for
22
+ any eigenstate density, and :func:`husimi_projection_1d` builds a
23
+ non-periodic analog of :func:`physicskit.chaos.quantum.husimi.husimi_function`
24
+ for viewing a 1D wavefunction slice (e.g. along the billiard's flat
25
+ wall) in phase space.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import numpy as np
31
+
32
+ __all__ = [
33
+ "bouncing_ball_energies",
34
+ "bouncing_ball_orbit_points",
35
+ "scar_enhancement",
36
+ "husimi_projection_1d",
37
+ ]
38
+
39
+
40
+ def bouncing_ball_energies(R: float, hbar: float = 1.0, m: float = 1.0, n_max: int = 6) -> np.ndarray:
41
+ r"""Predicted energies of the "bouncing ball" orbit family in a stadium billiard of cap radius ``R``.
42
+
43
+ A trajectory launched perpendicular to the flat top and bottom walls
44
+ of a Bunimovich stadium (see
45
+ :class:`physicskit.quantum.chapters.potentials.StadiumBilliard2D`)
46
+ bounces straight up and down forever, blind to the length ``L`` of
47
+ the central rectangle -- exactly the motion of a particle in a 1D
48
+ infinite square well of width :math:`2R`. Quantizing that 1D motion
49
+ gives a leading-order prediction for where "bouncing ball" states
50
+ (eigenstates concentrated on this orbit family) appear in the full
51
+ 2D spectrum:
52
+
53
+ .. math::
54
+
55
+ E_n = \frac{(n\pi\hbar)^2}{2m(2R)^2}, \qquad n=1,2,3,\dots
56
+
57
+ Parameters
58
+ ----------
59
+ R : float
60
+ Radius of the stadium's semicircular end-caps (half-height of
61
+ the billiard).
62
+ hbar : float, default=1.0
63
+ Value of :math:`\hbar` to use.
64
+ m : float, default=1.0
65
+ Particle mass.
66
+ n_max : int, default=6
67
+ Number of levels to compute.
68
+
69
+ Returns
70
+ -------
71
+ ndarray, shape (n_max,)
72
+ Predicted bouncing-ball energies, ascending.
73
+
74
+ See Also
75
+ --------
76
+ bouncing_ball_orbit_points : The classical orbit these energies quantize.
77
+
78
+ Examples
79
+ --------
80
+ This is exactly the ordinary infinite-square-well spectrum for a
81
+ well of width :math:`2R`:
82
+
83
+ >>> import numpy as np
84
+ >>> R = 0.5
85
+ >>> energies = bouncing_ball_energies(R, n_max=3)
86
+ >>> exact = (np.arange(1, 4) * np.pi) ** 2 / (2 * (2 * R) ** 2)
87
+ >>> bool(np.allclose(energies, exact))
88
+ True
89
+ """
90
+ n = np.arange(1, n_max + 1)
91
+ return (n * np.pi * hbar) ** 2 / (2.0 * m * (2.0 * R) ** 2)
92
+
93
+
94
+ def bouncing_ball_orbit_points(x0: float, R: float, n_bounces: int = 4) -> tuple:
95
+ r"""Trace the classical "bouncing ball" orbit at horizontal position ``x0`` in a stadium billiard.
96
+
97
+ A perpendicular launch from the bottom wall at :math:`(x_0,-R)`
98
+ reflects straight back and forth off the flat top (:math:`y=R`) and
99
+ bottom (:math:`y=-R`) walls, tracing the same vertical segment
100
+ forever -- returned here as a zig-zag list of points suitable for
101
+ overlaying on a density plot.
102
+
103
+ Parameters
104
+ ----------
105
+ x0 : float
106
+ Horizontal position of the orbit, with :math:`|x_0| < L/2`
107
+ (strictly inside the flat central section of the stadium).
108
+ R : float
109
+ Radius of the stadium's semicircular end-caps.
110
+ n_bounces : int, default=4
111
+ Number of full up-down traversals to trace.
112
+
113
+ Returns
114
+ -------
115
+ x, y : ndarray
116
+ Coordinates tracing the orbit, shape ``(2 * n_bounces + 1,)``.
117
+
118
+ See Also
119
+ --------
120
+ bouncing_ball_energies : Quantized energies of this orbit family.
121
+
122
+ Examples
123
+ --------
124
+ >>> x, y = bouncing_ball_orbit_points(x0=0.2, R=0.5, n_bounces=2)
125
+ >>> x
126
+ array([0.2, 0.2, 0.2, 0.2, 0.2])
127
+ >>> y
128
+ array([-0.5, 0.5, -0.5, 0.5, -0.5])
129
+ """
130
+ y = np.array([-R if i % 2 == 0 else R for i in range(2 * n_bounces + 1)])
131
+ x = np.full_like(y, x0)
132
+ return x, y
133
+
134
+
135
+ def scar_enhancement(density: np.ndarray, X: np.ndarray, Y: np.ndarray, mask: np.ndarray, x0: float, half_width: float) -> float:
136
+ r"""Density enhancement in a tube around a vertical bouncing-ball orbit, relative to the billiard average.
137
+
138
+ .. math::
139
+
140
+ \eta = \frac{\langle|\psi|^2\rangle_{\text{tube}}}{\langle|\psi|^2\rangle_{\text{billiard}}},
141
+ \qquad \text{tube} = \{(x,y)\in\text{billiard} : |x-x_0|\le w\},
142
+
143
+ a simple, direct measure of scarring: :math:`\eta\approx1` for an
144
+ ergodically-spread (unscarred) state, since the tube then just
145
+ samples a representative fraction of the whole density, while
146
+ :math:`\eta\gg1` signals density piled up specifically along the
147
+ orbit at :math:`x_0`.
148
+
149
+ Parameters
150
+ ----------
151
+ density : ndarray
152
+ Probability density :math:`|\psi(x,y)|^2` on a grid.
153
+ X, Y : ndarray
154
+ Coordinate meshgrid matching ``density``.
155
+ mask : ndarray of bool
156
+ ``True`` inside the billiard (e.g. from
157
+ :meth:`physicskit.quantum.chapters.potentials.StadiumBilliard2D.mask`).
158
+ x0 : float
159
+ Horizontal position of the bouncing-ball orbit to test.
160
+ half_width : float
161
+ Half-width of the tube around ``x0``.
162
+
163
+ Returns
164
+ -------
165
+ float
166
+ The enhancement factor :math:`\eta`.
167
+
168
+ Examples
169
+ --------
170
+ A density sharply concentrated in a narrow ridge at ``x0`` is
171
+ strongly enhanced inside a tube covering that ridge:
172
+
173
+ >>> import numpy as np
174
+ >>> x = np.linspace(-2, 2, 400)
175
+ >>> y = np.linspace(-1, 1, 200)
176
+ >>> X, Y = np.meshgrid(x, y, indexing="ij")
177
+ >>> mask = np.ones_like(X, dtype=bool)
178
+ >>> density = np.exp(-(X - 0.3) ** 2 / (2 * 0.05 ** 2))
179
+ >>> eta = scar_enhancement(density, X, Y, mask, x0=0.3, half_width=0.15)
180
+ >>> bool(12.0 < eta < 14.0)
181
+ True
182
+
183
+ An (exactly) uniform density is not enhanced anywhere:
184
+
185
+ >>> uniform = np.ones_like(X)
186
+ >>> round(scar_enhancement(uniform, X, Y, mask, x0=0.3, half_width=0.15), 8)
187
+ 1.0
188
+ """
189
+ tube = mask & (np.abs(X - x0) <= half_width)
190
+ return float(np.mean(density[tube]) / np.mean(density[mask]))
191
+
192
+
193
+ def husimi_projection_1d(
194
+ psi: np.ndarray,
195
+ s: np.ndarray,
196
+ hbar: float = 1.0,
197
+ sigma: float | None = None,
198
+ resolution: int = 60,
199
+ s0_range: tuple | None = None,
200
+ p0_range: tuple | None = None,
201
+ ) -> tuple:
202
+ r"""Husimi (coherent-state) phase-space projection of a 1D wavefunction slice on an open interval.
203
+
204
+ The non-periodic counterpart of
205
+ :func:`physicskit.chaos.quantum.husimi.husimi_function`: overlaps
206
+ ``psi`` with ordinary (non-periodized) coherent states
207
+ :math:`g_{s_0,p_0}(s)=\exp[-(s-s_0)^2/2\sigma^2+ip_0(s-s_0)/\hbar]`
208
+ at every point of an :math:`(s_0,p_0)` grid, suited to a slice taken
209
+ along an open boundary -- e.g. the flat top wall of a stadium
210
+ billiard, where :func:`bouncing_ball_orbit_points` lives -- rather
211
+ than a periodic domain.
212
+
213
+ Parameters
214
+ ----------
215
+ psi : ndarray of complex
216
+ Wavefunction values sampled on ``s``.
217
+ s : ndarray
218
+ Uniform 1D coordinate grid ``psi`` is sampled on.
219
+ hbar : float, default=1.0
220
+ Value of :math:`\hbar` to use.
221
+ sigma : float, optional
222
+ Coherent-state position width. Defaults to :math:`\sqrt{\hbar}`
223
+ (the minimum-uncertainty, equal-spread-in-natural-units choice).
224
+ resolution : int, default=60
225
+ Number of grid points along each of the :math:`s_0`, :math:`p_0` axes.
226
+ s0_range : (float, float), optional
227
+ Range of :math:`s_0` to scan. Defaults to ``(s.min(), s.max())``.
228
+ p0_range : (float, float), optional
229
+ Range of :math:`p_0` to scan. Defaults to
230
+ :math:`\pm\pi\hbar/\Delta s` (the grid's Nyquist momentum).
231
+
232
+ Returns
233
+ -------
234
+ S0, P0 : ndarray, shape (resolution, resolution)
235
+ Phase-space grid (``indexing="ij"``).
236
+ husimi : ndarray, shape (resolution, resolution)
237
+ The Husimi distribution, normalized to a peak value of 1.
238
+
239
+ See Also
240
+ --------
241
+ scar_enhancement : A simpler, single-number scarring diagnostic in
242
+ position space rather than phase space.
243
+
244
+ Examples
245
+ --------
246
+ A Gaussian wave packet's Husimi projection peaks at its own
247
+ position and momentum:
248
+
249
+ >>> import numpy as np
250
+ >>> s = np.linspace(-10, 10, 2000)
251
+ >>> s0_true, p0_true, w = 2.0, 3.0, 1.0
252
+ >>> psi = np.exp(-(s - s0_true) ** 2 / (2 * w ** 2)) * np.exp(1j * p0_true * s / 1.0)
253
+ >>> S0, P0, H = husimi_projection_1d(psi, s, hbar=1.0, sigma=w, resolution=80, s0_range=(-2, 6), p0_range=(-2, 8))
254
+ >>> i, j = np.unravel_index(np.argmax(H), H.shape)
255
+ >>> bool(abs(S0[i, j] - s0_true) < 0.2 and abs(P0[i, j] - p0_true) < 0.2)
256
+ True
257
+ """
258
+ s = np.asarray(s, dtype=float)
259
+ ds = s[1] - s[0]
260
+ if sigma is None:
261
+ sigma = np.sqrt(hbar)
262
+ if s0_range is None:
263
+ s0_range = (float(s.min()), float(s.max()))
264
+ if p0_range is None:
265
+ p_max = np.pi * hbar / ds
266
+ p0_range = (-p_max, p_max)
267
+
268
+ s0 = np.linspace(s0_range[0], s0_range[1], resolution)
269
+ p0 = np.linspace(p0_range[0], p0_range[1], resolution)
270
+ S0, P0 = np.meshgrid(s0, p0, indexing="ij")
271
+
272
+ ds_grid = s[None, None, :] - S0[:, :, None]
273
+ coherent = np.exp(-(ds_grid**2) / (2.0 * sigma**2) + 1j * P0[:, :, None] * ds_grid / hbar)
274
+ overlap = np.tensordot(np.conj(coherent), psi, axes=([2], [0])) * ds
275
+
276
+ husimi = np.abs(overlap) ** 2
277
+ husimi /= husimi.max()
278
+ return S0, P0, husimi
File without changes
@@ -0,0 +1,35 @@
1
+ """Physics-correctness tests for physicskit.semiclassical.core.gutzwiller."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+ import pytest
7
+ from scipy.signal import find_peaks
8
+
9
+ from physicskit.semiclassical.core.gutzwiller import (
10
+ classical_period,
11
+ gutzwiller_amplitude_from_monodromy,
12
+ gutzwiller_density_of_states,
13
+ )
14
+ from physicskit.semiclassical.core.wkb import bohr_sommerfeld_energies
15
+
16
+
17
+ @pytest.mark.slow
18
+ def test_gutzwiller_trace_formula_peaks_match_bohr_sommerfeld_spectrum():
19
+ V = lambda x: 0.5 * x**2
20
+ E_grid = np.linspace(0.2, 4.5, 200)
21
+ dos = gutzwiller_density_of_states(E_grid, V, m=1.0, x_min=-20, x_max=20)
22
+ peak_idx, _ = find_peaks(dos, height=0.3 * dos.max())
23
+ exact = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=4)
24
+ assert np.allclose(E_grid[peak_idx], exact, atol=0.05)
25
+
26
+
27
+ def test_classical_period_matches_harmonic_oscillator():
28
+ V = lambda x: 0.5 * x**2
29
+ T = classical_period(E=3.0, V=V, m=1.0, x_min=-20, x_max=20)
30
+ assert abs(T - 2 * np.pi) < 1e-4
31
+
32
+
33
+ def test_gutzwiller_amplitude_from_monodromy():
34
+ M = np.array([[2.0, 0.0], [0.0, 0.5]])
35
+ assert abs(gutzwiller_amplitude_from_monodromy(M) - 1.0 / np.sqrt(0.5)) < 1e-10