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,194 @@
1
+ """Physics-correctness tests for physicskit.semiclassical.core.path_integral."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+ import pytest
7
+
8
+ from physicskit.semiclassical.core.path_integral import (
9
+ build_phasor_diagram,
10
+ discretized_action,
11
+ feynman_phasor_partial_sums,
12
+ free_particle_classical_action,
13
+ free_particle_classical_path,
14
+ harmonic_oscillator_classical_action,
15
+ harmonic_oscillator_classical_path,
16
+ sample_random_paths,
17
+ )
18
+
19
+
20
+ def test_discretized_action_matches_free_particle_closed_form_exactly():
21
+ # The free-particle classical path is a straight line, so the midpoint-rule
22
+ # discretization is exact (constant velocity, zero potential) for any n_slices.
23
+ x0, xf, T, m = 0.0, 2.0, 1.0, 1.0
24
+ _, x = free_particle_classical_path(x0, xf, T, m, n_slices=200)
25
+ S_discrete = discretized_action(x, dt=T / 200, m=m, V=lambda x: 0.0 * x)
26
+ S_exact = free_particle_classical_action(x0, xf, T, m)
27
+ assert S_discrete == pytest.approx(S_exact, rel=1e-10)
28
+
29
+
30
+ def test_discretized_action_converges_to_harmonic_oscillator_closed_form():
31
+ # Unlike the free particle, the classical path here is curved, so the midpoint
32
+ # rule has O(dt^2) discretization error. At n_slices=200 the achieved relative
33
+ # error is ~2.5e-4 (checked empirically), well inside the 1% tolerance used here.
34
+ x0, xf, T, m, omega = 0.3, -0.7, 2.3, 1.0, 1.1
35
+ n_slices = 200
36
+ _, x = harmonic_oscillator_classical_path(x0, xf, T, m, omega, n_slices)
37
+ V = lambda x: 0.5 * m * omega**2 * x**2
38
+ S_discrete = discretized_action(x, dt=T / n_slices, m=m, V=V)
39
+ S_exact = harmonic_oscillator_classical_action(x0, xf, T, m, omega)
40
+ assert S_discrete == pytest.approx(S_exact, rel=1e-2)
41
+
42
+
43
+ def test_free_particle_classical_path_minimizes_action_among_random_paths():
44
+ # For a free particle the classical (straight-line) path is a true minimum of
45
+ # the action, not merely a stationary point, so every randomly sampled path
46
+ # must have action >= the classical action (within numerical tolerance).
47
+ x0, xf, T, m, n_slices = 0.0, 1.5, 1.0, 1.0, 40
48
+ S_cl = free_particle_classical_action(x0, xf, T, m)
49
+ paths = sample_random_paths(x0, xf, T, n_slices, n_paths=50, sigma=0.4, seed=1)
50
+ dt = T / n_slices
51
+ actions = np.array([discretized_action(p, dt, m, lambda x: 0.0 * x) for p in paths])
52
+ assert np.all(actions >= S_cl - 1e-8)
53
+
54
+
55
+ def test_harmonic_oscillator_classical_action_closer_than_random_perturbation():
56
+ # Unlike the free particle, the harmonic-oscillator classical path is only a
57
+ # stationary point of the action (not necessarily a minimum), so we only check
58
+ # that it is closer to the exact classical action than a randomly perturbed
59
+ # path -- a weaker but still meaningful sanity check.
60
+ x0, xf, T, m, omega, n_slices = 0.2, 0.8, 1.0, 1.0, 1.3, 60
61
+ S_cl = harmonic_oscillator_classical_action(x0, xf, T, m, omega)
62
+ _, x_cl = harmonic_oscillator_classical_path(x0, xf, T, m, omega, n_slices)
63
+ V = lambda x: 0.5 * m * omega**2 * x**2
64
+ dt = T / n_slices
65
+ S_cl_discrete = discretized_action(x_cl, dt, m, V)
66
+
67
+ random_paths = sample_random_paths(x0, xf, T, n_slices, n_paths=1, sigma=0.5, seed=3)
68
+ S_random = discretized_action(random_paths[0], dt, m, V)
69
+
70
+ assert abs(S_cl_discrete - S_cl) < abs(S_random - S_cl)
71
+
72
+
73
+ @pytest.mark.parametrize(
74
+ "target,func,kwargs",
75
+ [
76
+ ("path", harmonic_oscillator_classical_path, dict(x0=0.0, xf=1.0, m=1.0, omega=1.0, n_slices=10)),
77
+ ("action", harmonic_oscillator_classical_action, dict(x0=0.0, xf=1.0, m=1.0, omega=1.0)),
78
+ ],
79
+ )
80
+ def test_harmonic_oscillator_raises_at_conjugate_point(target, func, kwargs):
81
+ # omega*T = pi exactly is a conjugate point: the classical path is non-unique.
82
+ T = np.pi / kwargs["omega"]
83
+ with pytest.raises(ValueError):
84
+ func(T=T, **kwargs)
85
+
86
+
87
+ def test_feynman_phasor_partial_sums_matches_hand_computation():
88
+ actions = np.array([0.3, -1.2, 5.0, 0.0])
89
+ hbar = 0.5
90
+ classical_action = 0.1
91
+ paths = np.zeros((actions.shape[0], 3)) # only shape[0] is used by the function
92
+
93
+ partial = feynman_phasor_partial_sums(paths, actions, hbar, classical_action=classical_action)
94
+
95
+ # Independent hand computation: sort by |action - classical_action| ascending,
96
+ # then cumulatively sum exp(i*action/hbar) in that order, starting from 0.
97
+ order = np.argsort(np.abs(actions - classical_action))
98
+ expected = np.concatenate([[0.0 + 0.0j], np.cumsum(np.exp(1j * actions[order] / hbar))])
99
+
100
+ assert np.allclose(partial, expected)
101
+ assert partial.shape == (actions.shape[0] + 1,)
102
+ assert partial[0] == 0.0
103
+
104
+
105
+ def test_phasor_sum_concentrates_near_classical_path_as_hbar_shrinks():
106
+ # The core physics claim of this module: shrinking hbar makes the propagator's
107
+ # support concentrate ever more tightly around the classical path. Quantify
108
+ # this by comparing, at two very different hbar values, what fraction of the
109
+ # final (all-paths) partial-sum magnitude is already captured by just the
110
+ # closest 10% of paths (sorted by proximity to the classical action).
111
+ def frac_from_closest_10_percent(hbar, seed):
112
+ _, _, _, _, partial = build_phasor_diagram(
113
+ x0=0.0,
114
+ xf=1.0,
115
+ T=1.0,
116
+ m=1.0,
117
+ hbar=hbar,
118
+ potential="free",
119
+ n_slices=40,
120
+ n_paths=400,
121
+ sigma=0.5,
122
+ seed=seed,
123
+ )
124
+ n_total = partial.shape[0] - 1
125
+ idx = max(1, round(0.1 * n_total))
126
+ return abs(partial[idx]) / abs(partial[-1])
127
+
128
+ # hbar=20 is much larger than the typical |S - S_cl| spread of this ensemble
129
+ # (tens at most), so phases barely wind and the closest 10% contributes about
130
+ # the "trivial" 10% share. hbar=1.0 is much smaller than that spread, so the
131
+ # closest paths reinforce while distant ones increasingly cancel.
132
+ large_hbar, small_hbar = 20.0, 1.0
133
+ seed = 42
134
+
135
+ frac_large = frac_from_closest_10_percent(large_hbar, seed)
136
+ frac_small = frac_from_closest_10_percent(small_hbar, seed)
137
+
138
+ assert frac_small > frac_large
139
+
140
+
141
+ def test_free_particle_functions_reject_nonpositive_t_and_bad_n_slices():
142
+ with pytest.raises(ValueError):
143
+ free_particle_classical_path(x0=0.0, xf=1.0, T=0.0, m=1.0, n_slices=4)
144
+ with pytest.raises(ValueError):
145
+ free_particle_classical_path(x0=0.0, xf=1.0, T=1.0, m=1.0, n_slices=0)
146
+ with pytest.raises(ValueError):
147
+ free_particle_classical_action(x0=0.0, xf=1.0, T=0.0, m=1.0)
148
+
149
+
150
+ def test_harmonic_oscillator_functions_reject_nonpositive_t_and_bad_n_slices():
151
+ with pytest.raises(ValueError):
152
+ harmonic_oscillator_classical_path(x0=0.0, xf=1.0, T=0.0, m=1.0, omega=1.0, n_slices=4)
153
+ with pytest.raises(ValueError):
154
+ harmonic_oscillator_classical_path(x0=0.0, xf=1.0, T=1.0, m=1.0, omega=1.0, n_slices=0)
155
+ with pytest.raises(ValueError):
156
+ harmonic_oscillator_classical_action(x0=0.0, xf=1.0, T=0.0, m=1.0, omega=1.0)
157
+
158
+
159
+ def test_sample_random_paths_rejects_nonpositive_t_and_bad_counts():
160
+ with pytest.raises(ValueError):
161
+ sample_random_paths(x0=0.0, xf=1.0, T=0.0, n_slices=4, n_paths=2, sigma=0.1, seed=0)
162
+ with pytest.raises(ValueError):
163
+ sample_random_paths(x0=0.0, xf=1.0, T=1.0, n_slices=0, n_paths=2, sigma=0.1, seed=0)
164
+ with pytest.raises(ValueError):
165
+ sample_random_paths(x0=0.0, xf=1.0, T=1.0, n_slices=4, n_paths=0, sigma=0.1, seed=0)
166
+
167
+
168
+ def test_feynman_phasor_partial_sums_rejects_empty_actions_and_zero_hbar():
169
+ with pytest.raises(ValueError):
170
+ feynman_phasor_partial_sums(paths=np.empty((0, 1)), actions=np.array([]), hbar=0.5)
171
+ with pytest.raises(ValueError):
172
+ feynman_phasor_partial_sums(paths=np.zeros((2, 1)), actions=np.array([0.1, 0.2]), hbar=0.0)
173
+
174
+
175
+ def test_build_phasor_diagram_harmonic_potential_matches_classical_path_and_action():
176
+ omega = 1.5
177
+ paths, actions, x_cl, S_cl, partial = build_phasor_diagram(
178
+ x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.1, potential="harmonic", omega=omega, n_slices=10, n_paths=5, sigma=0.1, seed=0
179
+ )
180
+ expected_path = harmonic_oscillator_classical_path(x0=0.0, xf=1.0, T=1.0, m=1.0, omega=omega, n_slices=10)[1]
181
+ expected_action = harmonic_oscillator_classical_action(x0=0.0, xf=1.0, T=1.0, m=1.0, omega=omega)
182
+ assert np.allclose(x_cl, expected_path)
183
+ assert S_cl == pytest.approx(expected_action)
184
+ assert paths.shape[0] == actions.shape[0] == 6
185
+ assert partial.shape == (7,)
186
+
187
+
188
+ def test_build_phasor_diagram_rejects_nonpositive_t_missing_omega_and_bad_potential():
189
+ with pytest.raises(ValueError):
190
+ build_phasor_diagram(x0=0.0, xf=1.0, T=0.0, m=1.0, hbar=0.1, potential="free", n_slices=10, n_paths=5, sigma=0.1, seed=0)
191
+ with pytest.raises(ValueError):
192
+ build_phasor_diagram(x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.1, potential="harmonic", n_slices=10, n_paths=5, sigma=0.1, seed=0)
193
+ with pytest.raises(ValueError):
194
+ build_phasor_diagram(x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.1, potential="quartic", n_slices=10, n_paths=5, sigma=0.1, seed=0)
@@ -0,0 +1,82 @@
1
+ """Physics-correctness tests for physicskit.semiclassical.core.propagators."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+ from numba import njit
7
+
8
+ from physicskit.semiclassical.core.propagators import (
9
+ coherent_state_overlap,
10
+ frozen_gaussian_1d,
11
+ herman_kluk_propagate_wavepacket,
12
+ propagate_trajectory_monodromy_action,
13
+ van_vleck_propagator_1d,
14
+ )
15
+
16
+ _ZERO = njit(lambda q, params: 0.0, cache=False)
17
+
18
+
19
+ def _harmonic_potential(m=1.0, omega=1.0):
20
+ params = np.array([m * omega**2])
21
+ dVdx = njit(lambda q, params: params[0] * q, cache=False)
22
+ d2Vdx2 = njit(lambda q, params: params[0], cache=False)
23
+ V = njit(lambda q, params: 0.5 * params[0] * q**2, cache=False)
24
+ return dVdx, d2Vdx2, V, params
25
+
26
+
27
+ def test_monodromy_matches_harmonic_oscillator_and_preserves_liouville():
28
+ dVdx, d2Vdx2, V, params = _harmonic_potential()
29
+ t = 2.1
30
+ _q, _p, M, _S, _hist = propagate_trajectory_monodromy_action(1.0, 0.4, dVdx, d2Vdx2, V, m=1.0, dt=t / 3000, steps=3000, params=params)
31
+ M_exact = np.array([[np.cos(t), np.sin(t)], [-np.sin(t), np.cos(t)]])
32
+ assert np.max(np.abs(M - M_exact)) < 1e-5
33
+ assert abs(np.linalg.det(M) - 1.0) < 1e-8
34
+
35
+
36
+ def test_van_vleck_propagator_matches_free_particle_exact():
37
+ q_t, K = van_vleck_propagator_1d(q0=0.0, p0=1.0, dVdx=_ZERO, d2Vdx2=_ZERO, V=_ZERO, m=1.0, dt=1.0 / 2000, steps=2000)
38
+ K_exact = np.sqrt(1.0 / (2j * np.pi)) * np.exp(1j * q_t**2 / 2.0)
39
+ assert abs(K - K_exact) < 1e-6
40
+
41
+
42
+ def test_van_vleck_propagator_matches_harmonic_oscillator_exact():
43
+ dVdx, d2Vdx2, V, params = _harmonic_potential()
44
+ q0, p0, t = 1.0, 0.3, 1.3
45
+ q_t, K = van_vleck_propagator_1d(q0, p0, dVdx, d2Vdx2, V, m=1.0, dt=t / 4000, steps=4000, hbar=1.0, params=params)
46
+ K_exact = np.sqrt(1.0 / (2j * np.pi * np.sin(t))) * np.exp(1j / (2 * np.sin(t)) * ((q_t**2 + q0**2) * np.cos(t) - 2 * q_t * q0))
47
+ assert abs(K - K_exact) < 1e-5
48
+
49
+
50
+ def test_coherent_state_overlap_matches_numerical_integration():
51
+ x = np.linspace(-40, 40, 20000)
52
+ gamma = 1.0
53
+ psi1 = frozen_gaussian_1d(x, qc=0.3, pc=0.7, gamma=gamma)
54
+ psi2 = frozen_gaussian_1d(x, qc=-0.2, pc=1.1, gamma=gamma)
55
+ numeric = np.trapezoid(np.conj(psi1) * psi2, x)
56
+ closed_form = coherent_state_overlap(0.3, 0.7, -0.2, 1.1, gamma)
57
+ assert abs(numeric - closed_form) < 1e-6
58
+
59
+
60
+ def test_herman_kluk_reconstructs_initial_state_at_short_time():
61
+ dVdx, d2Vdx2, V, params = _harmonic_potential()
62
+ x = np.linspace(-6, 6, 400)
63
+ psi = herman_kluk_propagate_wavepacket(
64
+ 1.0, 0.0, gamma=1.0, dVdx=dVdx, d2Vdx2=d2Vdx2, V=V, m=1.0, dt=1e-6, steps=1, x_eval=x, n_grid=61, n_sigma=7.0, params=params
65
+ )
66
+ psi0 = frozen_gaussian_1d(x, qc=1.0, pc=0.0, gamma=1.0)
67
+ fidelity = abs(np.trapezoid(np.conj(psi0) * psi, x)) ** 2
68
+ assert fidelity > 0.999
69
+
70
+
71
+ def test_herman_kluk_defaults_params_to_an_empty_array_when_unused():
72
+ # dVdx/d2Vdx2/V here never index into params, so params=None (->
73
+ # np.empty(0) internally) is fine and should behave like the
74
+ # explicit-params harmonic oscillator above (m=omega=1).
75
+ dVdx = njit(lambda q, params: q, cache=False)
76
+ d2Vdx2 = njit(lambda q, params: 1.0, cache=False)
77
+ V = njit(lambda q, params: 0.5 * q**2, cache=False)
78
+ x = np.linspace(-6, 6, 400)
79
+ psi = herman_kluk_propagate_wavepacket(1.0, 0.0, gamma=1.0, dVdx=dVdx, d2Vdx2=d2Vdx2, V=V, m=1.0, dt=1e-6, steps=1, x_eval=x, n_grid=61, n_sigma=7.0)
80
+ psi0 = frozen_gaussian_1d(x, qc=1.0, pc=0.0, gamma=1.0)
81
+ fidelity = abs(np.trapezoid(np.conj(psi0) * psi, x)) ** 2
82
+ assert fidelity > 0.999
@@ -0,0 +1,43 @@
1
+ """Physics-correctness tests for physicskit.semiclassical.systems.scarring."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+
7
+ from physicskit.semiclassical.systems.scarring import bouncing_ball_energies, husimi_projection_1d, scar_enhancement
8
+
9
+
10
+ def test_bouncing_ball_energies_match_infinite_well_of_width_2R():
11
+ R = 0.7
12
+ energies = bouncing_ball_energies(R, n_max=4)
13
+ exact = (np.arange(1, 5) * np.pi) ** 2 / (2 * (2 * R) ** 2)
14
+ assert np.allclose(energies, exact)
15
+
16
+
17
+ def test_scar_enhancement_of_uniform_density_is_one():
18
+ x = np.linspace(-2, 2, 200)
19
+ y = np.linspace(-1, 1, 100)
20
+ X, Y = np.meshgrid(x, y, indexing="ij")
21
+ mask = np.ones_like(X, dtype=bool)
22
+ uniform = np.ones_like(X)
23
+ eta = scar_enhancement(uniform, X, Y, mask, x0=0.3, half_width=0.2)
24
+ assert abs(eta - 1.0) < 1e-10
25
+
26
+
27
+ def test_scar_enhancement_detects_concentrated_ridge():
28
+ x = np.linspace(-2, 2, 400)
29
+ y = np.linspace(-1, 1, 200)
30
+ X, Y = np.meshgrid(x, y, indexing="ij")
31
+ mask = np.ones_like(X, dtype=bool)
32
+ density = np.exp(-((X - 0.3) ** 2) / (2 * 0.05**2))
33
+ eta = scar_enhancement(density, X, Y, mask, x0=0.3, half_width=0.15)
34
+ assert eta > 5.0
35
+
36
+
37
+ def test_husimi_projection_1d_default_sigma_and_ranges_peaks_near_source():
38
+ s = np.linspace(-10, 10, 500)
39
+ s0_true, p0_true, w = 2.0, 3.0, 1.0
40
+ psi = np.exp(-((s - s0_true) ** 2) / (2 * w**2)) * np.exp(1j * p0_true * s / 1.0)
41
+ S0, P0, H = husimi_projection_1d(psi, s, hbar=1.0, resolution=30)
42
+ i, j = np.unravel_index(np.argmax(H), H.shape)
43
+ assert abs(S0[i, j] - s0_true) < 1.0
@@ -0,0 +1,89 @@
1
+ """Coverage for physicskit.semiclassical.visualizers's ax=<given> branch
2
+ (previously untested for every function here): plot_density_of_states,
3
+ plot_wkb_wavefunction, plot_classical_trajectory_on_wigner, plot_scar_map,
4
+ plot_husimi_1d. All pure matplotlib, small inputs -- fast."""
5
+
6
+ from __future__ import annotations
7
+
8
+ import matplotlib.pyplot as plt
9
+ import numpy as np
10
+
11
+ from physicskit.semiclassical.core.gutzwiller import gutzwiller_density_of_states
12
+ from physicskit.semiclassical.core.path_integral import build_phasor_diagram
13
+ from physicskit.semiclassical.core.propagators import frozen_gaussian_1d
14
+ from physicskit.semiclassical.core.wkb import bohr_sommerfeld_energies, wkb_wavefunction
15
+ from physicskit.semiclassical.systems.scarring import bouncing_ball_orbit_points, husimi_projection_1d
16
+ from physicskit.semiclassical.visualizers.gutzwiller import plot_density_of_states
17
+ from physicskit.semiclassical.visualizers.path_integral import animate_feynman_phasor_spiral, plot_phasor_convergence
18
+ from physicskit.semiclassical.visualizers.propagators import plot_classical_trajectory_on_wigner
19
+ from physicskit.semiclassical.visualizers.scarring import plot_husimi_1d, plot_scar_map
20
+ from physicskit.semiclassical.visualizers.wkb import plot_wkb_wavefunction
21
+
22
+
23
+ def test_plot_density_of_states_given_ax():
24
+ V = lambda x: 0.5 * x**2
25
+ E_grid = np.linspace(0.2, 3.5, 50)
26
+ dos = gutzwiller_density_of_states(E_grid, V, m=1.0, x_min=-20, x_max=20)
27
+ fig, ax = plt.subplots()
28
+ _, ax_given = plot_density_of_states(E_grid, dos, ax=ax)
29
+ assert ax_given is ax
30
+
31
+
32
+ def test_plot_wkb_wavefunction_given_ax():
33
+ V = lambda x: 0.5 * x**2
34
+ E2 = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=3)[2]
35
+ x = np.linspace(-6, 6, 200)
36
+ psi = wkb_wavefunction(x, E2, V)
37
+ fig, ax = plt.subplots()
38
+ _, ax_given = plot_wkb_wavefunction(x, psi, V=V, ax=ax)
39
+ assert ax_given is ax
40
+
41
+
42
+ def test_plot_classical_trajectory_on_wigner_given_ax():
43
+ x = np.linspace(-8, 8, 100)
44
+ psi = frozen_gaussian_1d(x, qc=1.0, pc=0.5, gamma=1.0)
45
+ theta = np.linspace(0, 2 * np.pi, 30)
46
+ q_hist, p_hist = np.cos(theta), np.sin(theta)
47
+ fig, ax = plt.subplots()
48
+ _, ax_given = plot_classical_trajectory_on_wigner(x, psi, q_hist, p_hist, ax=ax)
49
+ assert ax_given is ax
50
+
51
+
52
+ def test_plot_scar_map_given_ax():
53
+ x = np.linspace(-2, 2, 30)
54
+ y = np.linspace(-1, 1, 20)
55
+ X, Y = np.meshgrid(x, y, indexing="ij")
56
+ density = np.exp(-((X - 0.3) ** 2) / (2 * 0.2**2))
57
+ orbit_x, orbit_y = bouncing_ball_orbit_points(x0=0.3, R=1.0)
58
+ fig, ax = plt.subplots()
59
+ _, ax_given = plot_scar_map(X, Y, density, orbit_x=orbit_x, orbit_y=orbit_y, ax=ax)
60
+ assert ax_given is ax
61
+
62
+
63
+ def test_plot_husimi_1d_given_ax():
64
+ s = np.linspace(-10, 10, 200)
65
+ psi = np.exp(-((s - 2.0) ** 2) / 2.0) * np.exp(1j * 3.0 * s)
66
+ S0, P0, H = husimi_projection_1d(psi, s, sigma=1.0, resolution=20, s0_range=(-2, 6), p0_range=(-2, 8))
67
+ fig, ax = plt.subplots()
68
+ _, ax_given = plot_husimi_1d(S0, P0, H, ax=ax)
69
+ assert ax_given is ax
70
+
71
+
72
+ def test_animate_feynman_phasor_spiral_builds_and_draws_a_frame():
73
+ paths, actions, x_cl, S_cl, _ = build_phasor_diagram(x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.1, potential="free", n_slices=20, n_paths=10, sigma=0.3, seed=0)
74
+ t = np.linspace(0.0, 1.0, x_cl.shape[0])
75
+ anim = animate_feynman_phasor_spiral(paths, actions, x_cl, S_cl, hbar=0.1, t_array=t)
76
+ anim._init_draw()
77
+ anim._draw_frame(0)
78
+ anim._draw_frame(1) # a second frame exercises removing the previous frame's path lines
79
+ assert "2/" in anim._fig.axes[1].get_title()
80
+
81
+
82
+ def test_plot_phasor_convergence_given_ax():
83
+ sums, hbars = [], [0.5, 0.05]
84
+ for hbar in hbars:
85
+ _, _, _, _, partial = build_phasor_diagram(x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=hbar, potential="free", n_slices=10, n_paths=20, sigma=0.3, seed=0)
86
+ sums.append(partial)
87
+ fig, ax = plt.subplots()
88
+ _, ax_given = plot_phasor_convergence(sums, hbars, ax=ax)
89
+ assert ax_given is ax
@@ -0,0 +1,30 @@
1
+ """Physics-correctness tests for physicskit.semiclassical.core.wkb."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+
7
+ from physicskit.semiclassical.core.wkb import bohr_sommerfeld_energies, turning_points, wkb_wavefunction
8
+
9
+
10
+ def test_bohr_sommerfeld_matches_harmonic_oscillator_exact_spectrum():
11
+ V = lambda x: 0.5 * x**2
12
+ energies = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=6)
13
+ assert np.allclose(energies, np.arange(6) + 0.5, atol=1e-8)
14
+
15
+
16
+ def test_turning_points_finds_root_landing_exactly_on_a_search_grid_point():
17
+ # n_search=3 puts a grid point exactly at x=0, where E - V(x) = 0 - 0 = 0.
18
+ roots = turning_points(E=0.0, V=lambda x: x, x_min=-1.0, x_max=1.0, n_search=3)
19
+ assert roots == [0.0]
20
+
21
+
22
+ def test_wkb_wavefunction_has_n_nodes():
23
+ V = lambda x: 0.5 * x**2
24
+ for n in range(4):
25
+ E_n = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=n + 1)[n]
26
+ x = np.linspace(-10, 10, 4000)
27
+ psi = wkb_wavefunction(x, E_n, V, m=1.0)
28
+ nonzero = psi[psi != 0]
29
+ n_nodes = np.sum(np.diff(np.sign(nonzero)) != 0)
30
+ assert n_nodes == n
@@ -0,0 +1,17 @@
1
+ from physicskit.semiclassical.visualizers.gutzwiller import plot_density_of_states
2
+ from physicskit.semiclassical.visualizers.propagators import plot_classical_trajectory_on_wigner
3
+ from physicskit.semiclassical.visualizers.scarring import (
4
+ plot_husimi_1d,
5
+ plot_scar_map,
6
+ plot_scar_map_interactive,
7
+ )
8
+ from physicskit.semiclassical.visualizers.wkb import plot_wkb_wavefunction
9
+
10
+ __all__ = [
11
+ "plot_wkb_wavefunction",
12
+ "plot_classical_trajectory_on_wigner",
13
+ "plot_density_of_states",
14
+ "plot_scar_map",
15
+ "plot_husimi_1d",
16
+ "plot_scar_map_interactive",
17
+ ]
@@ -0,0 +1,55 @@
1
+ r"""Plotting helpers for the Gutzwiller trace-formula density of states."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+
8
+ __all__ = ["plot_density_of_states"]
9
+
10
+
11
+ def plot_density_of_states(E_grid: np.ndarray, dos: np.ndarray, exact_energies: np.ndarray | None = None, ax=None):
12
+ r"""Plot the Gutzwiller trace-formula density of states, with exact levels marked.
13
+
14
+ Parameters
15
+ ----------
16
+ E_grid : ndarray
17
+ Energy grid.
18
+ dos : ndarray
19
+ Density of states, e.g. from
20
+ :func:`physicskit.semiclassical.core.gutzwiller.gutzwiller_density_of_states`.
21
+ exact_energies : ndarray, optional
22
+ Exact (or Bohr-Sommerfeld) energy levels to mark with vertical
23
+ dashed lines.
24
+ ax : matplotlib.axes.Axes, optional
25
+ Axes to draw into; a new figure is created if omitted.
26
+
27
+ Returns
28
+ -------
29
+ fig : matplotlib.figure.Figure
30
+ ax : matplotlib.axes.Axes
31
+
32
+ Examples
33
+ --------
34
+ >>> import numpy as np
35
+ >>> from physicskit.semiclassical.core.gutzwiller import gutzwiller_density_of_states
36
+ >>> from physicskit.semiclassical.core.wkb import bohr_sommerfeld_energies
37
+ >>> V = lambda x: 0.5 * x ** 2
38
+ >>> E_grid = np.linspace(0.2, 3.5, 200)
39
+ >>> dos = gutzwiller_density_of_states(E_grid, V, m=1.0, x_min=-20, x_max=20)
40
+ >>> energies = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=3)
41
+ >>> fig, ax = plot_density_of_states(E_grid, dos, exact_energies=energies)
42
+ >>> isinstance(fig, plt.Figure)
43
+ True
44
+ """
45
+ if ax is None:
46
+ fig, ax = plt.subplots()
47
+ else:
48
+ fig = ax.figure
49
+ ax.plot(E_grid, dos, color="C0")
50
+ if exact_energies is not None:
51
+ for E_n in exact_energies:
52
+ ax.axvline(E_n, color="C3", linestyle="--", linewidth=0.8)
53
+ ax.set_xlabel("E")
54
+ ax.set_ylabel("g(E)")
55
+ return fig, ax