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,253 @@
1
+ r"""Quantum measurement simulator and expectation-value / uncertainty monitors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+
7
+ import numpy as np
8
+
9
+ from .._compat import trapz
10
+
11
+ __all__ = ["expectation_value", "uncertainty", "momentum_density", "ExpectationMonitor", "simulate_position_measurement"]
12
+
13
+
14
+ def expectation_value(operator_action, x: np.ndarray, psi: np.ndarray) -> complex:
15
+ r"""Expectation value of a local/differential operator.
16
+
17
+ .. math::
18
+
19
+ \langle\psi\rvert\hat A\lvert\psi\rangle
20
+ = \int \psi^*(x)\, [\hat A\psi](x)\, dx.
21
+
22
+ Parameters
23
+ ----------
24
+ operator_action : callable
25
+ A function ``operator_action(x, psi) -> A_psi`` applying
26
+ :math:`\hat A` to ``psi``.
27
+ x : numpy.ndarray
28
+ Positions.
29
+ psi : numpy.ndarray
30
+ Wavefunction sampled on ``x``.
31
+
32
+ Returns
33
+ -------
34
+ complex
35
+ """
36
+ A_psi = operator_action(x, psi)
37
+ return complex(trapz(np.conj(psi) * A_psi, x))
38
+
39
+
40
+ def position_expectation(x: np.ndarray, psi: np.ndarray) -> float:
41
+ r"""Position expectation value :math:`\langle x\rangle = \int x\,\lvert\psi(x)\rvert^2\,dx`.
42
+
43
+ Parameters
44
+ ----------
45
+ x : numpy.ndarray
46
+ psi : numpy.ndarray
47
+
48
+ Returns
49
+ -------
50
+ float
51
+ """
52
+ return float(np.real(trapz(x * np.abs(psi) ** 2, x)))
53
+
54
+
55
+ def position_variance(x: np.ndarray, psi: np.ndarray) -> float:
56
+ r"""Position variance :math:`\langle x^2\rangle - \langle x\rangle^2`.
57
+
58
+ Parameters
59
+ ----------
60
+ x : numpy.ndarray
61
+ psi : numpy.ndarray
62
+
63
+ Returns
64
+ -------
65
+ float
66
+ """
67
+ density = np.abs(psi) ** 2
68
+ mean = trapz(x * density, x)
69
+ mean_sq = trapz(x**2 * density, x)
70
+ return float(np.real(mean_sq - mean**2))
71
+
72
+
73
+ def momentum_density(x: np.ndarray, psi: np.ndarray, hbar: float = 1.0):
74
+ """FFT-based momentum-space wavefunction and probability density.
75
+
76
+ Parameters
77
+ ----------
78
+ x : numpy.ndarray
79
+ Positions (uniform grid).
80
+ psi : numpy.ndarray
81
+ Wavefunction sampled on ``x``.
82
+ hbar : float, default=1.0
83
+ Value of :math:`\\hbar` to use.
84
+
85
+ Returns
86
+ -------
87
+ p : numpy.ndarray
88
+ Momentum grid, ascending.
89
+ psi_p : numpy.ndarray
90
+ Normalized momentum-space wavefunction.
91
+ """
92
+ dx = x[1] - x[0]
93
+ N = x.shape[0]
94
+ k = 2 * np.pi * np.fft.fftfreq(N, d=dx)
95
+ psi_k = np.fft.fft(psi) * dx / np.sqrt(2 * np.pi)
96
+ p = hbar * k
97
+ order = np.argsort(p)
98
+ p_sorted, psi_k_sorted = p[order], psi_k[order]
99
+ norm = np.sqrt(trapz(np.abs(psi_k_sorted) ** 2, p_sorted))
100
+ return p_sorted, psi_k_sorted / norm
101
+
102
+
103
+ def momentum_expectation(x: np.ndarray, psi: np.ndarray, hbar: float = 1.0) -> float:
104
+ r"""Momentum expectation value :math:`\langle p\rangle`, via :func:`momentum_density`.
105
+
106
+ Parameters
107
+ ----------
108
+ x : numpy.ndarray
109
+ psi : numpy.ndarray
110
+ hbar : float, default=1.0
111
+
112
+ Returns
113
+ -------
114
+ float
115
+ """
116
+ p, psi_p = momentum_density(x, psi, hbar)
117
+ return float(np.real(trapz(p * np.abs(psi_p) ** 2, p)))
118
+
119
+
120
+ def momentum_variance(x: np.ndarray, psi: np.ndarray, hbar: float = 1.0) -> float:
121
+ r"""Momentum variance :math:`\langle p^2\rangle - \langle p\rangle^2`, via :func:`momentum_density`.
122
+
123
+ Parameters
124
+ ----------
125
+ x : numpy.ndarray
126
+ psi : numpy.ndarray
127
+ hbar : float, default=1.0
128
+
129
+ Returns
130
+ -------
131
+ float
132
+ """
133
+ p, psi_p = momentum_density(x, psi, hbar)
134
+ density = np.abs(psi_p) ** 2
135
+ mean = trapz(p * density, p)
136
+ mean_sq = trapz(p**2 * density, p)
137
+ return float(np.real(mean_sq - mean**2))
138
+
139
+
140
+ def uncertainty(x: np.ndarray, psi: np.ndarray, hbar: float = 1.0) -> tuple[float, float, float]:
141
+ r"""Position/momentum uncertainties and their product.
142
+
143
+ Parameters
144
+ ----------
145
+ x : numpy.ndarray
146
+ psi : numpy.ndarray
147
+ hbar : float, default=1.0
148
+
149
+ Returns
150
+ -------
151
+ dx, dp, product : float
152
+ :math:`\Delta x`, :math:`\Delta p`, and :math:`\Delta x\,\Delta p`,
153
+ for checking the Heisenberg bound :math:`\Delta x\,\Delta p \ge \hbar/2`.
154
+ """
155
+ dx = np.sqrt(position_variance(x, psi))
156
+ dp = np.sqrt(momentum_variance(x, psi, hbar))
157
+ return dx, dp, dx * dp
158
+
159
+
160
+ @dataclass
161
+ class ExpectationMonitor:
162
+ """Tracks expectation values along a time-evolution trajectory.
163
+
164
+ Records :math:`\\langle x\\rangle(t)`, :math:`\\langle p\\rangle(t)`,
165
+ :math:`\\Delta x(t)`, :math:`\\Delta p(t)`, and the norm, e.g. from the
166
+ frames returned by a
167
+ :meth:`~physicskit.quantum.core.solvers.SplitOperatorSolver1D.propagate` call.
168
+
169
+ Parameters
170
+ ----------
171
+ x : numpy.ndarray
172
+ Positions the wavefunction is sampled on.
173
+ hbar : float, default=1.0
174
+ Value of :math:`\\hbar` to use.
175
+ """
176
+
177
+ x: np.ndarray
178
+ hbar: float = 1.0
179
+ history: dict = field(default_factory=lambda: {"t": [], "norm": [], "x": [], "p": [], "dx": [], "dp": []})
180
+
181
+ def record(self, t: float, psi: np.ndarray):
182
+ """Record one snapshot.
183
+
184
+ Parameters
185
+ ----------
186
+ t : float
187
+ Time of the snapshot.
188
+ psi : numpy.ndarray
189
+ Wavefunction at time ``t``, sampled on ``self.x``.
190
+ """
191
+ norm = trapz(np.abs(psi) ** 2, self.x)
192
+ dx, dp, _ = uncertainty(self.x, psi, self.hbar)
193
+ self.history["t"].append(t)
194
+ self.history["norm"].append(float(norm))
195
+ self.history["x"].append(position_expectation(self.x, psi))
196
+ self.history["p"].append(momentum_expectation(self.x, psi, self.hbar))
197
+ self.history["dx"].append(dx)
198
+ self.history["dp"].append(dp)
199
+
200
+ def record_all(self, times: np.ndarray, frames: np.ndarray):
201
+ """Record a full trajectory.
202
+
203
+ Parameters
204
+ ----------
205
+ times : numpy.ndarray
206
+ Times of each snapshot.
207
+ frames : numpy.ndarray
208
+ Wavefunction snapshots, shape ``(len(times), len(self.x))``.
209
+ """
210
+ for t, psi in zip(times, frames):
211
+ self.record(t, psi)
212
+
213
+ def as_arrays(self) -> dict:
214
+ """Return the recorded history as arrays.
215
+
216
+ Returns
217
+ -------
218
+ dict
219
+ Maps ``'t'``, ``'norm'``, ``'x'``, ``'p'``, ``'dx'``, ``'dp'``
220
+ to :class:`numpy.ndarray`.
221
+ """
222
+ return {k: np.array(v) for k, v in self.history.items()}
223
+
224
+
225
+ def simulate_position_measurement(x: np.ndarray, psi: np.ndarray, n_samples: int = 1, rng: np.random.Generator | None = None) -> np.ndarray:
226
+ r"""Sample simulated projective position measurements.
227
+
228
+ Draws :math:`x_i \sim \lvert\psi(x)\rvert^2` (the Born rule), via
229
+ inverse-CDF sampling on the discretized density.
230
+
231
+ Parameters
232
+ ----------
233
+ x : numpy.ndarray
234
+ Positions.
235
+ psi : numpy.ndarray
236
+ Wavefunction sampled on ``x``.
237
+ n_samples : int, default=1
238
+ Number of simulated measurement outcomes to draw.
239
+ rng : numpy.random.Generator or None, optional
240
+ Random number generator; a fresh default one is used if omitted.
241
+
242
+ Returns
243
+ -------
244
+ numpy.ndarray
245
+ Simulated measurement outcomes, shape ``(n_samples,)``.
246
+ """
247
+ rng = rng or np.random.default_rng()
248
+ density = np.abs(psi) ** 2
249
+ density = density / trapz(density, x)
250
+ cdf = np.concatenate([[0.0], np.cumsum((density[1:] + density[:-1]) / 2 * np.diff(x))])
251
+ cdf /= cdf[-1]
252
+ u = rng.random(n_samples)
253
+ return np.interp(u, cdf, x)
File without changes
@@ -0,0 +1,205 @@
1
+ r"""Interactive 3D Bloch-sphere qubit trajectories (Plotly), and a frame-by-frame
2
+ matplotlib animation of the vector advancing along a trajectory."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import matplotlib.pyplot as plt
7
+ import numpy as np
8
+ import plotly.graph_objects as go
9
+ from matplotlib.animation import FuncAnimation
10
+
11
+ from ..core.operators import sigma_x, sigma_y, sigma_z
12
+
13
+ __all__ = ["bloch_vector", "state_to_bloch_trajectory", "plot_bloch_sphere", "animate_bloch_sphere"]
14
+
15
+
16
+ def bloch_vector(psi: np.ndarray) -> np.ndarray:
17
+ r"""The Bloch-sphere coordinates of a single-qubit pure state.
18
+
19
+ .. math::
20
+
21
+ \mathbf n = \left(\langle\psi\rvert\sigma_x\lvert\psi\rangle,\;
22
+ \langle\psi\rvert\sigma_y\lvert\psi\rangle,\;
23
+ \langle\psi\rvert\sigma_z\lvert\psi\rangle\right).
24
+
25
+ Parameters
26
+ ----------
27
+ psi : numpy.ndarray
28
+ A 2-component qubit state vector.
29
+
30
+ Returns
31
+ -------
32
+ numpy.ndarray
33
+ The 3-component Bloch vector ``(x, y, z)``.
34
+ """
35
+ psi = np.asarray(psi, dtype=complex)
36
+ x = np.real(np.vdot(psi, sigma_x @ psi))
37
+ y = np.real(np.vdot(psi, sigma_y @ psi))
38
+ z = np.real(np.vdot(psi, sigma_z @ psi))
39
+ return np.array([x, y, z])
40
+
41
+
42
+ def state_to_bloch_trajectory(states: np.ndarray) -> np.ndarray:
43
+ """Convert a time series of qubit states to Bloch-vector coordinates.
44
+
45
+ Parameters
46
+ ----------
47
+ states : numpy.ndarray
48
+ Qubit state vectors over time, shape ``(n_times, 2)``.
49
+
50
+ Returns
51
+ -------
52
+ numpy.ndarray
53
+ Bloch vectors, shape ``(n_times, 3)``.
54
+ """
55
+ return np.array([bloch_vector(psi) for psi in states])
56
+
57
+
58
+ def _sphere_mesh(n: int = 40):
59
+ u = np.linspace(0, 2 * np.pi, n)
60
+ v = np.linspace(0, np.pi, n)
61
+ xs = np.outer(np.cos(u), np.sin(v))
62
+ ys = np.outer(np.sin(u), np.sin(v))
63
+ zs = np.outer(np.ones_like(u), np.cos(v))
64
+ return xs, ys, zs
65
+
66
+
67
+ def plot_bloch_sphere(trajectory: np.ndarray | None = None, vectors: list[np.ndarray] | None = None, labels: list[str] | None = None) -> go.Figure:
68
+ """Render the Bloch sphere.
69
+
70
+ Parameters
71
+ ----------
72
+ trajectory : numpy.ndarray or None, optional
73
+ Bloch vectors traced over time, shape ``(n_times, 3)`` (e.g. from
74
+ :func:`state_to_bloch_trajectory`).
75
+ vectors : list of numpy.ndarray or None, optional
76
+ Static vectors to mark, each a 3-component array.
77
+ labels : list of str or None, optional
78
+ Labels for ``vectors``; defaults to ``v0, v1, ...``.
79
+
80
+ Returns
81
+ -------
82
+ plotly.graph_objects.Figure
83
+ """
84
+ xs, ys, zs = _sphere_mesh()
85
+ fig = go.Figure()
86
+ fig.add_trace(go.Surface(x=xs, y=ys, z=zs, opacity=0.15, showscale=False, colorscale=[[0, "lightblue"], [1, "lightblue"]]))
87
+
88
+ axis_len = 1.3
89
+ for axis, name in zip(np.eye(3), ["x", "y", "z"]):
90
+ fig.add_trace(
91
+ go.Scatter3d(
92
+ x=[-axis_len * axis[0], axis_len * axis[0]],
93
+ y=[-axis_len * axis[1], axis_len * axis[1]],
94
+ z=[-axis_len * axis[2], axis_len * axis[2]],
95
+ mode="lines",
96
+ line=dict(color="gray", width=2),
97
+ showlegend=False,
98
+ )
99
+ )
100
+ fig.add_trace(go.Scatter3d(x=[axis_len * axis[0]], y=[axis_len * axis[1]], z=[axis_len * axis[2]], mode="text", text=[name], showlegend=False))
101
+
102
+ if trajectory is not None:
103
+ fig.add_trace(
104
+ go.Scatter3d(
105
+ x=trajectory[:, 0],
106
+ y=trajectory[:, 1],
107
+ z=trajectory[:, 2],
108
+ mode="lines+markers",
109
+ marker=dict(size=3, color=np.arange(len(trajectory)), colorscale="Viridis"),
110
+ line=dict(color="darkred", width=4),
111
+ name="trajectory",
112
+ )
113
+ )
114
+
115
+ if vectors is not None:
116
+ for i, v in enumerate(vectors):
117
+ label = labels[i] if labels else f"v{i}"
118
+ fig.add_trace(
119
+ go.Scatter3d(
120
+ x=[0, v[0]],
121
+ y=[0, v[1]],
122
+ z=[0, v[2]],
123
+ mode="lines+markers",
124
+ line=dict(width=6),
125
+ marker=dict(size=[0, 6]),
126
+ name=label,
127
+ )
128
+ )
129
+
130
+ fig.update_layout(
131
+ scene=dict(
132
+ xaxis=dict(range=[-1.4, 1.4]),
133
+ yaxis=dict(range=[-1.4, 1.4]),
134
+ zaxis=dict(range=[-1.4, 1.4]),
135
+ aspectmode="cube",
136
+ ),
137
+ margin=dict(l=0, r=0, t=30, b=0),
138
+ title="Bloch sphere",
139
+ )
140
+ return fig
141
+
142
+
143
+ def animate_bloch_sphere(trajectory: np.ndarray, times: np.ndarray | None = None, interval: int = 30, trail: bool = True, ax=None) -> FuncAnimation:
144
+ """A matplotlib mplot3d ``FuncAnimation`` of the Bloch vector advancing along a trajectory.
145
+
146
+ Unlike :func:`plot_bloch_sphere` (which draws the whole path as one
147
+ static Plotly trace), this genuinely animates: the arrow from the
148
+ origin sweeps frame-by-frame along ``trajectory``, optionally leaving a
149
+ fading trail.
150
+
151
+ Parameters
152
+ ----------
153
+ trajectory : numpy.ndarray
154
+ Bloch vectors over time, shape ``(n_frames, 3)`` (e.g. from
155
+ :func:`state_to_bloch_trajectory`).
156
+ times : numpy.ndarray or None, optional
157
+ Time of each frame, used to label the animation title.
158
+ interval : int, default=30
159
+ Delay between frames, in milliseconds.
160
+ trail : bool, default=True
161
+ Whether to draw the path swept out so far.
162
+ ax : mpl_toolkits.mplot3d.axes3d.Axes3D or None, optional
163
+ Axis to draw on; a new 3D figure/axis is created if omitted.
164
+
165
+ Returns
166
+ -------
167
+ matplotlib.animation.FuncAnimation
168
+ """
169
+ if ax is None:
170
+ fig = plt.figure(figsize=(6, 6))
171
+ ax = fig.add_subplot(111, projection="3d")
172
+ else:
173
+ fig = ax.figure
174
+
175
+ u = np.linspace(0, 2 * np.pi, 30)
176
+ v = np.linspace(0, np.pi, 30)
177
+ xs = np.outer(np.cos(u), np.sin(v))
178
+ ys = np.outer(np.sin(u), np.sin(v))
179
+ zs = np.outer(np.ones_like(u), np.cos(v))
180
+ ax.plot_wireframe(xs, ys, zs, color="lightblue", alpha=0.2, linewidth=0.5)
181
+
182
+ axis_len = 1.3
183
+ for axis in np.eye(3):
184
+ ax.plot(*zip(-axis_len * axis, axis_len * axis), color="gray", lw=1)
185
+
186
+ ax.set_xlim(-1.3, 1.3)
187
+ ax.set_ylim(-1.3, 1.3)
188
+ ax.set_zlim(-1.3, 1.3)
189
+ ax.set_box_aspect((1, 1, 1))
190
+
191
+ (arrow_line,) = ax.plot([0, trajectory[0, 0]], [0, trajectory[0, 1]], [0, trajectory[0, 2]], color="darkred", lw=3, marker="o", markevery=[1])
192
+ (trail_line,) = ax.plot([], [], [], color="darkorange", lw=1.5, alpha=0.7)
193
+
194
+ def update(i):
195
+ vec = trajectory[i]
196
+ arrow_line.set_data([0, vec[0]], [0, vec[1]])
197
+ arrow_line.set_3d_properties([0, vec[2]])
198
+ if trail:
199
+ trail_line.set_data(trajectory[: i + 1, 0], trajectory[: i + 1, 1])
200
+ trail_line.set_3d_properties(trajectory[: i + 1, 2])
201
+ title = f"t = {times[i]:.3f}" if times is not None else f"frame {i}"
202
+ ax.set_title(title)
203
+ return arrow_line, trail_line
204
+
205
+ return FuncAnimation(fig, update, frames=len(trajectory), interval=interval, blit=False)
@@ -0,0 +1,58 @@
1
+ r"""Animated growth of an entanglement measure over time."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ from matplotlib.animation import FuncAnimation
8
+
9
+ __all__ = ["animate_entanglement_growth"]
10
+
11
+
12
+ def animate_entanglement_growth(t_values: np.ndarray, metric_values: np.ndarray, ylabel: str = "concurrence", interval: int = 30, ax=None) -> FuncAnimation:
13
+ """Animate a point tracing out an entanglement-measure curve as it builds up over time.
14
+
15
+ Draws the curve ``metric_values`` vs. ``t_values`` progressively (rather
16
+ than all at once), with a marker at the current time -- e.g. the
17
+ concurrence or reduced-state purity of
18
+ :class:`~physicskit.quantum.chapters.entanglement.IsingEntangler` growing
19
+ from 0 (product state) toward 1 (maximally entangled) as the coupling acts.
20
+
21
+ Parameters
22
+ ----------
23
+ t_values : numpy.ndarray
24
+ Times.
25
+ metric_values : numpy.ndarray
26
+ The entanglement measure evaluated at each time in ``t_values``.
27
+ ylabel : str, default='concurrence'
28
+ Label for the y-axis.
29
+ interval : int, default=30
30
+ Delay between frames, in milliseconds.
31
+ ax : matplotlib.axes.Axes or None, optional
32
+ Axis to draw on; a new figure/axis is created if omitted.
33
+
34
+ Returns
35
+ -------
36
+ matplotlib.animation.FuncAnimation
37
+ """
38
+ if ax is None:
39
+ fig, ax = plt.subplots(figsize=(7, 4))
40
+ else:
41
+ fig = ax.figure
42
+
43
+ ax.set_xlim(t_values.min(), t_values.max())
44
+ ymax = metric_values.max() * 1.1 if metric_values.max() > 0 else 1.0
45
+ ax.set_ylim(0, ymax)
46
+ ax.set_xlabel("t")
47
+ ax.set_ylabel(ylabel)
48
+
49
+ (line,) = ax.plot([], [], color="C0", lw=2)
50
+ (point,) = ax.plot([], [], "o", color="darkred", markersize=8)
51
+
52
+ def update(i):
53
+ line.set_data(t_values[: i + 1], metric_values[: i + 1])
54
+ point.set_data([t_values[i]], [metric_values[i]])
55
+ ax.set_title(f"t = {t_values[i]:.3f}")
56
+ return line, point
57
+
58
+ return FuncAnimation(fig, update, frames=len(t_values), interval=interval, blit=False)
@@ -0,0 +1,187 @@
1
+ r"""3D volumetric rendering of hydrogen electron density clouds (Plotly)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+ import plotly.graph_objects as go
7
+
8
+ from ..chapters.hydrogen_am import HydrogenOrbital, orbital_superposition_density
9
+
10
+ __all__ = ["orbital_density_grid", "plot_orbital_cloud", "animate_orbital_beating"]
11
+
12
+
13
+ def orbital_density_grid(orbital: HydrogenOrbital, extent: float | None = None, n_points: int = 60):
14
+ r"""Evaluate :math:`\lvert\psi_{nlm}\rvert^2` on a Cartesian grid.
15
+
16
+ Parameters
17
+ ----------
18
+ orbital : physicskit.quantum.chapters.hydrogen_am.HydrogenOrbital
19
+ The orbital to evaluate.
20
+ extent : float or None, optional
21
+ Half-width of the cubic grid; defaults to a value scaled to the
22
+ orbital's expected extent.
23
+ n_points : int, default=60
24
+ Number of grid points along each Cartesian axis.
25
+
26
+ Returns
27
+ -------
28
+ X, Y, Z : numpy.ndarray
29
+ Cartesian coordinate meshgrid.
30
+ density : numpy.ndarray
31
+ :math:`\lvert\psi_{nlm}\rvert^2` on the grid.
32
+ """
33
+ if extent is None:
34
+ extent = 3 * orbital.n**2 * orbital.a0 / orbital.Z + 8
35
+
36
+ lin = np.linspace(-extent, extent, n_points)
37
+ X, Y, Z = np.meshgrid(lin, lin, lin, indexing="ij")
38
+ r = np.sqrt(X**2 + Y**2 + Z**2)
39
+ r_safe = np.where(r == 0, 1e-9, r)
40
+ theta = np.arccos(np.clip(Z / r_safe, -1, 1))
41
+ phi = np.arctan2(Y, X) % (2 * np.pi)
42
+
43
+ density = orbital.density(r, theta, phi)
44
+ return X, Y, Z, density
45
+
46
+
47
+ def plot_orbital_cloud(
48
+ orbital: HydrogenOrbital, extent: float | None = None, n_points: int = 55, iso_fraction: float = 0.02, surface_count: int = 12
49
+ ) -> go.Figure:
50
+ r"""Volumetric isosurface render of the electron probability density.
51
+
52
+ Renders :math:`\lvert\psi_{nlm}(r,\theta,\phi)\rvert^2` for a hydrogen
53
+ orbital as a set of nested isosurfaces.
54
+
55
+ Parameters
56
+ ----------
57
+ orbital : physicskit.quantum.chapters.hydrogen_am.HydrogenOrbital
58
+ The orbital to render.
59
+ extent : float or None, optional
60
+ Half-width of the cubic grid; see :func:`orbital_density_grid`.
61
+ n_points : int, default=55
62
+ Number of grid points along each Cartesian axis.
63
+ iso_fraction : float, default=0.02
64
+ Lowest isosurface level, as a fraction of the peak density.
65
+ surface_count : int, default=12
66
+ Number of nested isosurfaces to draw.
67
+
68
+ Returns
69
+ -------
70
+ plotly.graph_objects.Figure
71
+ """
72
+ X, Y, Z, density = orbital_density_grid(orbital, extent, n_points)
73
+ dmax = density.max()
74
+
75
+ fig = go.Figure(
76
+ data=go.Volume(
77
+ x=X.flatten(),
78
+ y=Y.flatten(),
79
+ z=Z.flatten(),
80
+ value=density.flatten(),
81
+ isomin=iso_fraction * dmax,
82
+ isomax=dmax,
83
+ opacity=0.12,
84
+ surface_count=surface_count,
85
+ colorscale="Plasma",
86
+ caps=dict(x_show=False, y_show=False, z_show=False),
87
+ )
88
+ )
89
+ fig.update_layout(
90
+ title=f"|psi_{{{orbital.n},{orbital.l},{orbital.m}}}|^2",
91
+ scene=dict(xaxis_title="x", yaxis_title="y", zaxis_title="z", aspectmode="cube"),
92
+ margin=dict(l=0, r=0, t=30, b=0),
93
+ )
94
+ return fig
95
+
96
+
97
+ def animate_orbital_beating(
98
+ orb_a: HydrogenOrbital,
99
+ orb_b: HydrogenOrbital,
100
+ times: np.ndarray,
101
+ extent: float | None = None,
102
+ n_points: int = 35,
103
+ ca: complex = 2**-0.5,
104
+ cb: complex = 2**-0.5,
105
+ iso_fraction: float = 0.05,
106
+ surface_count: int = 8,
107
+ ) -> go.Figure:
108
+ r"""Plotly ``frames``-based animation of a two-orbital density beating.
109
+
110
+ Unlike a single stationary orbital (:func:`plot_orbital_cloud`, static in
111
+ time since :math:`\lvert\psi_{nlm}\rvert^2` is time-independent), the
112
+ density of a coherent superposition of two eigenstates
113
+ (:func:`~physicskit.quantum.chapters.hydrogen_am.orbital_superposition_density`)
114
+ genuinely reshapes at the Bohr frequency :math:`\omega_{ab}=E_a-E_b` --
115
+ rendered here as a play-button-driven sequence of isosurface frames.
116
+
117
+ Parameters
118
+ ----------
119
+ orb_a, orb_b : HydrogenOrbital
120
+ The two eigenstates in the superposition.
121
+ times : numpy.ndarray
122
+ Times to render frames at.
123
+ extent : float or None, optional
124
+ Half-width of the cubic grid; defaults to a value scaled to
125
+ ``orb_a``'s expected extent.
126
+ n_points : int, default=35
127
+ Number of grid points along each Cartesian axis (kept modest since
128
+ a full 3D grid is evaluated at every frame).
129
+ ca, cb : complex, default=1/sqrt(2) each
130
+ Superposition amplitudes.
131
+ iso_fraction : float, default=0.05
132
+ Lowest isosurface level, as a fraction of the peak density (over all
133
+ frames).
134
+ surface_count : int, default=8
135
+ Number of nested isosurfaces to draw per frame.
136
+
137
+ Returns
138
+ -------
139
+ plotly.graph_objects.Figure
140
+ With a "Play"/"Pause" button stepping through ``times``.
141
+ """
142
+ if extent is None:
143
+ extent = 3 * orb_a.n**2 * orb_a.a0 / orb_a.Z + 8
144
+
145
+ lin = np.linspace(-extent, extent, n_points)
146
+ X, Y, Z = np.meshgrid(lin, lin, lin, indexing="ij")
147
+ r = np.sqrt(X**2 + Y**2 + Z**2)
148
+ r_safe = np.where(r == 0, 1e-9, r)
149
+ theta = np.arccos(np.clip(Z / r_safe, -1, 1))
150
+ phi = np.arctan2(Y, X) % (2 * np.pi)
151
+
152
+ densities = [orbital_superposition_density(orb_a, orb_b, r, theta, phi, t, ca, cb) for t in times]
153
+ dmax = max(d.max() for d in densities)
154
+
155
+ def volume_trace(density):
156
+ return go.Volume(
157
+ x=X.flatten(),
158
+ y=Y.flatten(),
159
+ z=Z.flatten(),
160
+ value=density.flatten(),
161
+ isomin=iso_fraction * dmax,
162
+ isomax=dmax,
163
+ opacity=0.12,
164
+ surface_count=surface_count,
165
+ colorscale="Plasma",
166
+ caps=dict(x_show=False, y_show=False, z_show=False),
167
+ )
168
+
169
+ frames = [go.Frame(data=[volume_trace(d)], name=f"{i}") for i, d in enumerate(densities)]
170
+
171
+ fig = go.Figure(data=[volume_trace(densities[0])], frames=frames)
172
+ fig.update_layout(
173
+ title=f"|c_a psi_{{{orb_a.n},{orb_a.l},{orb_a.m}}} + c_b psi_{{{orb_b.n},{orb_b.l},{orb_b.m}}}|^2",
174
+ scene=dict(xaxis_title="x", yaxis_title="y", zaxis_title="z", aspectmode="cube"),
175
+ margin=dict(l=0, r=0, t=30, b=0),
176
+ updatemenus=[
177
+ dict(
178
+ type="buttons",
179
+ showactive=False,
180
+ buttons=[
181
+ dict(label="Play", method="animate", args=[None, dict(frame=dict(duration=100, redraw=True), fromcurrent=True)]),
182
+ dict(label="Pause", method="animate", args=[[None], dict(frame=dict(duration=0, redraw=False), mode="immediate")]),
183
+ ],
184
+ )
185
+ ],
186
+ )
187
+ return fig