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,133 @@
1
+ """Poincare sections and boundary phase-space (s, sin phi) plots for billiards."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, cast
6
+
7
+ import matplotlib.pyplot as plt
8
+ import numpy as np
9
+ from matplotlib.axes import Axes
10
+ from matplotlib.figure import Figure
11
+ from numpy.typing import ArrayLike
12
+
13
+ from physicskit.chaos.core.base_system import BilliardSystem
14
+ from physicskit.chaos.visualizers import theme
15
+
16
+
17
+ def plot_poincare_section(
18
+ billiard: BilliardSystem,
19
+ n_rays: int = 50,
20
+ n_bounces: int = 200,
21
+ pos: ArrayLike | None = None,
22
+ ax: Axes | None = None,
23
+ seed: int | None = None,
24
+ **scatter_kwargs: Any,
25
+ ) -> tuple[Figure, Axes]:
26
+ """Scatter-plot the boundary phase space ``(s, sin(phi))`` of a billiard.
27
+
28
+ Launches `n_rays` trajectories from an interior point at random angles
29
+ and collects `n_bounces` reflections from each, pooling all the resulting
30
+ boundary hits into one Poincare section. Integrable billiards (Circle,
31
+ Rectangle) trace out smooth invariant curves; chaotic (defocusing)
32
+ billiards (Sinai, Stadium) fill the section with a dense chaotic sea.
33
+ Rays are traced in a single call to
34
+ :meth:`~physicskit.chaos.systems.billiards._RayTracingBilliard.simulate_many_rays`,
35
+ which parallelizes across rays internally (Numba ``prange``).
36
+
37
+ Parameters
38
+ ----------
39
+ billiard : BilliardSystem
40
+ Billiard to sample.
41
+ n_rays : int, default 50
42
+ Number of independent trajectories to launch.
43
+ n_bounces : int, default 200
44
+ Number of reflections to trace per trajectory.
45
+ pos : array_like of float, shape (2,), optional
46
+ Shared launch position ``(x, y)`` for every ray; defaults to
47
+ ``billiard.sample_interior_point()``. Worth overriding for a billiard
48
+ whose default interior point is a point of special symmetry -- e.g.
49
+ :class:`~physicskit.chaos.systems.billiards.CircleBilliard`'s is its exact
50
+ center, from which *every* ray hits the boundary head-on
51
+ (``sin(phi) = 0``), collapsing the whole section onto a single line
52
+ instead of the family of invariant curves an off-center point traces
53
+ out.
54
+ ax : matplotlib.axes.Axes, optional
55
+ Axes to draw into; a new figure and axes are created if omitted.
56
+ seed : int, optional
57
+ Seed for the random angle generator, for reproducibility.
58
+ **scatter_kwargs
59
+ Additional keyword arguments forwarded to ``ax.scatter``.
60
+
61
+ Returns
62
+ -------
63
+ fig : matplotlib.figure.Figure
64
+ ax : matplotlib.axes.Axes
65
+ """
66
+ rng = np.random.default_rng(seed)
67
+ interior = billiard.sample_interior_point() if pos is None else np.asarray(pos, dtype=np.float64)
68
+ angles = rng.uniform(0.0, 2.0 * np.pi, size=n_rays)
69
+ result = billiard.simulate_many_rays(interior, angles, n_bounces)
70
+ s, sin_phi = result["s"], result["sin_phi"]
71
+
72
+ if ax is None:
73
+ fig, ax = plt.subplots(figsize=(7, 5))
74
+ else:
75
+ fig = cast(Figure, ax.figure)
76
+
77
+ kwargs: dict[str, Any] = {"s": 0.6, "c": theme.PRIMARY, "alpha": 0.6}
78
+ kwargs.update(scatter_kwargs)
79
+ ax.scatter(s, sin_phi, **kwargs)
80
+ ax.set_xlim(0.0, billiard.perimeter())
81
+ ax.set_ylim(-1.0, 1.0)
82
+ ax.set_xlabel("s (boundary arclength)")
83
+ ax.set_ylabel(r"$\sin\varphi$")
84
+ ax.set_title(f"{billiard.__class__.__name__} Poincare section")
85
+ return fig, ax
86
+
87
+
88
+ def plot_billiard_trajectory(
89
+ billiard: BilliardSystem,
90
+ pos: ArrayLike,
91
+ vel: ArrayLike,
92
+ n_bounces: int = 50,
93
+ ax: Axes | None = None,
94
+ **plot_kwargs: Any,
95
+ ) -> tuple[Figure, Axes]:
96
+ """Plot a single trajectory bouncing inside the billiard's boundary.
97
+
98
+ Parameters
99
+ ----------
100
+ billiard : BilliardSystem
101
+ Billiard to trace the trajectory within.
102
+ pos : array_like of float, shape (2,)
103
+ Initial position ``(x, y)``; must lie in the billiard's interior.
104
+ vel : array_like of float, shape (2,)
105
+ Initial velocity direction ``(vx, vy)``; normalized internally.
106
+ n_bounces : int, default 50
107
+ Number of reflections to trace.
108
+ ax : matplotlib.axes.Axes, optional
109
+ Axes to draw into; a new figure and axes are created if omitted.
110
+ **plot_kwargs
111
+ Additional keyword arguments forwarded to ``ax.plot`` for the
112
+ trajectory line.
113
+
114
+ Returns
115
+ -------
116
+ fig : matplotlib.figure.Figure
117
+ ax : matplotlib.axes.Axes
118
+ """
119
+ boundary = billiard.boundary_polyline()
120
+ path, _ = billiard.trajectory_segments(pos, vel, n_bounces)
121
+
122
+ if ax is None:
123
+ fig, ax = plt.subplots(figsize=(6, 6))
124
+ else:
125
+ fig = cast(Figure, ax.figure)
126
+
127
+ ax.plot(boundary[:, 0], boundary[:, 1], color=theme.STRUCTURE, lw=1.5)
128
+ kwargs: dict[str, Any] = {"color": theme.ACCENT, "lw": 0.8}
129
+ kwargs.update(plot_kwargs)
130
+ ax.plot(path[:, 0], path[:, 1], **kwargs)
131
+ ax.set_aspect("equal")
132
+ ax.set_title(f"{billiard.__class__.__name__} trajectory")
133
+ return fig, ax
@@ -0,0 +1,299 @@
1
+ """Plotting helpers for quantum maps and quantum billiards.
2
+
3
+ Plots the objects :mod:`physicskit.chaos.quantum` produces -- Floquet eigenphases,
4
+ Husimi phase-space distributions, and billiard eigenfunctions -- following
5
+ the same ``(fig, ax)``-returning, ``ax=`` -accepting convention as the rest
6
+ of :mod:`physicskit.chaos.visualizers`. Deliberately absent: any plot of spectral
7
+ *statistics* (level-spacing histograms, spectral rigidity, and the like) --
8
+ that analysis, and the random-matrix-theory context for it, belongs to the
9
+ separate ``physicskit.rmt`` package, which can consume
10
+ :meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.eigenphases`,
11
+ :meth:`~physicskit.chaos.quantum.maps.QuantumBakersMap.eigenphases`, or
12
+ :meth:`~physicskit.chaos.quantum.billiards.QuantumBilliard.wavenumbers` directly.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import Any, cast
18
+
19
+ import matplotlib.pyplot as plt
20
+ import numpy as np
21
+ from matplotlib.animation import FuncAnimation
22
+ from matplotlib.axes import Axes
23
+ from matplotlib.figure import Figure
24
+ from numpy.typing import ArrayLike
25
+
26
+ from physicskit.chaos.quantum.billiards import QuantumBilliard
27
+ from physicskit.chaos.quantum.maps import QuantumBakersMap, QuantumKickedRotor
28
+ from physicskit.chaos.visualizers import theme
29
+
30
+
31
+ def plot_quantum_spectrum(eigenphases: ArrayLike, ax: Axes | None = None, **scatter_kwargs: Any) -> tuple[Figure, Axes]:
32
+ """Scatter a quantum map's Floquet eigenphases on the unit circle.
33
+
34
+ Parameters
35
+ ----------
36
+ eigenphases : array_like of float, shape (n,)
37
+ Eigenphases in radians, e.g. from
38
+ :meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.eigenphases` or
39
+ :meth:`~physicskit.chaos.quantum.maps.QuantumBakersMap.eigenphases`.
40
+ ax : matplotlib.axes.Axes, optional
41
+ Axes to draw into; a new figure and axes are created if omitted.
42
+ **scatter_kwargs
43
+ Additional keyword arguments forwarded to ``ax.scatter``.
44
+
45
+ Returns
46
+ -------
47
+ fig : matplotlib.figure.Figure
48
+ ax : matplotlib.axes.Axes
49
+ """
50
+ eigenphases = np.asarray(eigenphases, dtype=np.float64)
51
+
52
+ if ax is None:
53
+ fig, ax = plt.subplots(figsize=(6, 6))
54
+ else:
55
+ fig = cast(Figure, ax.figure)
56
+
57
+ circle = np.linspace(0.0, 2.0 * np.pi, 400)
58
+ ax.plot(np.cos(circle), np.sin(circle), color=theme.MUTED, lw=0.8, zorder=1)
59
+ kwargs: dict[str, Any] = {"s": 12, "color": theme.PRIMARY, "zorder": 2}
60
+ kwargs.update(scatter_kwargs)
61
+ ax.scatter(np.cos(eigenphases), np.sin(eigenphases), **kwargs)
62
+ ax.set_aspect("equal")
63
+ ax.set_xlabel(r"$\cos(\phi)$")
64
+ ax.set_ylabel(r"$\sin(\phi)$")
65
+ ax.set_title("Floquet eigenphases")
66
+ return fig, ax
67
+
68
+
69
+ def plot_husimi(
70
+ q_grid: ArrayLike,
71
+ p_grid: ArrayLike,
72
+ husimi: ArrayLike,
73
+ ax: Axes | None = None,
74
+ cmap: str = theme.SEQUENTIAL_CMAP,
75
+ q_label: str = "q",
76
+ p_label: str = "p",
77
+ title: str | None = None,
78
+ ) -> tuple[Figure, Axes]:
79
+ """Plot a Husimi phase-space distribution.
80
+
81
+ Parameters
82
+ ----------
83
+ q_grid, p_grid : array_like of float, shape (resolution, resolution)
84
+ Phase-space grid, as returned by
85
+ :func:`~physicskit.chaos.quantum.husimi.husimi_function` (or
86
+ :meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.husimi` /
87
+ :meth:`~physicskit.chaos.quantum.maps.QuantumBakersMap.husimi`).
88
+ husimi : array_like of float, shape (resolution, resolution)
89
+ The Husimi distribution.
90
+ ax : matplotlib.axes.Axes, optional
91
+ Axes to draw into; a new figure and axes are created if omitted.
92
+ cmap : str, default theme.SEQUENTIAL_CMAP
93
+ Colormap name.
94
+ q_label, p_label : str, default "q", "p"
95
+ Axis labels.
96
+ title : str, optional
97
+ Axes title.
98
+
99
+ Returns
100
+ -------
101
+ fig : matplotlib.figure.Figure
102
+ ax : matplotlib.axes.Axes
103
+ """
104
+ q_grid = np.asarray(q_grid, dtype=np.float64)
105
+ p_grid = np.asarray(p_grid, dtype=np.float64)
106
+ husimi = np.asarray(husimi, dtype=np.float64)
107
+
108
+ if ax is None:
109
+ fig, ax = plt.subplots(figsize=(6.5, 6))
110
+ else:
111
+ fig = cast(Figure, ax.figure)
112
+
113
+ mesh = ax.pcolormesh(q_grid, p_grid, husimi, cmap=cmap, shading="gouraud")
114
+ fig.colorbar(mesh, ax=ax, label="Husimi intensity")
115
+ ax.set_xlabel(q_label)
116
+ ax.set_ylabel(p_label)
117
+ if title:
118
+ ax.set_title(title)
119
+ return fig, ax
120
+
121
+
122
+ def plot_billiard_eigenstate(
123
+ quantum_billiard: QuantumBilliard,
124
+ eigenfunction: ArrayLike,
125
+ ax: Axes | None = None,
126
+ density: bool = False,
127
+ show_boundary: bool = True,
128
+ ) -> tuple[Figure, Axes]:
129
+ """Plot one eigenfunction of a :class:`~physicskit.chaos.quantum.billiards.QuantumBilliard`.
130
+
131
+ Parameters
132
+ ----------
133
+ quantum_billiard : QuantumBilliard
134
+ The quantized billiard the eigenfunction belongs to (used for its
135
+ grid and boundary outline).
136
+ eigenfunction : array_like of float, shape (nx, ny)
137
+ One eigenfunction, e.g. a single row of the array returned by
138
+ :meth:`~physicskit.chaos.quantum.billiards.QuantumBilliard.eigenstates`; grid
139
+ points outside the billiard should be ``nan``.
140
+ ax : matplotlib.axes.Axes, optional
141
+ Axes to draw into; a new figure and axes are created if omitted.
142
+ density : bool, default False
143
+ If False (the default), plot the signed wavefunction ``psi`` itself
144
+ with a diverging colormap, showing nodal lines directly; this is
145
+ always available since :meth:`~physicskit.chaos.quantum.billiards.QuantumBilliard.eigenstates`
146
+ solves a real symmetric eigenproblem, so prefer it for a consistent
147
+ look across regular and chaotic billiards alike. If True, plot the
148
+ probability density ``|psi|^2`` instead, with a sequential colormap.
149
+ show_boundary : bool, default True
150
+ Whether to overlay the billiard's boundary outline.
151
+
152
+ Returns
153
+ -------
154
+ fig : matplotlib.figure.Figure
155
+ ax : matplotlib.axes.Axes
156
+ """
157
+ eigenfunction = np.asarray(eigenfunction, dtype=np.float64)
158
+ x_grid, y_grid = quantum_billiard.grid()
159
+
160
+ if ax is None:
161
+ fig, ax = plt.subplots(figsize=(6.5, 6))
162
+ else:
163
+ fig = cast(Figure, ax.figure)
164
+
165
+ if density:
166
+ field = eigenfunction**2
167
+ cmap = theme.SEQUENTIAL_CMAP
168
+ vmin, vmax = 0.0, np.nanmax(field)
169
+ label = r"$|\psi|^2$"
170
+ else:
171
+ field = eigenfunction
172
+ cmap = theme.DIVERGING_CMAP
173
+ vmax = np.nanmax(np.abs(field))
174
+ vmin = -vmax
175
+ label = r"$\psi$"
176
+
177
+ mesh = ax.pcolormesh(x_grid, y_grid, field, cmap=cmap, vmin=vmin, vmax=vmax, shading="auto")
178
+ fig.colorbar(mesh, ax=ax, label=label)
179
+
180
+ if show_boundary:
181
+ boundary = quantum_billiard.billiard.boundary_polyline()
182
+ ax.plot(boundary[:, 0], boundary[:, 1], color=theme.STRUCTURE, lw=1.2)
183
+
184
+ ax.set_aspect("equal")
185
+ ax.set_xlabel("x")
186
+ ax.set_ylabel("y")
187
+ return fig, ax
188
+
189
+
190
+ def plot_weyl_law(quantum_billiard: QuantumBilliard, n_states: int = 30, ax: Axes | None = None) -> tuple[Figure, Axes]:
191
+ """Compare a billiard's actual eigenvalue counting function to Weyl's law.
192
+
193
+ Draws the exact (staircase) count of eigenvalues below each wavenumber
194
+ alongside the smooth prediction from
195
+ :meth:`~physicskit.chaos.quantum.billiards.QuantumBilliard.weyl_counting_function`.
196
+
197
+ Parameters
198
+ ----------
199
+ quantum_billiard : QuantumBilliard
200
+ The quantized billiard to check.
201
+ n_states : int, default 30
202
+ Number of lowest eigenstates to compute and count.
203
+ ax : matplotlib.axes.Axes, optional
204
+ Axes to draw into; a new figure and axes are created if omitted.
205
+
206
+ Returns
207
+ -------
208
+ fig : matplotlib.figure.Figure
209
+ ax : matplotlib.axes.Axes
210
+ """
211
+ wavenumbers = quantum_billiard.wavenumbers(n_states)
212
+
213
+ if ax is None:
214
+ fig, ax = plt.subplots(figsize=(7, 5))
215
+ else:
216
+ fig = cast(Figure, ax.figure)
217
+
218
+ counts = np.arange(1, n_states + 1)
219
+ ax.step(wavenumbers, counts, where="post", color=theme.PRIMARY, label="actual $N(k)$")
220
+ k_smooth = np.linspace(0.0, wavenumbers[-1] * 1.05, 400)
221
+ ax.plot(
222
+ k_smooth,
223
+ quantum_billiard.weyl_counting_function(k_smooth),
224
+ color=theme.ACCENT,
225
+ ls="--",
226
+ label="Weyl's law",
227
+ )
228
+ ax.set_xlabel("k")
229
+ ax.set_ylabel("N(k)")
230
+ ax.set_title(f"{quantum_billiard.billiard.__class__.__name__}: eigenvalue counting function")
231
+ ax.legend(loc="upper left")
232
+ return fig, ax
233
+
234
+
235
+ def animate_husimi_evolution(
236
+ quantum_map: QuantumKickedRotor | QuantumBakersMap,
237
+ states: ArrayLike,
238
+ resolution: int = 80,
239
+ n_wraps: int = 3,
240
+ interval: int = 350,
241
+ cmap: str = theme.SEQUENTIAL_CMAP,
242
+ title: str | None = None,
243
+ ) -> FuncAnimation:
244
+ """Animate a quantum map state's Husimi distribution evolving, step by step.
245
+
246
+ Watching a coherent wavepacket's Husimi distribution spread across phase
247
+ space -- staying compact and orbit-like where the classical map is
248
+ regular, filling in a chaotic sea where it is not -- is one of the most
249
+ direct illustrations of quantum chaos: it shows the quantum-classical
250
+ correspondence visibly *breaking down*.
251
+
252
+ Parameters
253
+ ----------
254
+ quantum_map : QuantumKickedRotor or QuantumBakersMap
255
+ The quantum map `states` were generated from (used for its `husimi`
256
+ method).
257
+ states : array_like of complex, shape (n_steps + 1, dim)
258
+ State at each step, e.g. from
259
+ :meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.evolve` or
260
+ :meth:`~physicskit.chaos.quantum.maps.QuantumBakersMap.evolve`.
261
+ resolution : int, default 80
262
+ Number of grid points along each phase-space axis.
263
+ n_wraps : int, default 3
264
+ Number of periodic images summed to periodize the coherent states
265
+ used by :meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.husimi`.
266
+ interval : int, default 350
267
+ Delay between animation frames, in milliseconds.
268
+ cmap : str, default theme.SEQUENTIAL_CMAP
269
+ Colormap name.
270
+ title : str, optional
271
+ Base title; each frame appends its step number.
272
+
273
+ Returns
274
+ -------
275
+ matplotlib.animation.FuncAnimation
276
+ Assign it to a variable to keep it alive, and display it with
277
+ ``plt.show()`` or save it with ``anim.save(...)``.
278
+ """
279
+ states = np.asarray(states, dtype=np.complex128)
280
+ n_steps = states.shape[0]
281
+
282
+ q_grid, p_grid, husimi0 = quantum_map.husimi(states[0], resolution=resolution, n_wraps=n_wraps)
283
+
284
+ fig, ax = plt.subplots(figsize=(6.5, 6))
285
+ mesh = ax.pcolormesh(q_grid, p_grid, husimi0, cmap=cmap, shading="gouraud", vmin=0.0, vmax=1.0)
286
+ fig.colorbar(mesh, ax=ax, label="Husimi intensity")
287
+ ax.set_xlabel("q")
288
+ ax.set_ylabel("p")
289
+ base_title = title or f"{type(quantum_map).__name__} Husimi distribution"
290
+ title_artist = ax.set_title(f"{base_title} (step 0)")
291
+
292
+ def update(frame: int) -> tuple:
293
+ _, _, husimi = quantum_map.husimi(states[frame], resolution=resolution, n_wraps=n_wraps)
294
+ mesh.set_array(husimi.ravel())
295
+ title_artist.set_text(f"{base_title} (step {frame})")
296
+ return mesh, title_artist
297
+
298
+ anim = FuncAnimation(fig, update, frames=n_steps, interval=interval, blit=False)
299
+ return anim
@@ -0,0 +1,91 @@
1
+ """Visualizations of Poincare recurrence: recurrence plots and return-time histograms."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import cast
6
+
7
+ import matplotlib.pyplot as plt
8
+ from matplotlib.axes import Axes
9
+ from matplotlib.figure import Figure
10
+ from numpy.typing import ArrayLike
11
+
12
+ from physicskit.chaos.utils.recurrence import recurrence_matrix, recurrence_times
13
+ from physicskit.chaos.visualizers import theme
14
+
15
+
16
+ def plot_recurrence_matrix(states: ArrayLike, epsilon: float, ax: Axes | None = None) -> tuple[Figure, Axes]:
17
+ """Plot the classic black-and-white recurrence plot of a trajectory.
18
+
19
+ Parameters
20
+ ----------
21
+ states : array_like of float, shape (n, dim)
22
+ Trajectory samples.
23
+ epsilon : float
24
+ Neighborhood radius defining a "recurrence".
25
+ ax : matplotlib.axes.Axes, optional
26
+ Axes to draw into; a new figure and axes are created if omitted.
27
+
28
+ Returns
29
+ -------
30
+ fig : matplotlib.figure.Figure
31
+ ax : matplotlib.axes.Axes
32
+ """
33
+ matrix = recurrence_matrix(states, epsilon)
34
+
35
+ if ax is None:
36
+ fig, ax = plt.subplots(figsize=(6, 6))
37
+ else:
38
+ fig = cast(Figure, ax.figure)
39
+
40
+ ax.imshow(matrix, cmap="Greys", origin="lower", interpolation="nearest")
41
+ ax.set_xlabel("i")
42
+ ax.set_ylabel("j")
43
+ ax.set_title(f"Recurrence plot ($\\epsilon$ = {epsilon:g})")
44
+ return fig, ax
45
+
46
+
47
+ def plot_recurrence_times(
48
+ states: ArrayLike,
49
+ epsilon: float,
50
+ reference_idx: int = 0,
51
+ dt: float = 1.0,
52
+ bins: int = 40,
53
+ ax: Axes | None = None,
54
+ ) -> tuple[Figure, Axes]:
55
+ """Plot a histogram of the recurrence-time distribution to a reference point.
56
+
57
+ Parameters
58
+ ----------
59
+ states : array_like of float, shape (n, dim)
60
+ Trajectory samples.
61
+ epsilon : float
62
+ Neighborhood radius defining a "return".
63
+ reference_idx : int, default 0
64
+ Index into `states` of the reference point to measure returns to.
65
+ dt : float, default 1.0
66
+ Time between consecutive rows of `states`.
67
+ bins : int, default 40
68
+ Number of histogram bins.
69
+ ax : matplotlib.axes.Axes, optional
70
+ Axes to draw into; a new figure and axes are created if omitted.
71
+
72
+ Returns
73
+ -------
74
+ fig : matplotlib.figure.Figure
75
+ ax : matplotlib.axes.Axes
76
+ """
77
+ times = recurrence_times(states, epsilon, reference_idx=reference_idx, dt=dt)
78
+
79
+ if ax is None:
80
+ fig, ax = plt.subplots(figsize=(7, 5))
81
+ else:
82
+ fig = cast(Figure, ax.figure)
83
+
84
+ ax.hist(times, bins=bins, color=theme.PRIMARY, alpha=0.8)
85
+ if times.size:
86
+ ax.axvline(times.mean(), color=theme.ACCENT, linestyle="--", label=f"mean = {times.mean():.3g}")
87
+ ax.legend()
88
+ ax.set_xlabel("recurrence time")
89
+ ax.set_ylabel("count")
90
+ ax.set_title(f"Recurrence-time distribution ($\\epsilon$ = {epsilon:g})")
91
+ return fig, ax
@@ -0,0 +1,161 @@
1
+ """Poincare sections (surface-of-section crossings) for continuous-time flows.
2
+
3
+ Unlike :mod:`physicskit.chaos.visualizers.phase_space` (which builds a billiard's
4
+ boundary phase space from its ray-tracing bounces), this module implements
5
+ the original form of the technique Poincare introduced while studying the
6
+ restricted three-body problem: sample a continuous flow only at the instants
7
+ it pierces a fixed surface in state space, turning the ODE's trajectory into
8
+ a lower-dimensional map whose structure -- smooth invariant curves (or a
9
+ handful of points) for regular motion, a scattered "chaotic sea" otherwise --
10
+ is far easier to read than the raw, tangled trajectory.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import Any, cast
16
+
17
+ import matplotlib.pyplot as plt
18
+ import numpy as np
19
+ from matplotlib.axes import Axes
20
+ from matplotlib.figure import Figure
21
+ from numpy.typing import ArrayLike, NDArray
22
+
23
+ from physicskit.chaos.core.base_system import DynamicalSystem
24
+ from physicskit.chaos.visualizers import theme
25
+
26
+
27
+ def poincare_crossings(
28
+ system: DynamicalSystem,
29
+ state0: ArrayLike,
30
+ coord: int,
31
+ value: float = 0.0,
32
+ direction: float = 1.0,
33
+ t_max: float = 200.0,
34
+ dt: float = 0.001,
35
+ ) -> NDArray[np.float64]:
36
+ """Integrate one trajectory and record its state at every crossing of a
37
+ fixed surface ``state[coord] == value``.
38
+
39
+ Parameters
40
+ ----------
41
+ system : DynamicalSystem
42
+ System to integrate, via its own ``trajectory(state0, dt, n_steps)``.
43
+ state0 : array_like of float, shape (dim,)
44
+ Initial state.
45
+ coord : int
46
+ Index of the state component that defines the section surface.
47
+ value : float, default 0.0
48
+ Value of ``state[coord]`` the surface sits at.
49
+ direction : float, default 1.0
50
+ Sign of ``d(state[coord])/dt`` required to keep a crossing (e.g. the
51
+ default ``1.0`` keeps only crossings where `coord` is increasing,
52
+ discarding the return crossing on the way back, so each pass through
53
+ the surface is counted once instead of twice).
54
+ t_max : float, default 200.0
55
+ Total integration time.
56
+ dt : float, default 0.001
57
+ Fixed integration step size.
58
+
59
+ Returns
60
+ -------
61
+ ndarray of float, shape (n_crossings, dim)
62
+ The full state at each qualifying crossing, linearly interpolated
63
+ between the two bracketing integration steps.
64
+ """
65
+ n_steps = int(round(t_max / dt))
66
+ _, states = system.trajectory(state0=np.asarray(state0, dtype=np.float64), dt=dt, n_steps=n_steps)
67
+
68
+ f = states[:, coord] - value
69
+ crosses = (np.sign(f[:-1]) != np.sign(f[1:])) & (f[:-1] != 0.0)
70
+ if direction > 0:
71
+ crosses &= f[1:] > f[:-1]
72
+ elif direction < 0:
73
+ crosses &= f[1:] < f[:-1]
74
+ idx = np.flatnonzero(crosses)
75
+ if idx.size == 0:
76
+ return np.empty((0, states.shape[1]))
77
+
78
+ f0, f1 = f[idx], f[idx + 1]
79
+ frac = f0 / (f0 - f1)
80
+ return states[idx] + frac[:, None] * (states[idx + 1] - states[idx])
81
+
82
+
83
+ def plot_poincare_map(
84
+ system: DynamicalSystem,
85
+ initial_states: ArrayLike,
86
+ coord: int = 1,
87
+ value: float = 0.0,
88
+ direction: float = 1.0,
89
+ plot_coords: tuple[int, int] = (0, 2),
90
+ t_max: float = 200.0,
91
+ dt: float = 0.001,
92
+ labels: list[str] | None = None,
93
+ ax: Axes | None = None,
94
+ **scatter_kwargs: Any,
95
+ ) -> tuple[Figure, Axes]:
96
+ """Overlay Poincare-section crossings from several initial conditions.
97
+
98
+ Each initial condition in `initial_states` is integrated independently
99
+ and its :func:`poincare_crossings` plotted as its own scatter series
100
+ (colored from :data:`~physicskit.chaos.visualizers.theme.QUALITATIVE_CMAP`), so
101
+ a regular orbit's crossings -- collapsing onto a smooth curve, or even a
102
+ handful of points, for a periodic orbit -- can be compared directly
103
+ against a chaotic orbit's crossings, which scatter to fill a 2D patch.
104
+
105
+ Parameters
106
+ ----------
107
+ system : DynamicalSystem
108
+ System to integrate.
109
+ initial_states : array_like of float, shape (n_series, dim)
110
+ Initial states, one per series to overlay.
111
+ coord : int, default 1
112
+ Index of the state component that defines the section surface
113
+ (default ``1``, i.e. ``y`` for a state ``(x, y, vx, vy)``).
114
+ value : float, default 0.0
115
+ Value of ``state[coord]`` the surface sits at.
116
+ direction : float, default 1.0
117
+ Sign of ``d(state[coord])/dt`` required to keep a crossing; see
118
+ :func:`poincare_crossings`.
119
+ plot_coords : tuple of int, default (0, 2)
120
+ Indices of the two state components to scatter against each other
121
+ (default: ``x`` vs. ``vx`` for a state ``(x, y, vx, vy)``).
122
+ t_max : float, default 200.0
123
+ Total integration time per series.
124
+ dt : float, default 0.001
125
+ Fixed integration step size.
126
+ labels : list of str, optional
127
+ Legend label for each series; the legend is omitted entirely if not
128
+ given.
129
+ ax : matplotlib.axes.Axes, optional
130
+ Axes to draw into; a new figure and axes are created if omitted.
131
+ **scatter_kwargs
132
+ Additional keyword arguments forwarded to every ``ax.scatter`` call.
133
+
134
+ Returns
135
+ -------
136
+ fig : matplotlib.figure.Figure
137
+ ax : matplotlib.axes.Axes
138
+ """
139
+ initial_states = np.atleast_2d(np.asarray(initial_states, dtype=np.float64))
140
+
141
+ if ax is None:
142
+ fig, ax = plt.subplots(figsize=(7, 6))
143
+ else:
144
+ fig = cast(Figure, ax.figure)
145
+
146
+ cmap = plt.get_cmap(theme.QUALITATIVE_CMAP)
147
+ i0, i1 = plot_coords
148
+ for i, s0 in enumerate(initial_states):
149
+ crossings = poincare_crossings(system, s0, coord=coord, value=value, direction=direction, t_max=t_max, dt=dt)
150
+ if crossings.shape[0] == 0:
151
+ continue
152
+ kwargs: dict[str, Any] = {"s": 6, "alpha": 0.7, "color": cmap(i % cmap.N)}
153
+ if labels is not None:
154
+ kwargs["label"] = labels[i]
155
+ kwargs.update(scatter_kwargs)
156
+ ax.scatter(crossings[:, i0], crossings[:, i1], **kwargs)
157
+
158
+ if labels is not None:
159
+ ax.legend(fontsize=8)
160
+ ax.set_title(f"{system.__class__.__name__} Poincare section")
161
+ return fig, ax