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,181 @@
1
+ """Tests for the random density matrix ensembles (InducedMeasureEnsemble,
2
+ HilbertSchmidtEnsemble, BuresHallEnsemble) and the Page-curve entropy
3
+ helpers.
4
+
5
+ Every formula used for validation here (mean purity for both measures,
6
+ Page's average-entropy formula, and -- most importantly -- the
7
+ Bures-Hall construction itself) was independently checked against exact
8
+ theory or independent numerical integration during development, not
9
+ assumed from a remembered citation; see the module docstrings in
10
+ ``physicskit.rmt/ensembles/density_matrix.py`` and
11
+ ``physicskit.rmt/stats/entanglement.py``.
12
+ """
13
+
14
+ import numpy as np
15
+ import pytest
16
+ from cache_utils import cached_sample
17
+ from scipy import integrate
18
+
19
+ import physicskit.rmt as rmt
20
+
21
+
22
+ def _mean_purity(spectrum):
23
+ return np.mean(np.sum(spectrum.eigenvalues**2, axis=1))
24
+
25
+
26
+ # --- structural checks common to all three ensembles ---
27
+
28
+ ALL_DM_ENSEMBLES = [
29
+ (
30
+ "InducedMeasure",
31
+ lambda n, seed: rmt.ensembles.InducedMeasureEnsemble(n=n, k=n + 2, seed=seed),
32
+ ),
33
+ ("HilbertSchmidt", lambda n, seed: rmt.ensembles.HilbertSchmidtEnsemble(n=n, seed=seed)),
34
+ ("BuresHall", lambda n, seed: rmt.ensembles.BuresHallEnsemble(n=n, seed=seed)),
35
+ ]
36
+
37
+
38
+ @pytest.mark.parametrize("name,factory", ALL_DM_ENSEMBLES)
39
+ def test_eigenvalues_are_valid_probability_distribution(name, factory):
40
+ ens = factory(8, 0)
41
+ spectrum = cached_sample(ens, n_samples=20)
42
+ assert np.all(spectrum.eigenvalues >= -1e-10)
43
+ assert np.all(spectrum.eigenvalues <= 1.0 + 1e-10)
44
+ np.testing.assert_allclose(spectrum.eigenvalues.sum(axis=1), 1.0, atol=1e-8)
45
+
46
+
47
+ @pytest.mark.parametrize("name,factory", ALL_DM_ENSEMBLES)
48
+ def test_reproducibility(name, factory):
49
+ ens_a = factory(6, 42)
50
+ ens_b = factory(6, 42)
51
+ spec_a = ens_a.sample(n_samples=3)
52
+ spec_b = ens_b.sample(n_samples=3)
53
+ np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
54
+
55
+
56
+ def test_induced_measure_rejects_invalid_k():
57
+ with pytest.raises(ValueError):
58
+ rmt.ensembles.InducedMeasureEnsemble(n=5, k=0, seed=0)
59
+
60
+
61
+ def test_hilbert_schmidt_beta_is_two():
62
+ ens = rmt.ensembles.HilbertSchmidtEnsemble(n=5, seed=0)
63
+ assert ens.beta == 2
64
+
65
+
66
+ def test_bures_hall_beta_is_none():
67
+ # Not one of Dyson's classical beta-ensembles -- extra 1/(li+lj)
68
+ # factor in the joint density beyond a pure Vandermonde power.
69
+ ens = rmt.ensembles.BuresHallEnsemble(n=5, seed=0)
70
+ assert ens.beta is None
71
+
72
+
73
+ def test_k_equals_one_gives_pure_states():
74
+ # k=1 forces rank-1 rho: exactly one eigenvalue = 1, rest = 0.
75
+ ens = rmt.ensembles.InducedMeasureEnsemble(n=6, k=1, seed=1)
76
+ spectrum = cached_sample(ens, n_samples=10)
77
+ for row in spectrum.eigenvalues:
78
+ assert np.sum(row > 1e-8) == 1
79
+ assert np.max(row) == pytest.approx(1.0, abs=1e-8)
80
+
81
+
82
+ # --- exact mean-purity formulas (Zyczkowski-Sommers 2001) ---
83
+
84
+
85
+ @pytest.mark.parametrize("n", [2, 3, 5, 10])
86
+ def test_hilbert_schmidt_mean_purity_matches_exact_formula(n):
87
+ ens = rmt.ensembles.HilbertSchmidtEnsemble(n=n, seed=2)
88
+ spectrum = cached_sample(ens, n_samples=20000)
89
+ theory = 2.0 * n / (n**2 + 1)
90
+ assert _mean_purity(spectrum) == pytest.approx(theory, rel=0.03)
91
+
92
+
93
+ @pytest.mark.parametrize("n,k", [(3, 3), (3, 6), (3, 2), (4, 10)])
94
+ def test_induced_measure_mean_purity_matches_exact_formula(n, k):
95
+ ens = rmt.ensembles.InducedMeasureEnsemble(n=n, k=k, seed=3)
96
+ spectrum = cached_sample(ens, n_samples=20000)
97
+ theory = (n + k) / (n * k + 1)
98
+ assert _mean_purity(spectrum) == pytest.approx(theory, rel=0.03)
99
+
100
+
101
+ # --- Bures-Hall: verified directly against its own joint eigenvalue
102
+ # density (not merely against a remembered matrix-model recipe) ---
103
+
104
+
105
+ @pytest.mark.slow
106
+ def test_bures_hall_matches_exact_n2_marginal_density():
107
+ # For n=2, the exact Bures-Hall joint density on the simplex
108
+ # lambda1+lambda2=1 gives a closed-form 1-D density for the smaller
109
+ # eigenvalue: f(x) ~ (2x-1)^2 / sqrt(x(1-x)) on (0, 1), restricted
110
+ # to (0, 0.5] and doubled (by exchange symmetry) for the SMALLER
111
+ # eigenvalue's marginal CDF.
112
+ def unnorm_pdf(x):
113
+ return (2 * x - 1) ** 2 / np.sqrt(x * (1 - x))
114
+
115
+ z, _ = integrate.quad(unnorm_pdf, 0, 1)
116
+
117
+ def cdf_full(x):
118
+ val, _ = integrate.quad(unnorm_pdf, 0, x)
119
+ return val / z
120
+
121
+ def smaller_eig_cdf(x):
122
+ return np.clip(2.0 * np.vectorize(cdf_full)(np.clip(x, 0, 0.5)), 0.0, 1.0)
123
+
124
+ ens = rmt.ensembles.BuresHallEnsemble(n=2, seed=4)
125
+ spectrum = cached_sample(ens, n_samples=5000)
126
+ smaller_eigs = spectrum.eigenvalues[:, 0] # eigvalsh ascending -> smaller first
127
+
128
+ from scipy.stats import kstest
129
+
130
+ # kstest's per-sample smaller_eig_cdf evaluation (a scipy.integrate.quad
131
+ # call each) dominates runtime, hence the smaller n_samples here vs. the
132
+ # 50000 used elsewhere in this file; the KS threshold is loosened by the
133
+ # matching ~sqrt(10) factor for the noisier statistic at this sample size.
134
+ ks = kstest(smaller_eigs, smaller_eig_cdf)
135
+ assert ks.statistic < 0.06
136
+
137
+
138
+ def test_bures_hall_matches_exact_n3_mean_purity_via_joint_density_integration():
139
+ # For n=3, integrate the exact joint density over the 2-D simplex
140
+ # directly (independent of the matrix construction) to get the
141
+ # theoretical mean purity, and compare to Monte Carlo.
142
+ def unnorm_density(l1, l2):
143
+ l3 = 1.0 - l1 - l2
144
+ if l3 <= 0 or l1 <= 0 or l2 <= 0:
145
+ return 0.0
146
+ vand = (l1 - l2) ** 2 * (l1 - l3) ** 2 * (l2 - l3) ** 2
147
+ denom = (l1 + l2) * (l1 + l3) * (l2 + l3)
148
+ weight = (l1 * l2 * l3) ** (-0.5)
149
+ return vand / denom * weight
150
+
151
+ def integrand_z(l2, l1):
152
+ return unnorm_density(l1, l2)
153
+
154
+ def integrand_purity(l2, l1):
155
+ l3 = 1.0 - l1 - l2
156
+ return unnorm_density(l1, l2) * (l1**2 + l2**2 + l3**2)
157
+
158
+ z, _ = integrate.dblquad(integrand_z, 0, 1, lambda l1: 0, lambda l1: 1 - l1)
159
+ p, _ = integrate.dblquad(integrand_purity, 0, 1, lambda l1: 0, lambda l1: 1 - l1)
160
+ theory_mean_purity = p / z
161
+
162
+ ens = rmt.ensembles.BuresHallEnsemble(n=3, seed=5)
163
+ spectrum = cached_sample(ens, n_samples=40000)
164
+ assert _mean_purity(spectrum) == pytest.approx(theory_mean_purity, rel=0.02)
165
+
166
+
167
+ # --- Page curve (bipartite / entanglement) ---
168
+
169
+
170
+ def test_von_neumann_entropy_handles_zero_eigenvalues():
171
+ assert rmt.stats.von_neumann_entropy([1.0, 0.0, 0.0]) == pytest.approx(0.0)
172
+ assert rmt.stats.von_neumann_entropy([0.5, 0.5]) == pytest.approx(np.log(2.0))
173
+
174
+
175
+ @pytest.mark.parametrize("n,k", [(2, 2), (2, 8), (3, 3), (3, 10)])
176
+ def test_page_curve_matches_induced_measure_ensemble(n, k):
177
+ ens = rmt.ensembles.InducedMeasureEnsemble(n=n, k=k, seed=6)
178
+ spectrum = cached_sample(ens, n_samples=15000)
179
+ empirical = np.mean([rmt.stats.von_neumann_entropy(row) for row in spectrum.eigenvalues])
180
+ theory = rmt.stats.page_curve_average_entropy(n, k)
181
+ assert empirical == pytest.approx(theory, rel=0.02)
@@ -0,0 +1,140 @@
1
+ """Tests for the non-Hermitian effective Hamiltonian ensembles (EffGOE,
2
+ EffGUE, EffGSE) -- Feshbach-projection/chaotic-scattering resonance
3
+ ensembles built on GOE/GUE/GSE.
4
+
5
+ Like BdG (see ``tests/test_bdg.py``), there is no simple closed-form
6
+ bulk density to benchmark here, so validation is structural: causality
7
+ (widths never negative -- a property proved directly from Hermiticity
8
+ and positive semi-definiteness in the module docstring, not merely
9
+ observed), the m=0 Hermitian limit, and beta=4's Kramers degeneracy.
10
+ """
11
+
12
+ import numpy as np
13
+ import pytest
14
+ from cache_utils import cached_sample
15
+
16
+ import physicskit.rmt as rmt
17
+
18
+ EFFECTIVE = [
19
+ ("EffGOE", rmt.ensembles.EffGOE, 1),
20
+ ("EffGUE", rmt.ensembles.EffGUE, 2),
21
+ ("EffGSE", rmt.ensembles.EffGSE, 4),
22
+ ]
23
+
24
+
25
+ @pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
26
+ def test_beta_is_correct(name, cls, beta):
27
+ ens = cls(n=30, m=5, seed=0)
28
+ assert ens.beta == beta
29
+
30
+
31
+ @pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
32
+ def test_eigenvalues_are_complex(name, cls, beta):
33
+ ens = cls(n=40, m=5, seed=1)
34
+ spectrum = cached_sample(ens, n_samples=5)
35
+ assert np.iscomplexobj(spectrum.eigenvalues)
36
+
37
+
38
+ @pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
39
+ def test_produces_n_eigenvalues(name, cls, beta):
40
+ # beta=4 internally builds a 2n x 2n embedding but de-duplicates the
41
+ # exact Kramers pairs, so all three classes return exactly n
42
+ # eigenvalues per sample -- see module docstring.
43
+ ens = cls(n=25, m=4, seed=2)
44
+ spectrum = cached_sample(ens, n_samples=6)
45
+ assert spectrum.eigenvalues.shape == (6, 25)
46
+
47
+
48
+ @pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
49
+ def test_reproducibility(name, cls, beta):
50
+ ens_a = cls(n=30, m=5, seed=42)
51
+ ens_b = cls(n=30, m=5, seed=42)
52
+ spec_a = ens_a.sample(n_samples=3)
53
+ spec_b = ens_b.sample(n_samples=3)
54
+ np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
55
+
56
+
57
+ @pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
58
+ def test_widths_are_never_positive_causality(name, cls, beta):
59
+ # Gamma_k = -2*Im(lambda_k) >= 0 for every eigenvalue of every
60
+ # realization -- proved directly (not just observed) in the module
61
+ # docstring from H Hermitian + Gamma Hermitian PSD.
62
+ ens = cls(n=35, m=6, coupling=1.3, seed=3)
63
+ spectrum = cached_sample(ens, n_samples=20)
64
+ assert np.all(spectrum.eigenvalues.imag <= 1e-9)
65
+
66
+
67
+ @pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
68
+ def test_zero_channels_recovers_hermitian_limit(name, cls, beta):
69
+ # m=0 -> Gamma=0 -> H_eff=H exactly -> real eigenvalues to machine
70
+ # precision, regardless of beta.
71
+ ens = cls(n=30, m=0, seed=4)
72
+ spectrum = cached_sample(ens, n_samples=5)
73
+ assert np.abs(spectrum.eigenvalues.imag).max() < 1e-9
74
+
75
+
76
+ @pytest.mark.parametrize("name,cls,beta", EFFECTIVE)
77
+ def test_more_channels_increase_total_width(name, cls, beta):
78
+ # More open channels -> more total decay -> larger mean |Im(lambda)|
79
+ # (monotonic on average, not realization-by-realization).
80
+ total_widths = []
81
+ for m in (1, 4, 10):
82
+ ens = cls(n=40, m=m, seed=5)
83
+ spectrum = cached_sample(ens, n_samples=15)
84
+ total_widths.append(np.mean(-spectrum.eigenvalues.imag))
85
+ assert total_widths[0] < total_widths[1] < total_widths[2]
86
+
87
+
88
+ def test_effgse_eigenvalues_form_exact_kramers_pairs():
89
+ # Direct, un-cached check against the raw (non-deduplicated) 2n
90
+ # eigenvalues: EffGSE's Kramers degeneracy should be exact (machine
91
+ # precision), unlike GinSE's merely-conjugate (distinct) pairs.
92
+ from physicskit.rmt.ensembles.effective_hamiltonian import (
93
+ _sample_coupling,
94
+ _sample_hamiltonian,
95
+ )
96
+
97
+ rng = np.random.default_rng(6)
98
+ n, m = 15, 3
99
+ h = _sample_hamiltonian(n, rng, beta=4)
100
+ v = _sample_coupling(n, m, rng, beta=4)
101
+ gamma = v @ v.conj().T
102
+ h_eff = h - 0.5j * gamma
103
+
104
+ eigs = np.linalg.eigvals(h_eff)
105
+ order = np.lexsort((eigs.imag, eigs.real))
106
+ sorted_eigs = eigs[order]
107
+ pair_diffs = np.abs(sorted_eigs[0::2] - sorted_eigs[1::2])
108
+ assert pair_diffs.max() < 1e-8
109
+
110
+
111
+ def test_zero_coupling_is_equivalent_to_zero_channels():
112
+ # coupling=0 with m>0 should give the same Hermitian-limit behavior
113
+ # as m=0 (Gamma=0 either way).
114
+ ens = rmt.ensembles.EffGUE(n=25, m=6, coupling=0.0, seed=7)
115
+ spectrum = cached_sample(ens, n_samples=5)
116
+ assert np.abs(spectrum.eigenvalues.imag).max() < 1e-9
117
+
118
+
119
+ def test_zero_channels_fresh_sample_recovers_hermitian_limit():
120
+ # A fresh (uncached) direct .sample() call, so the m=0 -> Gamma=0
121
+ # branch is actually exercised rather than risking a disk-cache hit.
122
+ ens = rmt.ensembles.EffGOE(n=6, m=0, seed=555)
123
+ spectrum = ens.sample(n_samples=2)
124
+ assert np.abs(spectrum.eigenvalues.imag).max() < 1e-9
125
+
126
+
127
+ def test_sample_hamiltonian_and_coupling_reject_invalid_beta():
128
+ from physicskit.rmt.ensembles.effective_hamiltonian import _sample_coupling, _sample_hamiltonian
129
+
130
+ with pytest.raises(ValueError):
131
+ _sample_hamiltonian(5, np.random.default_rng(0), beta=3)
132
+ with pytest.raises(ValueError):
133
+ _sample_coupling(5, 3, np.random.default_rng(0), beta=3)
134
+
135
+
136
+ def test_effective_hamiltonian_ensemble_rejects_invalid_beta_and_negative_m():
137
+ with pytest.raises(ValueError):
138
+ rmt.ensembles.EffectiveHamiltonianEnsemble(n=5, m=1, beta=3, seed=0)
139
+ with pytest.raises(ValueError):
140
+ rmt.ensembles.EffectiveHamiltonianEnsemble(n=5, m=-1, beta=2, seed=0)
@@ -0,0 +1,169 @@
1
+ """Tests for the embedded Gaussian ensembles (EmbeddedGaussianEnsemble,
2
+ TwoBodyRandomEnsemble).
3
+
4
+ Unlike every classical ensemble in this package, the many-body
5
+ Hamiltonian here is built by embedding a k-body random interaction into
6
+ a Fock space, via hand-rolled Jordan-Wigner fermionic operators -- a
7
+ genuinely new piece of machinery with real correctness risk (an initial
8
+ implementation had the raising/lowering matrices swapped, caught only
9
+ by the k=m exact-match check below, not by the Hermiticity or particle-
10
+ number-conservation checks, which both silently passed anyway). These
11
+ tests reproduce that verification chain directly rather than only
12
+ trusting the module docstring's account of it.
13
+ """
14
+
15
+ import numpy as np
16
+ import pytest
17
+ from cache_utils import cached_sample
18
+
19
+ import physicskit.rmt as rmt
20
+ from physicskit.rmt.ensembles.embedded import _fermion_ladder_operators
21
+
22
+
23
+ def test_ladder_operators_satisfy_fermionic_algebra():
24
+ n = 5
25
+ creators = _fermion_ladder_operators(n)
26
+ annihilators = [c.conj().T for c in creators]
27
+ dim = 2**n
28
+ identity = np.eye(dim, dtype=complex)
29
+ for i in range(n):
30
+ for j in range(n):
31
+ anticomm_ac = annihilators[i] @ creators[j] + creators[j] @ annihilators[i]
32
+ target = identity if i == j else np.zeros((dim, dim))
33
+ assert np.abs(anticomm_ac - target).max() < 1e-10
34
+
35
+ anticomm_aa = annihilators[i] @ annihilators[j] + annihilators[j] @ annihilators[i]
36
+ assert np.abs(anticomm_aa).max() < 1e-10
37
+
38
+
39
+ @pytest.mark.parametrize("k,m,n_levels", [(2, 2, 4), (3, 3, 6)])
40
+ def test_k_equals_m_reduces_exactly_to_the_interaction_matrix(k, m, n_levels):
41
+ # The construction's most important structural check: with only m=k
42
+ # particles present, the embedding is trivial and H, restricted to
43
+ # the m-particle sector, must equal the k-body interaction matrix V
44
+ # EXACTLY (not merely statistically) -- this is precisely the check
45
+ # that caught an operator-ordering sign bug during development.
46
+ from itertools import combinations
47
+
48
+ from physicskit.rmt.ensembles.embedded import _fermion_ladder_operators
49
+
50
+ creators = _fermion_ladder_operators(n_levels)
51
+ tuples = list(combinations(range(n_levels), k))
52
+ n_tuples = len(tuples)
53
+ rng = np.random.default_rng(0)
54
+ x = rng.standard_normal((n_tuples, n_tuples))
55
+ v = (x + x.T) / np.sqrt(2.0)
56
+
57
+ def multi_create(idxs):
58
+ op = creators[idxs[0]]
59
+ for idx in idxs[1:]:
60
+ op = op @ creators[idx]
61
+ return op
62
+
63
+ p_ops = [multi_create(t) for t in tuples]
64
+ dim = p_ops[0].shape[0]
65
+ h = np.zeros((dim, dim), dtype=complex)
66
+ for a_idx in range(n_tuples):
67
+ q = sum(v[a_idx, b_idx] * p_ops[b_idx].conj().T for b_idx in range(n_tuples))
68
+ h += p_ops[a_idx] @ q
69
+
70
+ def occ_to_index(occ, n):
71
+ idx = 0
72
+ for site in occ:
73
+ idx |= 1 << (n - 1 - site)
74
+ return idx
75
+
76
+ basis = [occ_to_index(t, n_levels) for t in tuples]
77
+ h_sub = h[np.ix_(basis, basis)].real
78
+ np.testing.assert_allclose(h_sub, v, atol=1e-10)
79
+
80
+
81
+ @pytest.mark.parametrize("beta", [1, 2])
82
+ def test_hermiticity_and_particle_number_conservation(beta):
83
+ n_levels = 6
84
+ rng = np.random.default_rng(1)
85
+ # Directly rebuild the dense (pre-restriction) Hamiltonian to check
86
+ # Hermiticity and particle-number conservation on the FULL Fock
87
+ # space, not just the already-restricted eigenvalue output.
88
+ from itertools import combinations
89
+
90
+ from physicskit.rmt.ensembles.embedded import _fermion_ladder_operators
91
+
92
+ creators = _fermion_ladder_operators(n_levels)
93
+ tuples = list(combinations(range(n_levels), 2))
94
+ n_tuples = len(tuples)
95
+ if beta == 1:
96
+ x = rng.standard_normal((n_tuples, n_tuples))
97
+ v = (x + x.T) / np.sqrt(2.0)
98
+ else:
99
+ real_part = rng.standard_normal((n_tuples, n_tuples))
100
+ imag_part = rng.standard_normal((n_tuples, n_tuples))
101
+ x = (real_part + 1j * imag_part) / np.sqrt(2.0)
102
+ v = (x + x.conj().T) / 2.0
103
+
104
+ def multi_create(idxs):
105
+ op = creators[idxs[0]]
106
+ for idx in idxs[1:]:
107
+ op = op @ creators[idx]
108
+ return op
109
+
110
+ p_ops = [multi_create(t) for t in tuples]
111
+ dim = p_ops[0].shape[0]
112
+ h = np.zeros((dim, dim), dtype=complex)
113
+ for a_idx in range(n_tuples):
114
+ q = sum(v[a_idx, b_idx] * p_ops[b_idx].conj().T for b_idx in range(n_tuples))
115
+ h += p_ops[a_idx] @ q
116
+
117
+ assert np.abs(h - h.conj().T).max() < 1e-10
118
+
119
+ annihilators = [c.conj().T for c in creators]
120
+ n_total = sum(creators[i] @ annihilators[i] for i in range(n_levels))
121
+ assert np.abs(h @ n_total - n_total @ h).max() < 1e-8
122
+
123
+
124
+ def test_beta_and_k_are_stored():
125
+ ens = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, beta=2, seed=0)
126
+ assert ens.k == 2
127
+ assert ens.beta == 2
128
+ assert ens.n_levels == 6
129
+
130
+
131
+ def test_invalid_parameters_rejected():
132
+ with pytest.raises(ValueError):
133
+ rmt.ensembles.EmbeddedGaussianEnsemble(n_particles=3, n_levels=6, beta=3, seed=0)
134
+ with pytest.raises(ValueError):
135
+ rmt.ensembles.EmbeddedGaussianEnsemble(n_particles=3, n_levels=6, k=1, seed=0)
136
+ with pytest.raises(ValueError):
137
+ rmt.ensembles.EmbeddedGaussianEnsemble(n_particles=8, n_levels=6, k=2, seed=0)
138
+
139
+
140
+ def test_produces_binomial_n_levels_choose_m_eigenvalues():
141
+ from math import comb
142
+
143
+ ens = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, seed=2)
144
+ spectrum = cached_sample(ens, n_samples=3)
145
+ assert spectrum.eigenvalues.shape == (3, comb(6, 3))
146
+
147
+
148
+ def test_eigenvalues_are_real():
149
+ ens = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, beta=2, seed=3)
150
+ spectrum = cached_sample(ens, n_samples=3)
151
+ assert not np.iscomplexobj(spectrum.eigenvalues)
152
+ assert np.all(np.isfinite(spectrum.eigenvalues))
153
+
154
+
155
+ def test_beta_2_fresh_sample_is_real_and_finite():
156
+ # A fresh (uncached) direct .sample() call, to actually exercise the
157
+ # complex-construction (beta != 1) branch rather than risk a cache hit.
158
+ ens = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=2, n_levels=4, beta=2, seed=777)
159
+ spectrum = ens.sample(n_samples=2)
160
+ assert not np.iscomplexobj(spectrum.eigenvalues)
161
+ assert np.all(np.isfinite(spectrum.eigenvalues))
162
+
163
+
164
+ def test_reproducibility():
165
+ ens_a = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, seed=42)
166
+ ens_b = rmt.ensembles.TwoBodyRandomEnsemble(n_particles=3, n_levels=6, seed=42)
167
+ spec_a = ens_a.sample(n_samples=2)
168
+ spec_b = ens_b.sample(n_samples=2)
169
+ np.testing.assert_allclose(spec_a.eigenvalues, spec_b.eigenvalues)
@@ -0,0 +1,81 @@
1
+ """Tests for the free probability module (Stieltjes/R-transform, free
2
+ additive convolution).
3
+
4
+ The semicircle R-transform (R(w) = w) was derived directly here (solving
5
+ w = G(z) for z from the semicircle's own Stieltjes transform), not
6
+ recalled, and the generic numerical inversion pipeline
7
+ (``r_transform_numerical``) was checked to reproduce it before being
8
+ trusted to derive/verify the Marchenko-Pastur R-transform
9
+ (R(w) = 1/(1-gamma*w)) against the already-validated exact MP density.
10
+ The free additive convolution theorem itself (R_{A+B} = R_A + R_B for
11
+ independent, asymptotically free random matrices) is checked directly
12
+ against real matrix simulation (independent GOE + Wishart matrices
13
+ added together), not just asserted from the individual closed forms.
14
+ """
15
+
16
+ import numpy as np
17
+ import pytest
18
+
19
+ import physicskit.rmt as rmt
20
+
21
+
22
+ def test_stieltjes_transform_semicircle_matches_empirical():
23
+ ens = rmt.ensembles.GOE(n=2000, seed=0)
24
+ spectrum = ens.sample(n_samples=1)
25
+ eigs = spectrum.rescaled[0]
26
+ for z in [3.0, 5.0, 10.0]:
27
+ empirical = rmt.stats.stieltjes_transform_empirical(eigs, z)
28
+ exact = rmt.stats.stieltjes_transform_semicircle(z)
29
+ assert empirical.real == pytest.approx(exact.real, abs=0.02)
30
+
31
+
32
+ def test_numerical_inversion_recovers_semicircle_r_transform():
33
+ # The pipeline itself, exercised on a Stieltjes transform with a
34
+ # known-exact R-transform (see module docstring for the derivation).
35
+ for w in [0.1, 0.3, 0.6, 0.9]:
36
+ r_numerical = rmt.stats.r_transform_numerical(rmt.stats.stieltjes_transform_semicircle, w, z_bracket=(2.0001, 100.0))
37
+ assert r_numerical == pytest.approx(rmt.stats.r_transform_semicircle(w), rel=1e-4)
38
+
39
+
40
+ def test_numerical_inversion_recovers_marchenko_pastur_r_transform():
41
+ gamma = 0.5
42
+ lo, hi = rmt.stats.mp_support(gamma)
43
+
44
+ def stieltjes_mp(z):
45
+ from scipy.integrate import quad
46
+
47
+ real, _ = quad(lambda x: rmt.stats.mp_pdf(np.array([x]), gamma)[0] / (z - x), lo, hi, limit=200)
48
+ return real
49
+
50
+ for w in [0.1, 0.3, 0.6]:
51
+ r_numerical = rmt.stats.r_transform_numerical(stieltjes_mp, w, z_bracket=(hi + 1e-6, hi + 50.0))
52
+ assert r_numerical == pytest.approx(rmt.stats.r_transform_marchenko_pastur(w, gamma), rel=1e-3)
53
+
54
+
55
+ def test_free_additive_convolution_for_goe_plus_wishart():
56
+ # The genuine content of free probability's additive convolution
57
+ # theorem: for independent (hence asymptotically free) GOE and
58
+ # Wishart matrices A, B, the R-transform of A+B's spectral
59
+ # distribution should equal R_A + R_B -- checked here against DIRECT
60
+ # matrix simulation, not just the two closed forms in isolation.
61
+ rng = np.random.default_rng(0)
62
+ n = 800
63
+ gamma = 0.5
64
+ m = int(n / gamma)
65
+
66
+ x = rng.standard_normal((n, n))
67
+ a = (x + x.T) / np.sqrt(2.0) / np.sqrt(n) # semicircle normalization, variance 1
68
+
69
+ y = rng.standard_normal((n, m)) / np.sqrt(m)
70
+ b = y @ y.T # Marchenko-Pastur normalization at aspect ratio gamma
71
+
72
+ c_eigs = np.linalg.eigvalsh(a + b)
73
+
74
+ def stieltjes_c(z):
75
+ return rmt.stats.stieltjes_transform_empirical(c_eigs, z)
76
+
77
+ z_bracket = (c_eigs.max() + 0.05, c_eigs.max() + 50.0)
78
+ for w in [0.1, 0.2, 0.3]:
79
+ r_c = rmt.stats.r_transform_numerical(stieltjes_c, w, z_bracket)
80
+ r_sum = rmt.stats.r_transform_semicircle(w) + rmt.stats.r_transform_marchenko_pastur(w, gamma)
81
+ assert r_c == pytest.approx(r_sum, rel=0.01)
@@ -0,0 +1,22 @@
1
+ """Coverage for physicskit.rmt.ensembles.gaussian.HermiteBetaEnsemble
2
+ (previously untested directly): the return_eigenvectors=True guard for
3
+ continuum (non-classical) beta values."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import numpy as np
8
+ import pytest
9
+
10
+ import physicskit.rmt as rmt
11
+
12
+
13
+ def test_return_eigenvectors_rejects_continuum_beta():
14
+ ens = rmt.ensembles.HermiteBetaEnsemble(n=10, beta=1.5, seed=0)
15
+ with pytest.raises(NotImplementedError):
16
+ ens.sample(n_samples=2, return_eigenvectors=True)
17
+
18
+
19
+ def test_return_eigenvectors_works_for_classical_beta():
20
+ ens = rmt.ensembles.GOE(n=10, seed=0)
21
+ spectrum = ens.sample(n_samples=2, return_eigenvectors=True)
22
+ assert np.all(np.isfinite(spectrum.eigenvalues))