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,273 @@
1
+ """Tests for the chiral ensembles (chGOE, chGUE, chGSE) -- Altland-
2
+ Zirnbauer classes BDI, AIII, CII: block off-diagonal Hamiltonians with
3
+ an anticommuting chiral symmetry, the QCD-type Dirac operator random
4
+ matrix ensembles of Verbaarschot and Zahed.
5
+
6
+ Two independent layers of verification, mirroring the bar set by
7
+ ``physicskit.rmt/ensembles/wishart.py`` for the underlying Laguerre machinery:
8
+ (1) the fast production sampler's structural contract (beta, shape,
9
+ +-pairing, exact zero-mode count, reproducibility) -- trivially true by
10
+ construction, but worth asserting as documentation; and (2) an
11
+ independent, direct check on the actual dense block matrix
12
+ H = [[0, W], [W^dagger, 0]] (Hermiticity, exact chiral-symmetry
13
+ anticommutation with Gamma = diag(I, -I), and that its eigenvalues are
14
+ exactly +-singular-values-of-W plus exact zeros) -- confirming the
15
+ "reuse the Laguerre machinery" shortcut actually represents the linear
16
+ algebra it claims to, not merely trusting the module docstring's
17
+ derivation.
18
+ """
19
+
20
+ import numpy as np
21
+ import pytest
22
+ from cache_utils import cached_sample
23
+
24
+ import physicskit.rmt as rmt
25
+
26
+ CHIRAL = [
27
+ ("chGOE", rmt.ensembles.chGOE, 1),
28
+ ("chGUE", rmt.ensembles.chGUE, 2),
29
+ ("chGSE", rmt.ensembles.chGSE, 4),
30
+ ]
31
+
32
+
33
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
34
+ def test_beta_is_correct(name, cls, beta):
35
+ ens = cls(n=30, seed=0)
36
+ assert ens.beta == beta
37
+
38
+
39
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
40
+ def test_gamma_property(name, cls, beta):
41
+ ens = cls(n=30, nu=10, seed=0)
42
+ assert ens.gamma == pytest.approx(30.0 / 40.0)
43
+
44
+
45
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
46
+ def test_produces_2n_plus_nu_eigenvalues(name, cls, beta):
47
+ ens = cls(n=40, nu=5, seed=1)
48
+ spectrum = cached_sample(ens, n_samples=5)
49
+ assert spectrum.eigenvalues.shape == (5, 85)
50
+
51
+
52
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
53
+ def test_eigenvalues_are_real(name, cls, beta):
54
+ ens = cls(n=35, nu=3, seed=2)
55
+ spectrum = cached_sample(ens, n_samples=5)
56
+ assert not np.iscomplexobj(spectrum.eigenvalues)
57
+ assert np.all(np.isfinite(spectrum.eigenvalues))
58
+
59
+
60
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
61
+ def test_reproducibility(name, cls, beta):
62
+ ens_a = cls(n=40, nu=4, seed=42)
63
+ ens_b = cls(n=40, nu=4, seed=42)
64
+ spec_a = ens_a.sample(n_samples=3)
65
+ spec_b = ens_b.sample(n_samples=3)
66
+ np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
67
+
68
+
69
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
70
+ def test_spectrum_symmetric_about_zero(name, cls, beta):
71
+ # Chiral symmetry forces exact +-lambda pairing, like BdG -- but via
72
+ # an anticommuting (not commuting) operator; see module docstring.
73
+ ens = cls(n=50, nu=6, seed=3)
74
+ spectrum = cached_sample(ens, n_samples=10)
75
+ for row in spectrum.eigenvalues:
76
+ row_sorted = np.sort(row)
77
+ pairing_error = np.abs(row_sorted + row_sorted[::-1]).max()
78
+ assert pairing_error < 1e-8
79
+
80
+
81
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
82
+ def test_exact_zero_modes_match_nu(name, cls, beta):
83
+ ens = cls(n=45, nu=7, seed=4)
84
+ spectrum = cached_sample(ens, n_samples=5)
85
+ for row in spectrum.eigenvalues:
86
+ n_zeros = np.sum(np.abs(row) < 1e-10)
87
+ assert n_zeros == 7
88
+
89
+
90
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
91
+ def test_nonzero_eigenvalues_are_nonnegative_singular_values(name, cls, beta):
92
+ # +-sigma_k by construction: exactly half (rounding for nu>0's
93
+ # zeros) of the nonzero eigenvalues are strictly positive, the rest
94
+ # their exact negatives -- already covered by the pairing test, but
95
+ # additionally check the magnitudes are genuinely nonzero (not
96
+ # spuriously landing on/near zero beyond the nu exact zero modes).
97
+ ens = cls(n=30, nu=0, seed=5)
98
+ spectrum = cached_sample(ens, n_samples=5)
99
+ nonzero = spectrum.eigenvalues[np.abs(spectrum.eigenvalues) > 1e-10]
100
+ assert len(nonzero) == 5 * 60 # nu=0 -> no exact zeros
101
+ assert np.all(np.abs(nonzero) > 1e-6)
102
+
103
+
104
+ def test_invalid_parameters_rejected():
105
+ with pytest.raises(ValueError):
106
+ rmt.ensembles.ChiralBetaEnsemble(n=10, beta=0, seed=0)
107
+ with pytest.raises(ValueError):
108
+ rmt.ensembles.chGUE(n=10, nu=-1, seed=0)
109
+
110
+
111
+ def test_continuum_beta_also_produces_valid_spectrum():
112
+ ens = rmt.ensembles.ChiralBetaEnsemble(n=200, beta=1.7, nu=3, seed=6)
113
+ spectrum = cached_sample(ens, n_samples=10)
114
+ assert spectrum.eigenvalues.shape == (10, 403)
115
+ for row in spectrum.eigenvalues:
116
+ assert np.sum(np.abs(row) < 1e-10) == 3
117
+
118
+
119
+ # --- Direct, un-cached structural verification of the actual block
120
+ # matrix (independent of the fast Laguerre-reuse sampler above) ---
121
+
122
+
123
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
124
+ def test_dense_construction_hermitian_and_chiral_symmetric(name, cls, beta):
125
+ from physicskit.rmt.ensembles.chiral import _dense_chiral_hamiltonian
126
+
127
+ rng = np.random.default_rng(7)
128
+ n, nu = 10, 3
129
+ h = _dense_chiral_hamiltonian(n, nu, rng, beta)
130
+ assert np.abs(h - h.conj().T).max() < 1e-10
131
+
132
+ n_dim = n if beta != 4 else 2 * n
133
+ m_dim = (n + nu) if beta != 4 else 2 * (n + nu)
134
+ gamma5 = np.diag(np.concatenate([np.ones(n_dim), -np.ones(m_dim)]))
135
+ anticommutator_residual = gamma5 @ h @ gamma5 + h
136
+ assert np.abs(anticommutator_residual).max() < 1e-10
137
+
138
+
139
+ @pytest.mark.parametrize("name,cls,beta", CHIRAL)
140
+ def test_dense_construction_eigenvalues_are_singular_values_plus_zeros(name, cls, beta):
141
+ from physicskit.rmt.ensembles.chiral import _dense_chiral_hamiltonian, _sample_block
142
+
143
+ rng = np.random.default_rng(8)
144
+ n, nu = 10, 3
145
+ rng_for_w = np.random.default_rng(8)
146
+ w = _sample_block(n, n + nu, rng_for_w, beta)
147
+ singular_values = np.linalg.svd(w, compute_uv=False)
148
+
149
+ h = _dense_chiral_hamiltonian(n, nu, rng, beta)
150
+ eigs = np.sort(np.linalg.eigvalsh(h))
151
+
152
+ n_dim, m_dim = w.shape
153
+ n_zero_modes = m_dim - n_dim # rank deficiency of W (>= 0 for nu >= 0)
154
+ positive_eigs = eigs[eigs > 1e-8]
155
+ zero_eigs = eigs[np.abs(eigs) <= 1e-8]
156
+ negative_eigs = eigs[eigs < -1e-8]
157
+
158
+ assert len(zero_eigs) == n_zero_modes
159
+ np.testing.assert_allclose(
160
+ np.sort(positive_eigs),
161
+ np.sort(singular_values[singular_values > 1e-8]),
162
+ atol=1e-8,
163
+ )
164
+ np.testing.assert_allclose(np.sort(-negative_eigs), np.sort(positive_eigs), atol=1e-8)
165
+
166
+
167
+ @pytest.mark.parametrize(
168
+ "name,cls,beta",
169
+ [("chGOE", rmt.ensembles.chGOE, 1), ("chGUE", rmt.ensembles.chGUE, 2)],
170
+ )
171
+ def test_fast_sampler_matches_dense_construction_statistically(name, cls, beta):
172
+ # Two-sample KS test between the fast (Laguerre-reuse) sampler's
173
+ # pooled nonzero |eigenvalue|s and the literal dense block matrix's
174
+ # singular values -- the same cross-check standard
175
+ # ``physicskit.rmt/ensembles/wishart.py`` already applies to the underlying
176
+ # bidiagonal trick, done here explicitly for the chiral wrapper
177
+ # rather than just trusted transitively. beta=4 is excluded because
178
+ # the dense construction's explicit quaternion embedding doubles its
179
+ # dimension relative to the fast sampler's generalized-beta n (see
180
+ # module docstring), so the two are not directly comparable sample-
181
+ # for-sample at matched n.
182
+ #
183
+ # Scale note: the fast sampler reuses ``sample_laguerre_beta_eigenvalues``,
184
+ # which returns Marchenko-Pastur-*normalized* eigenvalues -- despite
185
+ # dividing the raw bidiagonal-model product by (beta*m) internally
186
+ # (see ``physicskit.rmt/utils/tridiagonal.py``), it matches dense X^dagger @ X / m
187
+ # for unit-variance X at every beta (confirmed directly here, and
188
+ # already the standard this repo verifies against -- see
189
+ # ``physicskit.rmt/ensembles/wishart.py``'s module docstring), i.e. the
190
+ # beta-dependence is absorbed into the bidiagonal model's chi
191
+ # degrees of freedom, not left over as an extra factor in the
192
+ # normalization. So the dense construction's raw singular values
193
+ # (built from literal unit-variance entries) need only be divided by
194
+ # sqrt(m), not sqrt(beta*m), to land on the same footing.
195
+ from scipy.stats import ks_2samp
196
+
197
+ from physicskit.rmt.ensembles.chiral import _dense_chiral_hamiltonian
198
+
199
+ n, nu = 12, 2
200
+ m = n + nu
201
+ fast_ens = cls(n=n, nu=nu, seed=9)
202
+ fast_spectrum = fast_ens.sample(n_samples=400)
203
+ fast_nonzero = np.abs(fast_spectrum.eigenvalues[np.abs(fast_spectrum.eigenvalues) > 1e-10])
204
+
205
+ rng = np.random.default_rng(10)
206
+ dense_singular_values = []
207
+ for _ in range(400):
208
+ h = _dense_chiral_hamiltonian(n, nu, rng, beta)
209
+ eigs = np.linalg.eigvalsh(h)
210
+ dense_singular_values.append(np.abs(eigs[np.abs(eigs) > 1e-8]))
211
+ dense_nonzero = np.concatenate(dense_singular_values) / np.sqrt(m)
212
+
213
+ ks = ks_2samp(fast_nonzero, dense_nonzero)
214
+ assert ks.statistic < 0.05, f"{name}: fast sampler diverges from dense construction, {ks}"
215
+
216
+
217
+ # --- QCD Dirac operator convention (D = i*H, purely imaginary spectrum) ---
218
+
219
+ QCD_DIRAC = [
220
+ ("QCDDiracGOE", rmt.ensembles.QCDDiracGOE, rmt.ensembles.chGOE, 1),
221
+ ("QCDDiracGUE", rmt.ensembles.QCDDiracGUE, rmt.ensembles.chGUE, 2),
222
+ ("QCDDiracGSE", rmt.ensembles.QCDDiracGSE, rmt.ensembles.chGSE, 4),
223
+ ]
224
+
225
+
226
+ @pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
227
+ def test_qcd_dirac_beta_is_correct(name, cls, ch_cls, beta):
228
+ ens = cls(n=30, seed=0)
229
+ assert ens.beta == beta
230
+
231
+
232
+ @pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
233
+ def test_qcd_dirac_eigenvalues_are_purely_imaginary(name, cls, ch_cls, beta):
234
+ ens = cls(n=40, nu=3, seed=1)
235
+ spectrum = cached_sample(ens, n_samples=5)
236
+ assert np.iscomplexobj(spectrum.eigenvalues)
237
+ assert np.abs(spectrum.eigenvalues.real).max() < 1e-10
238
+
239
+
240
+ @pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
241
+ def test_qcd_dirac_is_exactly_i_times_chiral_ensemble(name, cls, ch_cls, beta):
242
+ # Thin-wrapper contract from the module docstring: D = i*H exactly,
243
+ # for the SAME underlying random draw (matched seed) -- not just
244
+ # matching in distribution.
245
+ dirac_ens = cls(n=25, nu=2, seed=7)
246
+ chiral_ens = ch_cls(n=25, nu=2, seed=7)
247
+ dirac_spectrum = dirac_ens.sample(n_samples=4)
248
+ chiral_spectrum = chiral_ens.sample(n_samples=4)
249
+ np.testing.assert_allclose(dirac_spectrum.eigenvalues, 1j * chiral_spectrum.eigenvalues)
250
+
251
+
252
+ @pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
253
+ def test_qcd_dirac_exact_zero_modes_match_nu(name, cls, ch_cls, beta):
254
+ ens = cls(n=45, nu=6, seed=2)
255
+ spectrum = cached_sample(ens, n_samples=5)
256
+ for row in spectrum.eigenvalues:
257
+ assert np.sum(np.abs(row) < 1e-10) == 6
258
+
259
+
260
+ @pytest.mark.parametrize("name,cls,ch_cls,beta", QCD_DIRAC)
261
+ def test_qcd_dirac_reproducibility(name, cls, ch_cls, beta):
262
+ ens_a = cls(n=30, nu=3, seed=42)
263
+ ens_b = cls(n=30, nu=3, seed=42)
264
+ spec_a = ens_a.sample(n_samples=3)
265
+ spec_b = ens_b.sample(n_samples=3)
266
+ np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
267
+
268
+
269
+ def test_sample_block_rejects_invalid_beta():
270
+ from physicskit.rmt.ensembles.chiral import _sample_block
271
+
272
+ with pytest.raises(ValueError):
273
+ _sample_block(5, 6, np.random.default_rng(0), beta=3)
@@ -0,0 +1,225 @@
1
+ """Tests for COE, CUE, CSE and the sine kernel benchmark.
2
+
3
+ Circular ensembles are structurally different from the Gaussian/Wishart
4
+ families: COE is NOT "eigenvalues of a Haar-random orthogonal matrix"
5
+ and CSE is NOT "eigenvalues of a Haar-random symplectic matrix" (see the
6
+ warning in the ``physicskit.rmt.ensembles.circular`` module docstring for why).
7
+ These tests check both the structural correctness of each construction
8
+ (unitarity, symmetry/self-duality, exact degeneracy for CSE) and the
9
+ resulting spacing statistics against the already-validated Wigner
10
+ surmise -- an independent cross-family check, since spacing statistics
11
+ are universal in beta across the Gaussian and circular families.
12
+ """
13
+
14
+ import numpy as np
15
+ import pytest
16
+ from cache_utils import cached_sample
17
+
18
+ import physicskit.rmt as rmt
19
+ from physicskit.rmt.utils.haar import haar_unitary, symplectic_form
20
+
21
+ CIRCULAR = [
22
+ ("COE", rmt.ensembles.COE, 1),
23
+ ("CUE", rmt.ensembles.CUE, 2),
24
+ ("CSE", rmt.ensembles.CSE, 4),
25
+ ]
26
+
27
+
28
+ def test_haar_unitary_is_unitary():
29
+ rng = np.random.default_rng(0)
30
+ u = haar_unitary(150, rng)
31
+ identity_error = np.abs(u.conj().T @ u - np.eye(150)).max()
32
+ assert identity_error < 1e-9
33
+
34
+
35
+ def test_haar_unitary_eigenvalues_on_unit_circle():
36
+ rng = np.random.default_rng(1)
37
+ u = haar_unitary(150, rng)
38
+ eigs = np.linalg.eigvals(u)
39
+ assert np.abs(np.abs(eigs) - 1.0).max() < 1e-9
40
+
41
+
42
+ @pytest.mark.parametrize("name,cls,beta", CIRCULAR)
43
+ def test_beta_is_correct(name, cls, beta):
44
+ ens = cls(n=30, seed=0)
45
+ assert ens.beta == beta
46
+
47
+
48
+ @pytest.mark.parametrize("name,cls,beta", CIRCULAR)
49
+ def test_phases_in_valid_range(name, cls, beta):
50
+ ens = cls(n=100, seed=2)
51
+ spectrum = cached_sample(ens, n_samples=5)
52
+ assert np.all(spectrum.eigenvalues >= 0.0)
53
+ assert np.all(spectrum.eigenvalues < 2 * np.pi + 1e-9)
54
+
55
+
56
+ @pytest.mark.parametrize("name,cls,beta", CIRCULAR)
57
+ def test_reproducibility(name, cls, beta):
58
+ ens_a = cls(n=80, seed=42)
59
+ ens_b = cls(n=80, seed=42)
60
+ spec_a = ens_a.sample(n_samples=3)
61
+ spec_b = ens_b.sample(n_samples=3)
62
+ np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
63
+
64
+
65
+ @pytest.mark.parametrize("name,cls,beta", CIRCULAR)
66
+ def test_mean_spacing_is_exactly_unity(name, cls, beta):
67
+ # Unlike Gaussian/Wishart, circular ensembles have EXACT rotational
68
+ # invariance at any finite n, so mean spacing should be unity to
69
+ # floating-point precision, not just asymptotically.
70
+ ens = cls(n=200, seed=3)
71
+ spectrum = cached_sample(ens, n_samples=15)
72
+ spacings = rmt.stats.circular_spacings(spectrum)
73
+ assert spacings.mean() == pytest.approx(1.0, abs=1e-9)
74
+
75
+
76
+ @pytest.mark.parametrize("name,cls,beta", CIRCULAR)
77
+ def test_spacing_matches_wigner_surmise_at_matching_beta(name, cls, beta):
78
+ ens = cls(n=250, seed=4)
79
+ spectrum = cached_sample(ens, n_samples=25)
80
+ spacings = rmt.stats.circular_spacings(spectrum)
81
+ benchmark = rmt.validation.WignerSurmise(beta=beta)
82
+ result = benchmark.validate(spacings, seed=4)
83
+ assert result.ks_statistic < 0.02
84
+
85
+
86
+ def test_coe_matrix_is_symmetric():
87
+ rng = np.random.default_rng(5)
88
+ v = haar_unitary(100, rng)
89
+ u = v.T @ v
90
+ assert np.abs(u - u.T).max() < 1e-9
91
+ identity_error = np.abs(u.conj().T @ u - np.eye(100)).max()
92
+ assert identity_error < 1e-9 # still unitary
93
+
94
+
95
+ def test_cse_dual_matrix_is_self_dual_unitary():
96
+ rng = np.random.default_rng(6)
97
+ n2 = 60
98
+ v = haar_unitary(n2, rng)
99
+ z = symplectic_form(n2)
100
+ v_dual = (-z) @ v.T @ z
101
+ u = v_dual @ v
102
+ identity_error = np.abs(u.conj().T @ u - np.eye(n2)).max()
103
+ assert identity_error < 1e-9
104
+ # Self-duality: U^R == U, where U^R = Z U^T Z^{-1}
105
+ u_dual = (-z) @ u.T @ z
106
+ assert np.abs(u_dual - u).max() < 1e-8
107
+
108
+
109
+ def test_cse_eigenvalues_are_doubly_degenerate():
110
+ # inspect the raw (pre-dedup) construction directly
111
+ rng = np.random.default_rng(7)
112
+ from physicskit.rmt.utils.haar import haar_unitary, symplectic_form
113
+
114
+ n2 = 80
115
+ v = haar_unitary(n2, rng)
116
+ z = symplectic_form(n2)
117
+ v_dual = (-z) @ v.T @ z
118
+ u = v_dual @ v
119
+ eigs = np.linalg.eigvals(u)
120
+ theta = np.sort(np.angle(eigs) % (2 * np.pi))
121
+ pair_gaps = np.diff(theta)[0::2] # gaps WITHIN each claimed degenerate pair
122
+ assert np.max(np.abs(pair_gaps)) < 1e-6
123
+
124
+
125
+ def test_sine_kernel_matches_cue_correlations():
126
+ ens = rmt.ensembles.CUE(n=400, seed=8)
127
+ spectrum = cached_sample(ens, n_samples=60)
128
+ benchmark = rmt.validation.SineKernel()
129
+ result = benchmark.validate(spectrum)
130
+ assert result.rmse < 0.05
131
+
132
+
133
+ def test_sine_kernel_rejects_non_cue_beta():
134
+ ens = rmt.ensembles.COE(n=100, seed=0)
135
+ spectrum = cached_sample(ens, n_samples=5)
136
+ benchmark = rmt.validation.SineKernel()
137
+ with pytest.raises(ValueError):
138
+ benchmark.validate(spectrum)
139
+
140
+
141
+ def test_sine_kernel_zero_at_origin_and_one_at_large_separation():
142
+ r = np.array([0.0, 0.01, 2.0, 5.0])
143
+ r2 = rmt.stats.sine_kernel_r2(r)
144
+ assert r2[0] == pytest.approx(0.0, abs=1e-9)
145
+ assert r2[1] < 0.01 # strong level repulsion near r=0
146
+ assert r2[3] == pytest.approx(1.0, abs=1e-2)
147
+
148
+
149
+ # --- Pfaffian kernel building blocks (S, D, I) ---
150
+ # See physicskit.rmt/stats/correlations.py module docstring: only these three
151
+ # individually-exact building blocks are implemented, NOT their
152
+ # combination into a beta=1/4 two-point correlation function (an
153
+ # attempted reconstruction was checked and ruled out structurally --
154
+ # see that docstring for the Taylor-expansion argument).
155
+
156
+
157
+ def test_kernel_s_matches_sine_kernel_component():
158
+ r = np.array([0.0, 0.3, 1.0, 2.5])
159
+ np.testing.assert_allclose(rmt.stats.kernel_s(r) ** 2, 1.0 - rmt.stats.sine_kernel_r2(r), atol=1e-12)
160
+
161
+
162
+ def test_kernel_d_is_derivative_of_kernel_s():
163
+ r = np.linspace(0.05, 3.0, 20)
164
+ h = 1e-6
165
+ finite_diff = (rmt.stats.kernel_s(r + h) - rmt.stats.kernel_s(r - h)) / (2 * h)
166
+ np.testing.assert_allclose(rmt.stats.kernel_d(r), finite_diff, atol=1e-4)
167
+
168
+
169
+ def test_kernel_i_is_antiderivative_of_kernel_s():
170
+ from scipy.integrate import quad
171
+
172
+ for r in [0.3, 1.0, 2.0]:
173
+ expected, _ = quad(lambda t: rmt.stats.kernel_s(np.array([t]))[0], 0, r)
174
+ assert rmt.stats.kernel_i(np.array([r]))[0] == pytest.approx(expected, abs=1e-6)
175
+
176
+
177
+ def test_kernel_d_is_odd_and_kernel_s_is_even():
178
+ r = np.array([0.2, 0.7, 1.5])
179
+ np.testing.assert_allclose(rmt.stats.kernel_s(-r), rmt.stats.kernel_s(r))
180
+ np.testing.assert_allclose(rmt.stats.kernel_d(-r), -rmt.stats.kernel_d(r))
181
+
182
+
183
+ # --- general k-point determinantal correlation function (CUE) ---
184
+
185
+
186
+ def test_k_point_correlation_reduces_to_sine_kernel_r2_at_k_2():
187
+ r = 0.7
188
+ value = rmt.stats.k_point_correlation(np.array([0.0, r]))
189
+ assert value == pytest.approx(rmt.stats.sine_kernel_r2(np.array([r]))[0])
190
+
191
+
192
+ def test_k_point_correlation_vanishes_at_coincident_points():
193
+ # Level repulsion at all orders: a determinant with two identical
194
+ # rows (coincident positions) is exactly zero.
195
+ value = rmt.stats.k_point_correlation(np.array([0.0, 0.0, 1.5]))
196
+ assert value == pytest.approx(0.0, abs=1e-12)
197
+
198
+
199
+ def test_k_point_correlation_factorizes_at_large_separation():
200
+ # Cluster decomposition: R_3(x1, x2, x3) -> R_2(x1, x2) as x3 -> infinity.
201
+ r = 0.7
202
+ r2 = rmt.stats.sine_kernel_r2(np.array([r]))[0]
203
+ r3_near = rmt.stats.k_point_correlation(np.array([0.0, r, 5.0]))
204
+ r3_far = rmt.stats.k_point_correlation(np.array([0.0, r, 500.0]))
205
+ assert abs(r3_far - r2) < abs(r3_near - r2)
206
+ assert r3_far == pytest.approx(r2, abs=1e-4)
207
+
208
+
209
+ def test_level_repulsion_strength_orders_cse_cue_coe():
210
+ # Robust, exponent-free qualitative check (see correlations.py
211
+ # module docstring for why the exact beta=1/4 exponents/kernels are
212
+ # not asserted here): near a fixed small separation, the two-point
213
+ # correlation (level repulsion) should order CSE << CUE << COE,
214
+ # matching beta=4 > beta=2 > beta=1 repulsion strength.
215
+ n = 300
216
+ r_probe = 0.1
217
+ values = {}
218
+ ensembles = [("COE", rmt.ensembles.COE), ("CUE", rmt.ensembles.CUE), ("CSE", rmt.ensembles.CSE)]
219
+ for name, cls in ensembles:
220
+ ens = cls(n=n, seed=0)
221
+ spectrum = cached_sample(ens, n_samples=60)
222
+ centers, empirical = rmt.stats.pair_correlation_estimate(spectrum, r_max=1.0, n_bins=50)
223
+ idx = np.argmin(np.abs(centers - r_probe))
224
+ values[name] = empirical[idx]
225
+ assert values["CSE"] < values["CUE"] < values["COE"]
@@ -0,0 +1,72 @@
1
+ """Tests for GOEGUECrossoverEnsemble.
2
+
3
+ The natural_scale formula sqrt(n*(1+lambda^2)) and the crossover
4
+ behavior in level statistics (ratio statistic KS distance to the GOE
5
+ and GUE surmises) were both verified numerically during development
6
+ before being used here -- see module docstring in
7
+ ``physicskit.rmt/ensembles/crossover.py``.
8
+ """
9
+
10
+ import numpy as np
11
+ import pytest
12
+ from cache_utils import cached_sample
13
+ from scipy.stats import kstest
14
+
15
+ import physicskit.rmt as rmt
16
+
17
+
18
+ def test_lambda_0_recovers_goe_natural_scale():
19
+ ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=200, lam=0.0, seed=0)
20
+ assert ens.natural_scale() == pytest.approx(np.sqrt(200))
21
+
22
+
23
+ def test_natural_scale_matches_verified_formula():
24
+ n, lam = 300, 0.5
25
+ ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=n, lam=lam, seed=0)
26
+ assert ens.natural_scale() == pytest.approx(np.sqrt(n * (1 + lam**2)))
27
+
28
+
29
+ def test_negative_lambda_rejected():
30
+ with pytest.raises(ValueError):
31
+ rmt.ensembles.GOEGUECrossoverEnsemble(n=10, lam=-1.0, seed=0)
32
+
33
+
34
+ def test_reproducibility():
35
+ ens_a = rmt.ensembles.GOEGUECrossoverEnsemble(n=40, lam=0.3, seed=42)
36
+ ens_b = rmt.ensembles.GOEGUECrossoverEnsemble(n=40, lam=0.3, seed=42)
37
+ spec_a = ens_a.sample(n_samples=3)
38
+ spec_b = ens_b.sample(n_samples=3)
39
+ np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
40
+
41
+
42
+ def test_lambda_0_matches_goe_ratio_statistics():
43
+ ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=400, lam=0.0, seed=1)
44
+ spectrum = cached_sample(ens, n_samples=20)
45
+ ratios = rmt.stats.ratio_statistics(spectrum)
46
+ ks = kstest(ratios, rmt.stats.RatioSurmise(beta=1).cdf).statistic
47
+ assert ks < 0.03
48
+
49
+
50
+ def test_large_lambda_matches_gue_ratio_statistics():
51
+ ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=400, lam=1.0, seed=2)
52
+ spectrum = cached_sample(ens, n_samples=20)
53
+ ratios = rmt.stats.ratio_statistics(spectrum)
54
+ ks = kstest(ratios, rmt.stats.RatioSurmise(beta=2).cdf).statistic
55
+ assert ks < 0.03
56
+
57
+
58
+ def test_crossover_is_monotonic_between_goe_and_gue():
59
+ # As lambda grows from 0, KS distance to GOE should grow while KS
60
+ # distance to GUE should shrink -- the defining crossover behavior.
61
+ goe_model = rmt.stats.RatioSurmise(beta=1)
62
+ gue_model = rmt.stats.RatioSurmise(beta=2)
63
+ ks_goe = []
64
+ ks_gue = []
65
+ for lam in [0.0, 0.05, 1.0]:
66
+ ens = rmt.ensembles.GOEGUECrossoverEnsemble(n=400, lam=lam, seed=3)
67
+ spectrum = cached_sample(ens, n_samples=20)
68
+ ratios = rmt.stats.ratio_statistics(spectrum)
69
+ ks_goe.append(kstest(ratios, goe_model.cdf).statistic)
70
+ ks_gue.append(kstest(ratios, gue_model.cdf).statistic)
71
+ assert ks_goe[0] < ks_goe[1] < ks_goe[2]
72
+ assert ks_gue[0] > ks_gue[1] > ks_gue[2]
@@ -0,0 +1,23 @@
1
+ """Coverage for physicskit.rmt.stats.density.empirical_density (previously
2
+ never called anywhere in the codebase)."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import numpy as np
7
+
8
+ import physicskit.rmt as rmt
9
+ from physicskit.rmt.stats.density import empirical_density
10
+
11
+
12
+ def test_empirical_density_rescaled_and_raw():
13
+ ens = rmt.ensembles.GOE(n=20, seed=0)
14
+ spectrum = ens.sample(n_samples=5)
15
+
16
+ centers_r, counts_r = empirical_density(spectrum, bins=20, rescaled=True)
17
+ assert centers_r.shape == counts_r.shape == (20,)
18
+ assert np.all(np.isfinite(counts_r))
19
+
20
+ centers_raw, counts_raw = empirical_density(spectrum, bins=20, rescaled=False)
21
+ assert centers_raw.shape == counts_raw.shape == (20,)
22
+ assert np.all(np.isfinite(counts_raw))
23
+ assert not np.allclose(centers_r, centers_raw) # genuinely different scale