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,305 @@
1
+ """Site and bond percolation on the square lattice, via Hoshen-Kopelman cluster labeling.
2
+
3
+ Percolation theory studies the sudden, geometric phase transition that
4
+ appears when a fraction ``p`` of a lattice's sites (or bonds) are randomly
5
+ occupied: below a critical threshold :math:`p_c` only small, finite clusters
6
+ exist, while above it a single cluster spans the entire system. The
7
+ transition is purely geometric -- there is no energy scale or temperature --
8
+ yet it shares the full apparatus of critical phenomena: a sharp threshold,
9
+ power-law cluster-size distributions, and universal critical exponents.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import numpy as np
15
+
16
+ __all__ = ["Percolation2D", "hoshen_kopelman"]
17
+
18
+
19
+ def hoshen_kopelman(occupied):
20
+ """Label connected clusters of occupied sites with the Hoshen-Kopelman algorithm.
21
+
22
+ A single raster pass assigns provisional labels while a union-find
23
+ structure tracks label equivalences (created whenever a site connects two
24
+ previously separate provisional clusters); a second pass resolves every
25
+ label to its cluster's root.
26
+
27
+ Parameters
28
+ ----------
29
+ occupied : ndarray of shape (L, L), dtype bool
30
+ Site occupation grid (open boundary conditions -- no wraparound).
31
+
32
+ Returns
33
+ -------
34
+ ndarray of shape (L, L), dtype int64
35
+ Cluster label at each site; ``0`` marks unoccupied sites, and
36
+ occupied sites sharing a label belong to the same connected cluster.
37
+ Labels are not necessarily contiguous integers.
38
+
39
+ Examples
40
+ --------
41
+ >>> grid = np.array([[True, True, False], [False, True, False], [False, False, True]])
42
+ >>> labels = hoshen_kopelman(grid)
43
+ >>> bool(labels[0, 0] == labels[0, 1] == labels[1, 1])
44
+ True
45
+ >>> bool(labels[2, 2] not in (0, labels[0, 0]))
46
+ True
47
+ """
48
+ L0, L1 = occupied.shape
49
+ labels = np.zeros((L0, L1), dtype=np.int64)
50
+ parent = [0]
51
+
52
+ def find(x):
53
+ root = x
54
+ while parent[root] != root:
55
+ root = parent[root]
56
+ while parent[x] != root:
57
+ parent[x], x = root, parent[x]
58
+ return root
59
+
60
+ def union(x, y):
61
+ rx, ry = find(x), find(y)
62
+ if rx != ry:
63
+ parent[max(rx, ry)] = min(rx, ry)
64
+
65
+ next_label = 1
66
+ for i in range(L0):
67
+ for j in range(L1):
68
+ if not occupied[i, j]:
69
+ continue
70
+ left = labels[i, j - 1] if j > 0 and occupied[i, j - 1] else 0
71
+ up = labels[i - 1, j] if i > 0 and occupied[i - 1, j] else 0
72
+ if left == 0 and up == 0:
73
+ labels[i, j] = next_label
74
+ parent.append(next_label)
75
+ next_label += 1
76
+ elif left != 0 and up == 0:
77
+ labels[i, j] = find(left)
78
+ elif left == 0 and up != 0:
79
+ labels[i, j] = find(up)
80
+ else:
81
+ union(left, up)
82
+ labels[i, j] = find(left)
83
+
84
+ for i in range(L0):
85
+ for j in range(L1):
86
+ if labels[i, j] != 0:
87
+ labels[i, j] = find(labels[i, j])
88
+ return labels
89
+
90
+
91
+ class Percolation2D:
92
+ """Site or bond percolation on a periodic-free (open-boundary) square lattice.
93
+
94
+ Parameters
95
+ ----------
96
+ L : int, default=64
97
+ Linear lattice size.
98
+ p : float, default=0.5
99
+ Occupation probability: fraction of sites (site percolation) or
100
+ bonds (bond percolation) that are open.
101
+ mode : {"site", "bond"}, default="site"
102
+ Percolation type. Known exact thresholds for the square lattice are
103
+ :math:`p_c \\approx 0.592746` (site) and :math:`p_c = 0.5` (bond,
104
+ exact by self-duality).
105
+ seed : int, optional
106
+ Seed for reproducible lattice realizations.
107
+
108
+ Attributes
109
+ ----------
110
+ labels : ndarray of shape (L, L)
111
+ Cluster labels of the current realization, from
112
+ :func:`hoshen_kopelman`.
113
+ """
114
+
115
+ #: Known threshold for square-lattice site percolation (numerical estimate).
116
+ P_C_SITE = 0.592746
117
+ #: Exact threshold for square-lattice bond percolation (self-duality).
118
+ P_C_BOND = 0.5
119
+
120
+ def __init__(self, L=64, p=0.5, mode="site", seed=None):
121
+ if mode not in ("site", "bond"):
122
+ raise ValueError("mode must be 'site' or 'bond'")
123
+ self.L = L
124
+ self.p = p
125
+ self.mode = mode
126
+ self._rng = np.random.default_rng(seed)
127
+ self.labels = None
128
+ self.generate()
129
+
130
+ @property
131
+ def p_c(self):
132
+ """Threshold occupation probability for the current ``mode``."""
133
+ return self.P_C_SITE if self.mode == "site" else self.P_C_BOND
134
+
135
+ def generate(self, p=None):
136
+ """Draw a fresh random realization and label its clusters.
137
+
138
+ Parameters
139
+ ----------
140
+ p : float, optional
141
+ Occupation probability to use; defaults to ``self.p``. If given,
142
+ also updates ``self.p``.
143
+
144
+ Returns
145
+ -------
146
+ ndarray of shape (L, L)
147
+ The updated cluster ``labels`` array.
148
+ """
149
+ if p is not None:
150
+ self.p = p
151
+ if self.mode == "site":
152
+ occupied = self._rng.random((self.L, self.L)) < self.p
153
+ else:
154
+ occupied = self._bond_occupation_to_sites(self.p)
155
+ self.labels = hoshen_kopelman(occupied)
156
+ return self.labels
157
+
158
+ def _bond_occupation_to_sites(self, p):
159
+ """Build an effective all-occupied site grid whose HK labeling respects bond connectivity.
160
+
161
+ Bond percolation is reduced to Hoshen-Kopelman site labeling by
162
+ working on a doubled lattice: real sites at even indices, and
163
+ "bond sites" at the odd indices between them, present only when the
164
+ corresponding bond is open.
165
+ """
166
+ L = self.L
167
+ expanded = np.zeros((2 * L - 1, 2 * L - 1), dtype=bool)
168
+ expanded[0::2, 0::2] = True # all real sites present
169
+
170
+ h_bonds = self._rng.random((L, L - 1)) < p # horizontal bonds
171
+ v_bonds = self._rng.random((L - 1, L)) < p # vertical bonds
172
+ expanded[0::2, 1::2] = h_bonds
173
+ expanded[1::2, 0::2] = v_bonds
174
+ return expanded
175
+
176
+ def spanning_labels(self):
177
+ """Cluster labels of the current realization that span top to bottom.
178
+
179
+ For bond percolation the doubled lattice is used internally, but
180
+ returned labels index the real (even-index) sites.
181
+
182
+ Returns
183
+ -------
184
+ ndarray
185
+ Labels present on both the first and last row of real sites.
186
+ """
187
+ if self.mode == "site":
188
+ top_labels = set(self.labels[0, :]) - {0}
189
+ bottom_labels = set(self.labels[-1, :]) - {0}
190
+ else:
191
+ top_labels = set(self.labels[0, 0::2]) - {0}
192
+ bottom_labels = set(self.labels[-1, 0::2]) - {0}
193
+ return np.array(sorted(top_labels & bottom_labels), dtype=np.int64)
194
+
195
+ def spans(self):
196
+ """Whether the current realization has a top-to-bottom spanning cluster."""
197
+ return len(self.spanning_labels()) > 0
198
+
199
+ def _real_labels(self):
200
+ """Cluster labels restricted to real (non-bond-auxiliary) lattice sites."""
201
+ return self.labels if self.mode == "site" else self.labels[0::2, 0::2]
202
+
203
+ def largest_cluster_size(self):
204
+ """Number of (real) sites in the largest cluster of the current realization."""
205
+ sizes = self.cluster_size_distribution()
206
+ return int(sizes.max()) if sizes.size else 0
207
+
208
+ def cluster_size_distribution(self):
209
+ """Sizes of every cluster in the current realization.
210
+
211
+ At the percolation threshold, the number of clusters of size ``s``
212
+ follows a power law :math:`n_s \\sim s^{-\\tau}` with the Fisher
213
+ exponent :math:`\\tau = 187/91 \\approx 2.055` for 2D percolation --
214
+ the geometric analogue of the divergent susceptibility seen at a
215
+ thermal critical point.
216
+
217
+ Returns
218
+ -------
219
+ ndarray
220
+ Cluster sizes, in sites, one entry per cluster (including the
221
+ spanning cluster if one exists).
222
+ """
223
+ real_labels = self._real_labels()
224
+ labels = real_labels[real_labels != 0]
225
+ if labels.size == 0:
226
+ return np.array([], dtype=np.int64)
227
+ _, counts = np.unique(labels, return_counts=True)
228
+ return counts
229
+
230
+ def spanning_probability(self, p_values, n_trials=100):
231
+ """Monte Carlo estimate of the spanning probability :math:`P_{\\text{span}}(p)`.
232
+
233
+ For each probability in ``p_values``, generates ``n_trials``
234
+ independent realizations and reports the fraction that contain a
235
+ top-to-bottom spanning cluster. As :math:`L \\to \\infty` this curve
236
+ sharpens into a step function at :math:`p_c`.
237
+
238
+ Parameters
239
+ ----------
240
+ p_values : array_like
241
+ Occupation probabilities to sample.
242
+ n_trials : int, default=100
243
+ Independent realizations per probability.
244
+
245
+ Returns
246
+ -------
247
+ p_values : ndarray
248
+ P_span : ndarray
249
+ Estimated spanning probability at each ``p``.
250
+
251
+ Examples
252
+ --------
253
+ >>> perc = Percolation2D(L=20, seed=0)
254
+ >>> p, P = perc.spanning_probability([0.3, 0.593, 0.8], n_trials=20)
255
+ >>> bool(P[0] < P[2])
256
+ True
257
+ """
258
+ p_values = np.asarray(p_values, dtype=np.float64)
259
+ P_span = np.empty(len(p_values))
260
+ for k, p in enumerate(p_values):
261
+ hits = 0
262
+ for _ in range(n_trials):
263
+ self.generate(p)
264
+ hits += self.spans()
265
+ P_span[k] = hits / n_trials
266
+ return p_values, P_span
267
+
268
+ def fractal_dimension(self, n_trials=20):
269
+ """Estimate the fractal dimension of the largest cluster at :math:`p = p_c`.
270
+
271
+ A single lattice size gives no direct mass-versus-``L`` scaling, so
272
+ instead this estimates :math:`d_f` from the mass-radius relation of
273
+ the largest cluster in each realization,
274
+ :math:`d_f = \\log(\\text{cluster size}) / \\log(R_g)`, where
275
+ :math:`R_g` is the cluster's radius of gyration, averaged over
276
+ trials. The 2D percolation universality class predicts
277
+ :math:`d_f = 91/48 \\approx 1.896`.
278
+
279
+ Parameters
280
+ ----------
281
+ n_trials : int, default=20
282
+ Number of critical realizations to average over.
283
+
284
+ Returns
285
+ -------
286
+ float
287
+ Estimated fractal dimension.
288
+ """
289
+ dims = []
290
+ for _ in range(n_trials):
291
+ self.generate(self.p_c)
292
+ real_labels = self._real_labels()
293
+ labels = real_labels[real_labels != 0]
294
+ if labels.size == 0:
295
+ continue
296
+ values, counts = np.unique(labels, return_counts=True)
297
+ biggest = values[np.argmax(counts)]
298
+ ii, jj = np.nonzero(real_labels == biggest)
299
+ size = len(ii)
300
+ if size < 4:
301
+ continue
302
+ Rg = np.sqrt(np.mean((ii - ii.mean()) ** 2 + (jj - jj.mean()) ** 2))
303
+ if Rg > 0:
304
+ dims.append(np.log(size) / np.log(Rg))
305
+ return float(np.mean(dims)) if dims else float("nan")
@@ -0,0 +1,142 @@
1
+ """Random walks: diffusion, the Einstein relation, and the central limit theorem.
2
+
3
+ The random walk is arguably the most foundational model in statistical
4
+ physics: it underlies Einstein's 1905 explanation of Brownian motion (which
5
+ provided the first direct evidence for the atomic hypothesis), and its
6
+ Gaussian long-time limit is the simplest nontrivial instance of the central
7
+ limit theorem, whose universality is itself the deep reason so many
8
+ different microscopic models flow to the same few macroscopic diffusion
9
+ laws.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import numpy as np
15
+
16
+ from physicskit.statphys.core.monte_carlo import seed_numba_random
17
+ from physicskit.statphys.core.random_walk_engine import simulate_gaussian_walks, simulate_lattice_walks
18
+
19
+ __all__ = ["RandomWalk"]
20
+
21
+
22
+ class RandomWalk:
23
+ """An ensemble of independent random walkers used to study diffusion.
24
+
25
+ Parameters
26
+ ----------
27
+ n_walkers : int, default=500
28
+ Number of independent walkers in the ensemble.
29
+ n_steps : int, default=1000
30
+ Number of steps each walker takes.
31
+ dim : int, default=2
32
+ Spatial dimension.
33
+ kind : {"lattice", "gaussian"}, default="lattice"
34
+ ``"lattice"`` walkers take unit steps along a randomly chosen axis
35
+ (a simple-cubic lattice walk); ``"gaussian"`` walkers take
36
+ continuous, independent Gaussian steps in every dimension at every
37
+ time step (a discrete-time model of Brownian motion).
38
+ step_std : float, default=1.0
39
+ Per-axis standard deviation of a single step. Only used for
40
+ ``kind="gaussian"``.
41
+ seed : int, optional
42
+ Seed for reproducible trajectories.
43
+
44
+ Attributes
45
+ ----------
46
+ trajectories : ndarray of shape (n_steps + 1, n_walkers, dim) or None
47
+ Walker positions at every time, populated by :meth:`run`.
48
+
49
+ Examples
50
+ --------
51
+ >>> walk = RandomWalk(n_walkers=200, n_steps=200, dim=2, seed=0)
52
+ >>> t, msd = walk.mean_squared_displacement()
53
+ >>> bool(msd[-1] > msd[10])
54
+ True
55
+ """
56
+
57
+ def __init__(self, n_walkers=500, n_steps=1000, dim=2, kind="lattice", step_std=1.0, seed=None):
58
+ self.n_walkers = n_walkers
59
+ self.n_steps = n_steps
60
+ self.dim = dim
61
+ self.kind = kind
62
+ self.step_std = step_std
63
+ if seed is not None:
64
+ seed_numba_random(seed)
65
+ self.trajectories = None
66
+
67
+ def run(self):
68
+ """Simulate every walker's full trajectory.
69
+
70
+ Returns
71
+ -------
72
+ ndarray of shape (n_steps + 1, n_walkers, dim)
73
+ The same array stored in :attr:`trajectories`.
74
+ """
75
+ if self.kind == "lattice":
76
+ self.trajectories = simulate_lattice_walks(self.n_walkers, self.n_steps, self.dim).astype(np.float64)
77
+ elif self.kind == "gaussian":
78
+ self.trajectories = simulate_gaussian_walks(self.n_walkers, self.n_steps, self.dim, self.step_std)
79
+ else:
80
+ raise ValueError("kind must be 'lattice' or 'gaussian'")
81
+ return self.trajectories
82
+
83
+ def mean_squared_displacement(self):
84
+ """Ensemble-averaged mean squared displacement :math:`\\text{MSD}(t) = \\langle |r(t)|^2 \\rangle`.
85
+
86
+ Returns
87
+ -------
88
+ t : ndarray of shape (n_steps + 1,)
89
+ Time (in steps), starting at 0.
90
+ msd : ndarray of shape (n_steps + 1,)
91
+ Mean squared displacement from the (shared) origin at each time.
92
+ """
93
+ if self.trajectories is None:
94
+ self.run()
95
+ disp2 = np.sum(self.trajectories**2, axis=2)
96
+ msd = disp2.mean(axis=1)
97
+ t = np.arange(self.n_steps + 1)
98
+ return t, msd
99
+
100
+ def diffusion_coefficient(self):
101
+ """Estimate the diffusion coefficient D via the Einstein relation.
102
+
103
+ Fits :math:`\\text{MSD}(t) = 2 d D t` (a line through the origin,
104
+ least-squares) to the ensemble MSD, where :math:`d` is
105
+ :attr:`dim`.
106
+
107
+ Returns
108
+ -------
109
+ float
110
+ Estimated diffusion coefficient.
111
+ """
112
+ t, msd = self.mean_squared_displacement()
113
+ slope = np.sum(t[1:] * msd[1:]) / np.sum(t[1:] ** 2)
114
+ return float(slope / (2.0 * self.dim))
115
+
116
+ def final_displacement_histogram(self, axis=0, bins=40):
117
+ """Density histogram of the final-time displacement along one axis.
118
+
119
+ A demonstration of the central limit theorem: regardless of the
120
+ (highly non-Gaussian) single-step distribution, the sum of many
121
+ independent steps approaches a Gaussian.
122
+
123
+ Parameters
124
+ ----------
125
+ axis : int, default=0
126
+ Which spatial axis to histogram.
127
+ bins : int, default=40
128
+ Number of histogram bins.
129
+
130
+ Returns
131
+ -------
132
+ centers : ndarray of shape (bins,)
133
+ Bin center positions.
134
+ density : ndarray of shape (bins,)
135
+ Probability density in each bin.
136
+ """
137
+ if self.trajectories is None:
138
+ self.run()
139
+ final = self.trajectories[-1, :, axis]
140
+ density, edges = np.histogram(final, bins=bins, density=True)
141
+ centers = 0.5 * (edges[:-1] + edges[1:])
142
+ return centers, density
@@ -0,0 +1,148 @@
1
+ """Real-space renormalization group: Kadanoff block-spin coarse-graining.
2
+
3
+ Kadanoff's block-spin construction groups an Ising lattice into
4
+ :math:`b \\times b` blocks and replaces each block by a single effective spin
5
+ (here, majority rule with ``b = 2``), producing a new, smaller lattice at the
6
+ same nominal temperature. Iterating this map is a real-space renormalization
7
+ group transformation: starting configurations flow toward one of the
8
+ theory's fixed points -- a fully ordered state at :math:`T \\ll T_c`, a fully
9
+ disordered state at :math:`T \\gg T_c`, and a self-similar, scale-invariant
10
+ critical configuration at :math:`T = T_c`, where the coarse-grained lattice
11
+ looks statistically identical to the original.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import numpy as np
17
+
18
+ from physicskit.statphys.chapters.ising_lattice import Ising2D
19
+
20
+ __all__ = ["BlockSpinRG"]
21
+
22
+
23
+ class BlockSpinRG:
24
+ """Iterated 2x2 majority-rule block-spin coarse-graining of an Ising configuration.
25
+
26
+ Parameters
27
+ ----------
28
+ L : int, default=64
29
+ Linear size of the initial lattice. Should be a power of 2 times the
30
+ largest block factor you intend to reach, e.g. ``L=64`` supports up
31
+ to 6 coarse-graining steps.
32
+ T : float, default=None
33
+ Temperature at which to equilibrate the initial configuration, in
34
+ units of ``J/kB``. Defaults to the exact critical temperature
35
+ (``Ising2D.T_C``) if not given, i.e. the critical fixed point.
36
+ J : float, default=1.0
37
+ Ising coupling constant used to equilibrate the initial
38
+ configuration.
39
+ n_equil_sweeps : int, default=500
40
+ Wolff cluster updates used to equilibrate the initial fine-grained
41
+ configuration at temperature ``T`` before coarse-graining begins.
42
+ seed : int, optional
43
+ Seed for the initial equilibration and for majority-rule tie
44
+ breaking.
45
+
46
+ Attributes
47
+ ----------
48
+ initial_spins : ndarray of shape (L, L)
49
+ The equilibrated fine-grained configuration coarse-graining starts
50
+ from.
51
+ """
52
+
53
+ def __init__(self, L=64, T=None, J=1.0, n_equil_sweeps=500, seed=None):
54
+ self.L = L
55
+ self.J = J
56
+ self._rng = np.random.default_rng(seed)
57
+
58
+ model = Ising2D(L=L, J=J, seed=seed)
59
+ self.T = model.T_C if T is None else T
60
+ beta = 1.0 / self.T if self.T > 0 else np.inf
61
+ if np.isfinite(beta):
62
+ # Wolff cluster updates equilibrate far more reliably than single-spin
63
+ # Metropolis: at low T, Metropolis dynamics from a random start undergoes
64
+ # slow domain-wall coarsening that a modest sweep budget cannot outrun.
65
+ model.sweep(beta, algorithm="wolff", n_sweeps=n_equil_sweeps)
66
+ self.initial_spins = model.spins.copy()
67
+
68
+ def coarse_grain_step(self, spins):
69
+ """Apply one 2x2 majority-rule block-spin transformation.
70
+
71
+ Each non-overlapping :math:`2 \\times 2` block of the input is
72
+ replaced by a single spin equal to the sign of the block's sum; an
73
+ exact tie (sum of zero) is broken by an independent fair coin flip.
74
+
75
+ Parameters
76
+ ----------
77
+ spins : ndarray of shape (L, L)
78
+ Input configuration. ``L`` must be even.
79
+
80
+ Returns
81
+ -------
82
+ ndarray of shape (L // 2, L // 2)
83
+ Coarse-grained spin configuration.
84
+ """
85
+ L = spins.shape[0]
86
+ if L % 2 != 0:
87
+ raise ValueError("lattice size must be even to block by 2x2")
88
+ blocks = spins.reshape(L // 2, 2, L // 2, 2).sum(axis=(1, 3))
89
+ new_spins = np.sign(blocks).astype(np.int64)
90
+ ties = new_spins == 0
91
+ if np.any(ties):
92
+ coin = self._rng.choice(np.array([-1, 1], dtype=np.int64), size=ties.sum())
93
+ new_spins[ties] = coin
94
+ return new_spins
95
+
96
+ def iterate(self, n_steps=None):
97
+ """Repeatedly coarse-grain the initial configuration.
98
+
99
+ Parameters
100
+ ----------
101
+ n_steps : int, optional
102
+ Number of coarse-graining steps. Defaults to
103
+ ``floor(log2(L)) - 1``, i.e. as many as keep the lattice at least
104
+ :math:`2 \\times 2`.
105
+
106
+ Returns
107
+ -------
108
+ list of ndarray
109
+ The sequence of configurations
110
+ ``[initial_spins, step_1, step_2, ...]``, of shrinking size
111
+ :math:`L, L/2, L/4, \\ldots`
112
+
113
+ Examples
114
+ --------
115
+ >>> rg = BlockSpinRG(L=16, T=100.0, seed=0)
116
+ >>> grids = rg.iterate(n_steps=3)
117
+ >>> [g.shape[0] for g in grids]
118
+ [16, 8, 4, 2]
119
+ """
120
+ if n_steps is None:
121
+ n_steps = int(np.floor(np.log2(self.L))) - 1
122
+ grids = [self.initial_spins]
123
+ current = self.initial_spins
124
+ for _ in range(n_steps):
125
+ current = self.coarse_grain_step(current)
126
+ grids.append(current)
127
+ return grids
128
+
129
+ @staticmethod
130
+ def order_parameter(spins):
131
+ """Magnitude of the mean magnetization per site, :math:`|\\langle s \\rangle|`.
132
+
133
+ A convenient scalar summary of a grid in the RG flow: it drifts to
134
+ ``1`` under iteration when the starting temperature is below
135
+ :math:`T_c` (flow to the ordered fixed point), to ``0`` when above
136
+ (flow to the disordered fixed point), and hovers at an intermediate,
137
+ scale-invariant value at :math:`T_c`.
138
+
139
+ Parameters
140
+ ----------
141
+ spins : ndarray
142
+ A spin configuration.
143
+
144
+ Returns
145
+ -------
146
+ float
147
+ """
148
+ return float(np.abs(spins.mean()))
@@ -0,0 +1,109 @@
1
+ """The Bak-Tang-Wiesenfeld sandpile: self-organized criticality.
2
+
3
+ Ordinary critical phenomena require fine-tuning a parameter (temperature,
4
+ occupation probability) to a special value. Bak, Tang, and Wiesenfeld's 1987
5
+ sandpile model was the first example of a system that tunes *itself* to a
6
+ critical state through its own slow-driving, fast-relaxation dynamics --
7
+ "self-organized criticality" (SOC) -- and was proposed as a generic
8
+ explanation for the ubiquity of power laws in nature (earthquakes, forest
9
+ fires, neural avalanches), without needing anyone to tune anything.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import numpy as np
15
+
16
+ from physicskit.statphys.core.sandpile_engine import topple_to_stability
17
+
18
+ __all__ = ["BTWSandpile"]
19
+
20
+
21
+ class BTWSandpile:
22
+ """The Bak-Tang-Wiesenfeld sandpile on an L x L grid with open (absorbing) boundaries.
23
+
24
+ Grains are added one at a time to a chosen (or random) site; whenever a
25
+ site's height reaches the toppling threshold, it topples, distributing
26
+ one grain to each orthogonal neighbor (grains that fall off the grid's
27
+ edge are permanently lost). A single added grain can trigger a chain
28
+ reaction of topplings -- an avalanche -- whose size has no
29
+ characteristic scale once the pile has self-organized to its critical
30
+ state.
31
+
32
+ Parameters
33
+ ----------
34
+ L : int, default=64
35
+ Linear grid size.
36
+ threshold : int, default=4
37
+ Toppling threshold (4 is the standard value on the square lattice).
38
+ seed : int, optional
39
+ Seed for the random drop-site sequence.
40
+
41
+ Attributes
42
+ ----------
43
+ heights : ndarray of shape (L, L)
44
+ Current pile heights; always ``< threshold`` everywhere immediately
45
+ after a call to :meth:`add_grain` or :meth:`run`.
46
+ """
47
+
48
+ def __init__(self, L=64, threshold=4, seed=None):
49
+ self.L = L
50
+ self.threshold = threshold
51
+ self._rng = np.random.default_rng(seed)
52
+ self.heights = np.zeros((L, L), dtype=np.int64)
53
+
54
+ def add_grain(self, site=None):
55
+ """Add one grain and relax the pile to stability.
56
+
57
+ Parameters
58
+ ----------
59
+ site : tuple of int, optional
60
+ ``(i, j)`` grid coordinates to drop the grain at. A uniformly
61
+ random site is chosen if not given.
62
+
63
+ Returns
64
+ -------
65
+ int
66
+ Avalanche size: the number of individual topplings triggered by
67
+ this grain (``0`` if it did not trigger any toppling).
68
+ """
69
+ if site is None:
70
+ i = self._rng.integers(0, self.L)
71
+ j = self._rng.integers(0, self.L)
72
+ else:
73
+ i, j = site
74
+ self.heights[i, j] += 1
75
+ return topple_to_stability(self.heights, self.threshold)
76
+
77
+ def run(self, n_grains, warmup=0):
78
+ """Drop many grains at random sites, recording each one's avalanche size.
79
+
80
+ Parameters
81
+ ----------
82
+ n_grains : int
83
+ Number of grains to add and record after the warmup period.
84
+ warmup : int, default=0
85
+ Grains added first, to let the pile reach its self-organized
86
+ critical state, whose avalanche sizes are discarded.
87
+
88
+ Returns
89
+ -------
90
+ ndarray of shape (n_grains,), dtype int64
91
+ Avalanche size triggered by each recorded grain.
92
+
93
+ Examples
94
+ --------
95
+ >>> pile = BTWSandpile(L=20, seed=0)
96
+ >>> sizes = pile.run(n_grains=500, warmup=500)
97
+ >>> sizes.shape
98
+ (500,)
99
+ """
100
+ for _ in range(warmup):
101
+ self.add_grain()
102
+ sizes = np.empty(n_grains, dtype=np.int64)
103
+ for k in range(n_grains):
104
+ sizes[k] = self.add_grain()
105
+ return sizes
106
+
107
+ def total_grains(self):
108
+ """Total number of grains currently on the pile."""
109
+ return int(self.heights.sum())