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,207 @@
1
+ """Embedded Gaussian ensembles (EGOE(k)/EGUE(k)) and the Two-Body Random
2
+ Ensemble (TBRE, k=2) -- random k-body interactions among m fermions
3
+ distributed over N single-particle levels.
4
+
5
+ References
6
+ ----------
7
+ K. K. Mon, J. B. French, "Statistical properties of many-particle
8
+ spectra", Ann. Phys. 95 (1975) 90 -- the k-body embedded ensemble
9
+ construction and the celebrated result that the many-body density of
10
+ states approaches a GAUSSIAN (not the semicircle law) as m, N -> infinity
11
+ at fixed k >= 2, k < m.
12
+ T. A. Brody, J. Flores, J. B. French, P. A. Mello, A. Pandey,
13
+ S. S. M. Wong, "Random-matrix physics: spectrum and strength
14
+ fluctuations", Rev. Mod. Phys. 53 (1981) 385 -- review.
15
+ V. K. B. Kota, "Embedded Random Matrix Ensembles in Quantum Physics",
16
+ Lecture Notes in Physics 884, Springer, 2014 -- comprehensive reference.
17
+ T. Papenbrock, H. A. Weidenmuller, "Colloquium: Random matrices and
18
+ chaos in nuclear physics", Rev. Mod. Phys. 79 (2007) 997.
19
+
20
+ Unlike every classical ensemble in this package (i.i.d. matrix entries),
21
+ the many-body Hamiltonian matrix here is built by EMBEDDING a random
22
+ k-body interaction into the m-particle Fock space: the interaction
23
+ itself is a Hermitian random (GOE/GUE-type) matrix V on the space of
24
+ k-particle Slater determinants (dimension C(N, k)), and the m-particle
25
+ Hamiltonian is
26
+
27
+ H = sum_{I, J} V_{I, J} * a^dagger_I a_J
28
+
29
+ summed over all k-index tuples I, J (I = i_1 < ... < i_k, similarly J),
30
+ with a^dagger_I = a^dagger_{i_1} ... a^dagger_{i_k} and
31
+ a_J = a_{j_k} ... a_{j_1} (reversed order, so a^dagger_I a_J is built
32
+ from creation operators applied in ASCENDING index order and
33
+ annihilation operators in DESCENDING index order -- get this backwards
34
+ and Hermiticity silently survives but the exact k=m identity below does
35
+ not, which is exactly how an initial, subtly wrong sign convention
36
+ during development was caught).
37
+
38
+ Because H is built from a SHARED set of k-body matrix elements rather
39
+ than independent entries, the resulting many-body matrix elements are
40
+ strongly correlated (unlike GOE) -- this correlation structure is
41
+ exactly what drives the many-body density of states toward a Gaussian
42
+ rather than a semicircle as m, N grow (Mon-French 1975), the qualitative
43
+ signature this ensemble exists to demonstrate.
44
+
45
+ Implementation: creation/annihilation operators are realized via the
46
+ standard Jordan-Wigner tensor-product construction over N qubits (one
47
+ per single-particle level, ``|0>``/``|1>`` = unoccupied/occupied) -- the SAME
48
+ technique already used for SYK's Majorana operators
49
+ (``physicskit.rmt.ensembles.syk``), just for fermionic number-conserving ladder
50
+ operators instead. H is built on the full 2^N Fock space, then restricted
51
+ to the fixed-m-particle sector (dimension C(N, m)) by selecting the
52
+ appropriate basis states -- exact, not an approximation, since
53
+ number-conserving k-body terms never mix different particle-number
54
+ sectors.
55
+
56
+ Verified during development (see ``tests/test_embedded.py``), independent
57
+ of trusting the construction's well-known status in the literature:
58
+
59
+ - H is exactly Hermitian and exactly commutes with the total particle
60
+ number operator (both to machine precision).
61
+ - The celebrated special case k = m: with only m particles present, a
62
+ k=m-body interaction acts on all of them at once, so the embedding is
63
+ trivial and the m-particle Hamiltonian reduces EXACTLY (not merely
64
+ statistically) to the k-body matrix V itself -- checked directly for
65
+ k=m=2 and k=m=3 to machine precision, catching the operator-ordering
66
+ sign bug mentioned above during development.
67
+
68
+ Cost note (genuinely different from the classical ensembles, exactly
69
+ like SYK): the Fock-space dimension is 2^N, and building H requires
70
+ O(C(N,k)^2) dense Hilbert-space operator products -- exponential in N,
71
+ not polynomial. Keep ``n_levels`` small (roughly <= 10) for interactive
72
+ use.
73
+
74
+ ``beta`` in {1, 2} selects a real-symmetric (EGOE, "orthogonal") or
75
+ complex-Hermitian (EGUE, "unitary") random two-body interaction V; no
76
+ simple universal ``natural_scale`` rescaling is attempted (unlike GOE's
77
+ sqrt(n), the many-body spectral width here depends on N, m, and k
78
+ through a nontrivial combinatorial moment formula -- see Mon-French
79
+ 1975 -- not implemented here).
80
+ """
81
+
82
+ from __future__ import annotations
83
+
84
+ from itertools import combinations
85
+
86
+ import numpy as np
87
+
88
+ from .base import MatrixEnsemble
89
+
90
+ _I2 = np.eye(2, dtype=complex)
91
+ _Z = np.array([[1.0, 0.0], [0.0, -1.0]], dtype=complex)
92
+ _CREATE_LOCAL = np.array([[0.0, 0.0], [1.0, 0.0]], dtype=complex) # |0>=unoccupied -> |1>=occupied
93
+ _ANNIHILATE_LOCAL = np.array([[0.0, 1.0], [0.0, 0.0]], dtype=complex)
94
+
95
+
96
+ def _fermion_ladder_operators(n_levels: int) -> list[np.ndarray]:
97
+ """The N fermionic creation operators a^dagger_1, ..., a^dagger_N as
98
+ dense 2^N x 2^N complex matrices (Jordan-Wigner construction; the
99
+ corresponding annihilation operators are their conjugate transposes).
100
+ """
101
+ creators = []
102
+ for k in range(n_levels):
103
+ factors = [_Z] * k + [_CREATE_LOCAL] + [_I2] * (n_levels - k - 1)
104
+ op = factors[0]
105
+ for factor in factors[1:]:
106
+ op = np.kron(op, factor)
107
+ creators.append(op)
108
+ return creators
109
+
110
+
111
+ class EmbeddedGaussianEnsemble(MatrixEnsemble):
112
+ """EGOE(k)/EGUE(k): m fermions in N single-particle levels,
113
+ interacting via a random k-body interaction (see module docstring).
114
+
115
+ Parameters
116
+ ----------
117
+ n_particles : int
118
+ Number of fermions m.
119
+ n_levels : int
120
+ Number of single-particle levels N (>= n_particles). Keep small
121
+ (roughly <= 10) -- see the module docstring's cost note.
122
+ k : int, optional
123
+ Interaction body-rank (default 2, i.e. TBRE). Must satisfy
124
+ 2 <= k <= n_particles.
125
+ beta : int, optional
126
+ 1 (real symmetric interaction, EGOE) or 2 (complex Hermitian,
127
+ EGUE).
128
+ """
129
+
130
+ def __init__(
131
+ self,
132
+ n_particles: int,
133
+ n_levels: int,
134
+ k: int = 2,
135
+ beta: int = 1,
136
+ seed: int | np.random.Generator | None = None,
137
+ ) -> None:
138
+ if beta not in (1, 2):
139
+ raise ValueError(f"beta must be 1 or 2, got {beta}")
140
+ if not 2 <= k <= n_particles <= n_levels:
141
+ raise ValueError(f"require 2 <= k <= n_particles <= n_levels; got k={k}, n_particles={n_particles}, n_levels={n_levels}")
142
+ super().__init__(n_particles, seed=seed)
143
+ self.n_levels = n_levels
144
+ self.k = k
145
+ self.beta: float = beta
146
+ self._p_ops: list[np.ndarray] | None = None
147
+ self._basis: list[int] | None = None
148
+
149
+ def _operators(self) -> tuple[list[np.ndarray], list[int]]:
150
+ """The k-body creation operators P_a (one per k-subset of levels)
151
+ and the fixed-m-particle basis indices -- independent of the
152
+ random interaction V, so computed once and cached rather than
153
+ redone on every ``_sample_eigenvalues`` call.
154
+ """
155
+ if self._p_ops is None:
156
+ n_levels, k, m = self.n_levels, self.k, self.n
157
+ creators = _fermion_ladder_operators(n_levels)
158
+ tuples = list(combinations(range(n_levels), k))
159
+
160
+ def multi_create(idxs: tuple[int, ...]) -> np.ndarray:
161
+ op = creators[idxs[0]]
162
+ for idx in idxs[1:]:
163
+ op = op @ creators[idx]
164
+ return op
165
+
166
+ self._p_ops = [multi_create(t) for t in tuples]
167
+ dim = self._p_ops[0].shape[0]
168
+ self._basis = [state for state in range(dim) if bin(state).count("1") == m]
169
+ return self._p_ops, self._basis
170
+
171
+ def _sample_eigenvalues(self, rng: np.random.Generator) -> np.ndarray:
172
+ p_ops, basis = self._operators()
173
+ n_tuples = len(p_ops)
174
+
175
+ if self.beta == 1:
176
+ x = rng.standard_normal((n_tuples, n_tuples))
177
+ v = (x + x.T) / np.sqrt(2.0)
178
+ else:
179
+ x = (rng.standard_normal((n_tuples, n_tuples)) + 1j * rng.standard_normal((n_tuples, n_tuples))) / np.sqrt(2.0)
180
+ v = (x + x.conj().T) / 2.0
181
+
182
+ dim = p_ops[0].shape[0]
183
+ h = np.zeros((dim, dim), dtype=complex)
184
+ for a_idx in range(n_tuples):
185
+ q = sum(v[a_idx, b_idx] * p_ops[b_idx].conj().T for b_idx in range(n_tuples))
186
+ h += p_ops[a_idx] @ q
187
+
188
+ h_sub = h[np.ix_(basis, basis)]
189
+ h_sub = (h_sub + h_sub.conj().T) / 2.0
190
+ return np.linalg.eigvalsh(h_sub)
191
+
192
+ def natural_scale(self) -> float:
193
+ return 1.0
194
+
195
+
196
+ class TwoBodyRandomEnsemble(EmbeddedGaussianEnsemble):
197
+ """TBRE: the k=2 special case of :class:`EmbeddedGaussianEnsemble`,
198
+ by far the most commonly studied (nuclear shell-model-type) case."""
199
+
200
+ def __init__(
201
+ self,
202
+ n_particles: int,
203
+ n_levels: int,
204
+ beta: int = 1,
205
+ seed: int | np.random.Generator | None = None,
206
+ ) -> None:
207
+ super().__init__(n_particles, n_levels, k=2, beta=beta, seed=seed)
@@ -0,0 +1,153 @@
1
+ """Gaussian (Hermite) ensembles -- GOE, GUE, GSE -- plus the continuum
2
+ Dyson-index generalization, all built on the Dumitriu-Edelman tridiagonal
3
+ model (see ``physicskit.rmt.utils.tridiagonal``).
4
+
5
+ References
6
+ ----------
7
+ E. Wigner, Ann. Math. 62 (1955) 548; Ann. Math. 67 (1958) 325.
8
+ M. L. Mehta, "Random Matrices" (3rd ed.), Academic Press, 2004.
9
+ I. Dumitriu, A. Edelman, J. Math. Phys. 43, 5830 (2002).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import numpy as np
15
+
16
+ from ..utils.tridiagonal import sample_hermite_beta_eigenvalues
17
+ from .base import MatrixEnsemble
18
+
19
+
20
+ def _dense_hermite(n: int, beta: int, rng: np.random.Generator) -> np.ndarray:
21
+ """Dense n x n GOE/GUE matrix (beta=1 real symmetric, beta=2 complex
22
+ Hermitian), same off-diagonal-variance-1/diagonal-variance-2
23
+ convention as the tridiagonal model above.
24
+
25
+ Used only for ``_sample_eigenvalues_and_vectors``: unlike the
26
+ tridiagonal model, whose eigenVALUES are exact in distribution but
27
+ whose eigenVECTORS are an artifact of that particular sparse
28
+ representation (verified numerically during development -- their
29
+ inverse participation ratio was 2-3x too large relative to the exact
30
+ Haar-vector result below, and the gap grew with n), a genuinely
31
+ dense, rotationally/unitarily-invariant construction is needed to
32
+ get Haar-distributed eigenvectors. See ``_dense_hermite_quaternion``
33
+ for the beta=4 (GSE) analogue.
34
+ """
35
+ if beta == 1:
36
+ x = rng.standard_normal((n, n))
37
+ return (x + x.T) / np.sqrt(2.0)
38
+ x = (rng.standard_normal((n, n)) + 1j * rng.standard_normal((n, n))) / np.sqrt(2.0)
39
+ return (x + x.conj().T) / 2.0
40
+
41
+
42
+ def _dense_hermite_quaternion(n: int, rng: np.random.Generator) -> np.ndarray:
43
+ """Dense n x n quaternionic self-dual Hermitian matrix (GSE),
44
+ embedded as a 2n x 2n complex matrix via the standard
45
+ quaternion-to-2x2-complex-block map (same convention as
46
+ ``physicskit.rmt.ensembles.ginibre.GinSE``).
47
+
48
+ Its 2n eigenvalues come in exact Kramers double-degenerate pairs
49
+ (like GSE/CSE/EffGSE/JSE); ``_sample_eigenvalues_and_vectors`` keeps
50
+ one representative eigenvalue AND its (2n-dimensional complex, i.e.
51
+ n-quaternion) eigenvector per pair. Verified numerically during
52
+ development that folding each such eigenvector into n per-site
53
+ quaternion weights ``|v[2i]|^2 + |v[2i+1]|^2`` gives an inverse
54
+ participation ratio matching the exact beta=4 Haar-vector theory
55
+ (``physicskit.rmt.stats.localization.ipr_theory(n, beta=4)``) to four
56
+ significant figures -- see
57
+ ``physicskit.rmt.stats.localization.inverse_participation_ratio_quaternionic``
58
+ and ``tests/test_localization.py``.
59
+ """
60
+ a = rng.standard_normal((n, n))
61
+ b = rng.standard_normal((n, n))
62
+ c = rng.standard_normal((n, n))
63
+ d = rng.standard_normal((n, n))
64
+ m = np.zeros((2 * n, 2 * n), dtype=complex)
65
+ m[0::2, 0::2] = a + 1j * b
66
+ m[0::2, 1::2] = c + 1j * d
67
+ m[1::2, 0::2] = -c + 1j * d
68
+ m[1::2, 1::2] = a - 1j * b
69
+ return (m + m.conj().T) / 2.0
70
+
71
+
72
+ class HermiteBetaEnsemble(MatrixEnsemble):
73
+ """General beta-Hermite (Gaussian) ensemble.
74
+
75
+ beta=1, 2, 4 recover GOE, GUE, GSE exactly (same joint eigenvalue
76
+ density, not merely the same limiting law); any beta > 0 is a valid
77
+ continuum generalization, useful for studying the Dyson index as a
78
+ continuous "inverse temperature" parameter.
79
+
80
+ Use the named subclasses (:class:`GOE`, :class:`GUE`, :class:`GSE`)
81
+ for the classical cases; use this class directly for other beta.
82
+ """
83
+
84
+ def __init__(self, n: int, beta: float, seed: int | np.random.Generator | None = None) -> None:
85
+ """
86
+ Parameters
87
+ ----------
88
+ n : int
89
+ Matrix dimension.
90
+ beta : float
91
+ Dyson index; must be positive.
92
+ seed : int, numpy.random.Generator, or None, optional
93
+ """
94
+ if beta <= 0:
95
+ raise ValueError(f"beta must be positive, got {beta}")
96
+ super().__init__(n, seed=seed)
97
+ self.beta: float = float(beta)
98
+
99
+ def _sample_eigenvalues(self, rng: np.random.Generator) -> np.ndarray:
100
+ return sample_hermite_beta_eigenvalues(self.n, self.beta, rng)
101
+
102
+ def _sample_eigenvalues_and_vectors(self, rng: np.random.Generator) -> tuple[np.ndarray, np.ndarray]:
103
+ if self.beta not in (1, 2, 4):
104
+ raise NotImplementedError("return_eigenvectors=True is only supported for beta in (1, 2, 4) (GOE, GUE, GSE).")
105
+ if self.beta == 4:
106
+ h = _dense_hermite_quaternion(self.n, rng)
107
+ eigenvalues, eigenvectors = np.linalg.eigh(h)
108
+ # Exact Kramers double degeneracy: keep one eigenvalue and its
109
+ # (2n-dim complex) eigenvector per pair -- see
110
+ # _dense_hermite_quaternion's docstring.
111
+ return eigenvalues[0::2], eigenvectors[:, 0::2]
112
+ h = _dense_hermite(self.n, int(self.beta), rng)
113
+ eigenvalues, eigenvectors = np.linalg.eigh(h)
114
+ return eigenvalues, eigenvectors
115
+
116
+ def natural_scale(self) -> float:
117
+ # Verified empirically (see design notes): raw eigenvalue spread
118
+ # grows as sqrt(n * beta); dividing by this recovers the standard
119
+ # semicircle normalization with support [-2, 2] for all beta.
120
+ return np.sqrt(self.n * self.beta)
121
+
122
+
123
+ class GOE(HermiteBetaEnsemble):
124
+ """Gaussian Orthogonal Ensemble (beta=1).
125
+
126
+ Real symmetric matrices; time-reversal symmetric with T^2 = +1.
127
+ Altland-Zirnbauer class AI.
128
+ """
129
+
130
+ def __init__(self, n: int, seed: int | np.random.Generator | None = None) -> None:
131
+ super().__init__(n, beta=1, seed=seed)
132
+
133
+
134
+ class GUE(HermiteBetaEnsemble):
135
+ """Gaussian Unitary Ensemble (beta=2).
136
+
137
+ Complex Hermitian matrices; no time-reversal symmetry.
138
+ Altland-Zirnbauer class A.
139
+ """
140
+
141
+ def __init__(self, n: int, seed: int | np.random.Generator | None = None) -> None:
142
+ super().__init__(n, beta=2, seed=seed)
143
+
144
+
145
+ class GSE(HermiteBetaEnsemble):
146
+ """Gaussian Symplectic Ensemble (beta=4).
147
+
148
+ Quaternionic self-dual Hermitian matrices; time-reversal symmetric
149
+ with T^2 = -1. Altland-Zirnbauer class AII.
150
+ """
151
+
152
+ def __init__(self, n: int, seed: int | np.random.Generator | None = None) -> None:
153
+ super().__init__(n, beta=4, seed=seed)
@@ -0,0 +1,110 @@
1
+ """Ginibre ensembles -- GinOE (real), GinUE (complex), GinSE (quaternion).
2
+
3
+ References
4
+ ----------
5
+ J. Ginibre, "Statistical Ensembles of Complex, Quaternion, and Real
6
+ Matrices", J. Math. Phys. 6 (1965) 440.
7
+ A. Edelman, E. Kostlan, S. Shub, "How many eigenvalues of a random
8
+ matrix are real?", J. Amer. Math. Soc. 7 (1994) 247 -- the real-Ginibre
9
+ real-eigenvalue-count result, validated (against its large-n asymptotic
10
+ form, not the exact finite-n closed form -- see
11
+ ``physicskit.rmt.stats.real_ginibre`` for why) by
12
+ ``physicskit.rmt.validation.RealGinibreEigenvalueCount``.
13
+
14
+ Unlike the Hermitian/unitary ensembles built so far, Ginibre matrices
15
+ have NO symmetry constraint at all -- just i.i.d. entries -- so their
16
+ eigenvalues are genuinely complex and spread over a 2-D region (the unit
17
+ disk, asymptotically), not confined to the real line or unit circle.
18
+ ``Spectrum.eigenvalues`` for these ensembles is therefore a complex
19
+ array; ``natural_scale`` (sqrt(n)) rescales eigenvalues onto the unit
20
+ disk (Ginibre's exact result, not merely asymptotic, for finite n up to
21
+ this fixed rescaling).
22
+
23
+ Real vs. complex vs. quaternion Ginibre are NOT interchangeable dtypes
24
+ of the same construction -- they have qualitatively different eigenvalue
25
+ structure::
26
+
27
+ GinUE (complex): eigenvalues spread generically over the disk.
28
+ GinOE (real): a mix of purely real eigenvalues and complex-conjugate
29
+ pairs (the number of real eigenvalues grows like sqrt(2n/pi),
30
+ Edelman-Kostlan-Shub 1994) -- a vanishing fraction of n as
31
+ n -> infinity, but a structurally distinct, celebrated result
32
+ with no Hermitian-ensemble analogue.
33
+ GinSE (quaternion): a real quaternion matrix, embedded as a 2n x 2n
34
+ complex matrix via the standard quaternion-to-2x2-complex-block
35
+ map, has exactly 2n eigenvalues occurring in complex-conjugate
36
+ pairs (z, z-bar) -- but, importantly, this is NOT the same kind
37
+ of degeneracy as GSE/CSE (where the paired eigenvalues are
38
+ *exactly identical*, a true Kramers symmetry): here z and
39
+ z-bar are genuinely distinct eigenvalues whenever z is not real,
40
+ so GinSE keeps all 2n eigenvalues rather than de-duplicating.
41
+ """
42
+
43
+ import numpy as np
44
+
45
+ from .base import MatrixEnsemble
46
+
47
+
48
+ class GinOE(MatrixEnsemble):
49
+ """Real Ginibre ensemble.
50
+
51
+ ``Spectrum.eigenvalues`` holds n complex values per sample (purely
52
+ real entries have zero imaginary part).
53
+ """
54
+
55
+ beta: float = 1
56
+
57
+ def _sample_eigenvalues(self, rng: np.random.Generator) -> np.ndarray:
58
+ x = rng.standard_normal((self.n, self.n))
59
+ return np.linalg.eigvals(x).astype(complex)
60
+
61
+ def natural_scale(self) -> float:
62
+ return np.sqrt(self.n)
63
+
64
+
65
+ class GinUE(MatrixEnsemble):
66
+ """Complex Ginibre ensemble."""
67
+
68
+ beta: float = 2
69
+
70
+ def _sample_eigenvalues(self, rng: np.random.Generator) -> np.ndarray:
71
+ x = (rng.standard_normal((self.n, self.n)) + 1j * rng.standard_normal((self.n, self.n))) / np.sqrt(2.0)
72
+ return np.linalg.eigvals(x)
73
+
74
+ def natural_scale(self) -> float:
75
+ return np.sqrt(self.n)
76
+
77
+
78
+ class GinSE(MatrixEnsemble):
79
+ """Quaternion Ginibre ensemble.
80
+
81
+ ``n`` is the quaternion matrix dimension; each sample produces 2*n
82
+ complex eigenvalues (genuinely distinct conjugate pairs -- see
83
+ module docstring for why these are NOT de-duplicated, unlike GSE/CSE).
84
+ """
85
+
86
+ beta: float = 4
87
+
88
+ def _sample_eigenvalues(self, rng: np.random.Generator) -> np.ndarray:
89
+ n = self.n
90
+ a = rng.standard_normal((n, n))
91
+ b = rng.standard_normal((n, n))
92
+ c = rng.standard_normal((n, n))
93
+ d = rng.standard_normal((n, n))
94
+ # Vectorized quaternion-to-2x2-complex-block embedding (verified
95
+ # against the direct per-block loop construction to give an
96
+ # identical matrix): strided assignment places each block
97
+ # [[a+bi, c+di], [-c+di, a-bi]] / 2 directly, without a Python
98
+ # loop over n^2 blocks. The /2 normalizes entry scale to match
99
+ # the same unit-disk circular law radius as GinOE/GinUE after
100
+ # the shared sqrt(n) natural_scale -- verified numerically (see
101
+ # design notes / test suite).
102
+ m = np.zeros((2 * n, 2 * n), dtype=complex)
103
+ m[0::2, 0::2] = (a + 1j * b) / 2.0
104
+ m[0::2, 1::2] = (c + 1j * d) / 2.0
105
+ m[1::2, 0::2] = (-c + 1j * d) / 2.0
106
+ m[1::2, 1::2] = (a - 1j * b) / 2.0
107
+ return np.linalg.eigvals(m)
108
+
109
+ def natural_scale(self) -> float:
110
+ return np.sqrt(self.n)
@@ -0,0 +1,190 @@
1
+ """Girko ensembles -- universality generalizations of the Ginibre
2
+ ensembles.
3
+
4
+ References
5
+ ----------
6
+ V. L. Girko, "Circular law", Theory Probab. Appl. 29 (1984) 694 -- the
7
+ circular law holds for ANY i.i.d. entry distribution (mean 0, unit
8
+ variance), not just Gaussian.
9
+ Z. D. Bai, "Circular law", Ann. Probab. 25 (1997) 494 -- fixed gaps in
10
+ Girko's original proof.
11
+ T. Tao, V. Vu (with an appendix by M. Krishnapur), "Random matrices:
12
+ Universality of ESDs and the circular law", Ann. Probab. 38 (2010) 2023
13
+ -- relaxed the moment condition to finite variance.
14
+ V. L. Girko, "The elliptic law", Theory Probab. Appl. 30 (1985) 677 --
15
+ matrices whose (X_ij, X_ji) entry pairs are correlated have eigenvalues
16
+ filling an ellipse rather than a disk.
17
+ A. Naumov, "Elliptic law for random matrices", arXiv:1201.1639 (2012) --
18
+ rigorous elliptic law for general (non-Gaussian) entry distributions.
19
+ Y. V. Fyodorov, B. A. Khoruzhenko, H.-J. Sommers, "Almost-Hermitian
20
+ random matrices: eigenvalue density in the complex plane", Phys. Lett.
21
+ A 226 (1997) 46 -- the Gaussian special case ("elliptic Ginibre"), which
22
+ :class:`GirkoElliptic` recovers for its default entry distribution --
23
+ per the design notes, FKS is a parametrization of the general Girko
24
+ result below, not a separate construction.
25
+
26
+ Both ensembles reuse ``physicskit.rmt.ensembles.universality``'s entry-sampler
27
+ convention (``uniform_unit_variance``, ``rademacher``,
28
+ ``exponential_centered_unit_variance``) -- the same non-Gaussian entry
29
+ distributions already used there to demonstrate Wigner (Hermitian)
30
+ universality now demonstrate its non-Hermitian analogue: the circular
31
+ and elliptic laws depend only on the first two moments of the entry
32
+ distribution, not on Gaussianity.
33
+
34
+ Unlike every Dyson-indexed ensemble elsewhere in this package,
35
+ :class:`IIDEnsemble` and :class:`GirkoElliptic` have NO beta:
36
+ Girko universality is a different, orthogonal axis from Dyson's
37
+ threefold way -- it says the *macroscopic* eigenvalue law
38
+ (circular/elliptic) is unchanged across entry distributions, not that
39
+ the *exact* joint eigenvalue density matches a beta-ensemble formula
40
+ (only Gaussian entries have that property). ``Spectrum.beta`` is
41
+ therefore left ``None`` for both, inherited from the base class.
42
+ """
43
+
44
+ from __future__ import annotations
45
+
46
+ from collections.abc import Callable
47
+
48
+ import numpy as np
49
+
50
+ from .base import MatrixEnsemble
51
+
52
+ EntrySampler = Callable[[np.random.Generator, tuple[int, ...]], np.ndarray]
53
+
54
+
55
+ def standard_normal(rng: np.random.Generator, size: tuple[int, ...]) -> np.ndarray:
56
+ """i.i.d. standard Gaussian entries -- mean 0, variance 1. Default
57
+ entry distribution for :class:`GirkoElliptic` (the FKS elliptic
58
+ Ginibre special case); also usable directly with :class:`IIDEnsemble`
59
+ to recover plain Ginibre-law behavior via the general construction."""
60
+ return rng.standard_normal(size)
61
+
62
+
63
+ class IIDEnsemble(MatrixEnsemble):
64
+ """Girko's circular law: eigenvalues of an n x n matrix with i.i.d.
65
+ mean-zero, unit-variance entries (real or complex) converge to the
66
+ uniform distribution on the unit disk after the sqrt(n) rescaling --
67
+ exactly the GinOE/GinUE limiting law, but for ANY entry distribution
68
+ satisfying those two moment conditions, not just Gaussian.
69
+
70
+ Parameters
71
+ ----------
72
+ n : int
73
+ entry_sampler : callable
74
+ ``entry_sampler(rng, size)`` returning i.i.d. mean-zero,
75
+ unit-variance real samples of the given shape -- see
76
+ ``standard_normal`` above and
77
+ ``physicskit.rmt.ensembles.universality.uniform_unit_variance``,
78
+ ``rademacher``, ``exponential_centered_unit_variance`` for
79
+ ready-made options.
80
+ complex_entries : bool, optional
81
+ If True (default), each entry is
82
+ ``(entry_sampler + 1j*entry_sampler) / sqrt(2)`` -- matching
83
+ GinUE's construction. If False, entries are real -- matching
84
+ GinOE, including its real-eigenvalue anomaly at any finite n
85
+ (a property of real matrices generally, not just Gaussian ones).
86
+ """
87
+
88
+ def __init__(
89
+ self,
90
+ n: int,
91
+ entry_sampler: EntrySampler,
92
+ complex_entries: bool = True,
93
+ seed: int | np.random.Generator | None = None,
94
+ ) -> None:
95
+ super().__init__(n, seed=seed)
96
+ self.entry_sampler = entry_sampler
97
+ self.complex_entries = complex_entries
98
+
99
+ def _sample_eigenvalues(self, rng: np.random.Generator) -> np.ndarray:
100
+ n = self.n
101
+ if self.complex_entries:
102
+ x = (self.entry_sampler(rng, (n, n)) + 1j * self.entry_sampler(rng, (n, n))) / np.sqrt(2.0)
103
+ else:
104
+ x = self.entry_sampler(rng, (n, n))
105
+ return np.linalg.eigvals(x).astype(complex)
106
+
107
+ def natural_scale(self) -> float:
108
+ return np.sqrt(self.n)
109
+
110
+
111
+ def _correlated_pair_matrix(n: int, rho: float, entry_sampler: EntrySampler, rng: np.random.Generator) -> np.ndarray:
112
+ """n x n real matrix whose off-diagonal entry pairs (X_ij, X_ji)
113
+ (i != j) each have unit variance and correlation ``rho``.
114
+
115
+ Construction: independent A, B ~ entry_sampler; for i < j,
116
+ X_ij = c1*A_ij + c2*B_ij
117
+ X_ji = c1*A_ij - c2*B_ij
118
+ with c1 = sqrt((1+rho)/2), c2 = sqrt((1-rho)/2). Directly verifiable:
119
+ Var(X_ij) = Var(X_ji) = c1^2 + c2^2 = 1 and
120
+ Cov(X_ij, X_ji) = c1^2 - c2^2 = rho, for any entry_sampler with
121
+ mean 0, unit variance -- not just Gaussian (Naumov 2012).
122
+
123
+ Diagonal entries are set to X_ii = c1*sqrt(2)*A_ii, giving
124
+ Var(X_ii) = 1+rho -- chosen (rather than a fixed unit variance) so
125
+ the construction degenerates *exactly* at both endpoints: at rho=1
126
+ (c1=1) this is sqrt(2)*A_ii, the standard Wigner/GOE
127
+ variance-2 diagonal convention used elsewhere in this package (see
128
+ ``physicskit.rmt.ensembles.universality.GeneralWignerEnsemble``), and at
129
+ rho=-1 (c1=0) the diagonal is exactly zero -- required for X to be
130
+ exactly antisymmetric there (X_ii = -X_ii forces X_ii = 0; no
131
+ distribution of nonzero variance can satisfy that identically).
132
+ """
133
+ a = entry_sampler(rng, (n, n))
134
+ b = entry_sampler(rng, (n, n))
135
+ c1 = np.sqrt((1.0 + rho) / 2.0)
136
+ c2 = np.sqrt((1.0 - rho) / 2.0)
137
+ upper = np.triu(c1 * a + c2 * b, k=1)
138
+ lower = np.triu(c1 * a - c2 * b, k=1).T
139
+ diagonal = np.diag(c1 * np.sqrt(2.0) * np.diag(a))
140
+ return upper + lower + diagonal
141
+
142
+
143
+ class GirkoElliptic(MatrixEnsemble):
144
+ """Girko's elliptic law: eigenvalues of an n x n real matrix whose
145
+ (X_ij, X_ji) entry pairs are correlated at ``rho`` (each individually
146
+ unit variance) fill an ellipse with semi-axes (1+rho) along the real
147
+ axis and (1-rho) along the imaginary axis, after the sqrt(n)
148
+ rescaling.
149
+
150
+ rho=0 recovers plain i.i.d. entries -- Girko's circular law, a disk
151
+ of radius 1, the same limiting law as :class:`IIDEnsemble` with
152
+ ``complex_entries=False``. The endpoints rho=+-1 are exact
153
+ (not just asymptotic) degenerate limits, checkable at any finite n:
154
+ rho=1 makes X exactly symmetric (X_ij = X_ji), so eigenvalues are
155
+ exactly real (recovering the real-entries Wigner/semicircle case,
156
+ the ellipse collapsed onto the real segment [-2, 2]); rho=-1 makes X
157
+ exactly antisymmetric, so eigenvalues are exactly purely imaginary
158
+ (real antisymmetric matrices have eigenvalues 0 or imaginary
159
+ conjugate pairs -- the ellipse collapsed onto the imaginary axis).
160
+
161
+ Parameters
162
+ ----------
163
+ n : int
164
+ rho : float
165
+ Entry-pair correlation, in [-1, 1].
166
+ entry_sampler : callable, optional
167
+ ``entry_sampler(rng, size)`` returning i.i.d. mean-zero,
168
+ unit-variance real samples (default: ``standard_normal``, i.e.
169
+ the Fyodorov-Khoruzhenko-Sommers elliptic Ginibre special case).
170
+ """
171
+
172
+ def __init__(
173
+ self,
174
+ n: int,
175
+ rho: float,
176
+ entry_sampler: EntrySampler | None = None,
177
+ seed: int | np.random.Generator | None = None,
178
+ ) -> None:
179
+ if not -1.0 <= rho <= 1.0:
180
+ raise ValueError(f"rho must be in [-1, 1], got {rho}")
181
+ super().__init__(n, seed=seed)
182
+ self.rho = float(rho)
183
+ self.entry_sampler = entry_sampler or standard_normal
184
+
185
+ def _sample_eigenvalues(self, rng: np.random.Generator) -> np.ndarray:
186
+ x = _correlated_pair_matrix(self.n, self.rho, self.entry_sampler, rng)
187
+ return np.linalg.eigvals(x).astype(complex)
188
+
189
+ def natural_scale(self) -> float:
190
+ return np.sqrt(self.n)