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.
- physicskit/__init__.py +51 -0
- physicskit/astro/__init__.py +66 -0
- physicskit/astro/cosmic_web.py +395 -0
- physicskit/astro/galactic_dynamics.py +137 -0
- physicskit/astro/nbody.py +208 -0
- physicskit/astro/orbital_mechanics.py +220 -0
- physicskit/astro/stellar_dynamo.py +628 -0
- physicskit/astro/stellar_structure.py +198 -0
- physicskit/astro/tests/__init__.py +0 -0
- physicskit/astro/tests/conftest.py +7 -0
- physicskit/astro/tests/test_cosmic_web.py +159 -0
- physicskit/astro/tests/test_galactic_dynamics.py +46 -0
- physicskit/astro/tests/test_nbody.py +81 -0
- physicskit/astro/tests/test_orbital_mechanics.py +73 -0
- physicskit/astro/tests/test_stellar_dynamo.py +198 -0
- physicskit/astro/tests/test_stellar_structure.py +52 -0
- physicskit/astro/tests/test_visualizers.py +159 -0
- physicskit/astro/visualizers.py +628 -0
- physicskit/chaos/__init__.py +55 -0
- physicskit/chaos/core/__init__.py +3 -0
- physicskit/chaos/core/base_system.py +342 -0
- physicskit/chaos/core/integrators.py +40 -0
- physicskit/chaos/exceptions.py +24 -0
- physicskit/chaos/quantum/__init__.py +38 -0
- physicskit/chaos/quantum/billiards.py +274 -0
- physicskit/chaos/quantum/husimi.py +85 -0
- physicskit/chaos/quantum/maps.py +366 -0
- physicskit/chaos/systems/__init__.py +38 -0
- physicskit/chaos/systems/billiards.py +1131 -0
- physicskit/chaos/systems/continuous.py +1276 -0
- physicskit/chaos/systems/maps.py +557 -0
- physicskit/chaos/tests/__init__.py +0 -0
- physicskit/chaos/tests/test_basins.py +76 -0
- physicskit/chaos/tests/test_bifurcation.py +132 -0
- physicskit/chaos/tests/test_billiards.py +115 -0
- physicskit/chaos/tests/test_continuous.py +224 -0
- physicskit/chaos/tests/test_dimension.py +69 -0
- physicskit/chaos/tests/test_divergence.py +90 -0
- physicskit/chaos/tests/test_dynamic_plots.py +269 -0
- physicskit/chaos/tests/test_integrators.py +96 -0
- physicskit/chaos/tests/test_io.py +41 -0
- physicskit/chaos/tests/test_maps.py +110 -0
- physicskit/chaos/tests/test_metrics.py +115 -0
- physicskit/chaos/tests/test_phase_space.py +73 -0
- physicskit/chaos/tests/test_properties.py +116 -0
- physicskit/chaos/tests/test_quantum_billiards.py +94 -0
- physicskit/chaos/tests/test_quantum_maps.py +144 -0
- physicskit/chaos/tests/test_recurrence.py +51 -0
- physicskit/chaos/tests/test_repr_and_api_consistency.py +134 -0
- physicskit/chaos/tests/test_section.py +49 -0
- physicskit/chaos/tests/test_spectral.py +48 -0
- physicskit/chaos/tests/test_streamlit_app.py +45 -0
- physicskit/chaos/tests/test_timeseries.py +131 -0
- physicskit/chaos/tests/test_viewer3d.py +41 -0
- physicskit/chaos/utils/__init__.py +46 -0
- physicskit/chaos/utils/dimension.py +139 -0
- physicskit/chaos/utils/io.py +95 -0
- physicskit/chaos/utils/metrics.py +304 -0
- physicskit/chaos/utils/recurrence.py +122 -0
- physicskit/chaos/utils/spectral.py +69 -0
- physicskit/chaos/utils/timeseries.py +303 -0
- physicskit/chaos/visualizers/__init__.py +85 -0
- physicskit/chaos/visualizers/basins.py +185 -0
- physicskit/chaos/visualizers/bifurcation.py +273 -0
- physicskit/chaos/visualizers/divergence.py +374 -0
- physicskit/chaos/visualizers/dynamic_plots.py +1372 -0
- physicskit/chaos/visualizers/phase_space.py +133 -0
- physicskit/chaos/visualizers/quantum.py +299 -0
- physicskit/chaos/visualizers/recurrence.py +91 -0
- physicskit/chaos/visualizers/section.py +161 -0
- physicskit/chaos/visualizers/theme.py +31 -0
- physicskit/chaos/visualizers/viewer3d.py +82 -0
- physicskit/classical/__init__.py +55 -0
- physicskit/classical/core/__init__.py +17 -0
- physicskit/classical/core/base_system.py +510 -0
- physicskit/classical/core/integrators.py +397 -0
- physicskit/classical/systems/__init__.py +32 -0
- physicskit/classical/systems/chains.py +334 -0
- physicskit/classical/systems/hamiltonian.py +215 -0
- physicskit/classical/systems/lagrangian.py +308 -0
- physicskit/classical/systems/newtonian.py +536 -0
- physicskit/classical/systems/rotations.py +614 -0
- physicskit/classical/tests/__init__.py +0 -0
- physicskit/classical/tests/conftest.py +7 -0
- physicskit/classical/tests/test_base_system.py +113 -0
- physicskit/classical/tests/test_chains.py +84 -0
- physicskit/classical/tests/test_conservation.py +244 -0
- physicskit/classical/tests/test_conservation_utils.py +47 -0
- physicskit/classical/tests/test_hamiltonian.py +44 -0
- physicskit/classical/tests/test_integrators.py +123 -0
- physicskit/classical/tests/test_lagrangian.py +69 -0
- physicskit/classical/tests/test_newtonian.py +45 -0
- physicskit/classical/tests/test_rotations.py +160 -0
- physicskit/classical/tests/test_stepsize.py +149 -0
- physicskit/classical/tests/test_symbolic.py +125 -0
- physicskit/classical/tests/test_visualizers.py +172 -0
- physicskit/classical/utils/__init__.py +20 -0
- physicskit/classical/utils/conservation.py +126 -0
- physicskit/classical/utils/stepsize.py +187 -0
- physicskit/classical/utils/symbolic.py +235 -0
- physicskit/classical/visualizers/__init__.py +25 -0
- physicskit/classical/visualizers/animations.py +508 -0
- physicskit/classical/visualizers/interactive.py +113 -0
- physicskit/classical/visualizers/modal_analysis.py +97 -0
- physicskit/classical/visualizers/phase_space.py +214 -0
- physicskit/condensed/__init__.py +122 -0
- physicskit/condensed/anderson_localization.py +155 -0
- physicskit/condensed/correlated.py +284 -0
- physicskit/condensed/ginzburg_landau.py +220 -0
- physicskit/condensed/landau_levels.py +246 -0
- physicskit/condensed/laughlin.py +229 -0
- physicskit/condensed/models.py +627 -0
- physicskit/condensed/tests/__init__.py +0 -0
- physicskit/condensed/tests/test_condensed.py +518 -0
- physicskit/condensed/tests/test_visualizers.py +87 -0
- physicskit/condensed/tight_binding.py +445 -0
- physicskit/condensed/topological_insulator_3d.py +178 -0
- physicskit/condensed/topology.py +217 -0
- physicskit/condensed/visualizers.py +296 -0
- physicskit/condensed/weyl.py +180 -0
- physicskit/constants.py +184 -0
- physicskit/fields/__init__.py +111 -0
- physicskit/fields/electrodynamics.py +671 -0
- physicskit/fields/quantum_fields.py +510 -0
- physicskit/fields/solitons.py +527 -0
- physicskit/fields/tests/__init__.py +0 -0
- physicskit/fields/tests/conftest.py +7 -0
- physicskit/fields/tests/test_field_animations.py +154 -0
- physicskit/fields/tests/test_fields.py +439 -0
- physicskit/fields/tests/test_visualizers.py +101 -0
- physicskit/fields/visualizers.py +503 -0
- physicskit/fluids/__init__.py +134 -0
- physicskit/fluids/core/__init__.py +23 -0
- physicskit/fluids/core/grid.py +165 -0
- physicskit/fluids/core/timestepping.py +231 -0
- physicskit/fluids/exceptions.py +26 -0
- physicskit/fluids/systems/__init__.py +70 -0
- physicskit/fluids/systems/compressible_flow.py +281 -0
- physicskit/fluids/systems/instabilities.py +343 -0
- physicskit/fluids/systems/navier_stokes.py +221 -0
- physicskit/fluids/systems/potential_flow.py +440 -0
- physicskit/fluids/systems/viscous_flow.py +425 -0
- physicskit/fluids/systems/vortex_dynamics.py +304 -0
- physicskit/fluids/tests/__init__.py +0 -0
- physicskit/fluids/tests/conftest.py +7 -0
- physicskit/fluids/tests/test_compressible_flow.py +66 -0
- physicskit/fluids/tests/test_instabilities.py +115 -0
- physicskit/fluids/tests/test_navier_stokes.py +67 -0
- physicskit/fluids/tests/test_potential_flow.py +92 -0
- physicskit/fluids/tests/test_static_visualizers.py +91 -0
- physicskit/fluids/tests/test_utils.py +100 -0
- physicskit/fluids/tests/test_viscous_flow.py +110 -0
- physicskit/fluids/tests/test_visualizers.py +34 -0
- physicskit/fluids/tests/test_vortex_dynamics.py +88 -0
- physicskit/fluids/utils/__init__.py +18 -0
- physicskit/fluids/utils/dimensionless.py +239 -0
- physicskit/fluids/utils/spectral_analysis.py +142 -0
- physicskit/fluids/visualizers/__init__.py +14 -0
- physicskit/fluids/visualizers/compressible.py +39 -0
- physicskit/fluids/visualizers/flow_fields.py +252 -0
- physicskit/fluids/visualizers/potential_flow.py +51 -0
- physicskit/fluids/visualizers/spectra.py +62 -0
- physicskit/fluids/visualizers/theme.py +38 -0
- physicskit/integrators/__init__.py +52 -0
- physicskit/integrators/adaptive.py +199 -0
- physicskit/integrators/fixed_step.py +360 -0
- physicskit/integrators/tests/__init__.py +0 -0
- physicskit/integrators/tests/test_integrators.py +101 -0
- physicskit/optics/__init__.py +124 -0
- physicskit/optics/_compat.py +5 -0
- physicskit/optics/gaussian.py +382 -0
- physicskit/optics/quantum_optics.py +428 -0
- physicskit/optics/ray.py +469 -0
- physicskit/optics/tests/__init__.py +0 -0
- physicskit/optics/tests/test_diffraction_animation.py +38 -0
- physicskit/optics/tests/test_gaussian.py +170 -0
- physicskit/optics/tests/test_quantum_optics.py +147 -0
- physicskit/optics/tests/test_ray.py +177 -0
- physicskit/optics/tests/test_visualizers.py +58 -0
- physicskit/optics/tests/test_wave.py +146 -0
- physicskit/optics/visualizers.py +264 -0
- physicskit/optics/wave.py +365 -0
- physicskit/particle/__init__.py +152 -0
- physicskit/particle/collider.py +382 -0
- physicskit/particle/confinement.py +125 -0
- physicskit/particle/decays.py +357 -0
- physicskit/particle/electroweak.py +300 -0
- physicskit/particle/kinematics.py +271 -0
- physicskit/particle/neutrinos.py +84 -0
- physicskit/particle/nuclear.py +100 -0
- physicskit/particle/scattering.py +159 -0
- physicskit/particle/tests/__init__.py +0 -0
- physicskit/particle/tests/conftest.py +7 -0
- physicskit/particle/tests/test_collider.py +119 -0
- physicskit/particle/tests/test_confinement.py +42 -0
- physicskit/particle/tests/test_decays.py +112 -0
- physicskit/particle/tests/test_electroweak.py +97 -0
- physicskit/particle/tests/test_kinematics.py +138 -0
- physicskit/particle/tests/test_neutrinos.py +36 -0
- physicskit/particle/tests/test_nuclear.py +45 -0
- physicskit/particle/tests/test_scattering.py +64 -0
- physicskit/particle/tests/test_visualizers.py +214 -0
- physicskit/particle/visualizers/__init__.py +38 -0
- physicskit/particle/visualizers/animations.py +705 -0
- physicskit/particle/visualizers/static.py +101 -0
- physicskit/plasma/__init__.py +176 -0
- physicskit/plasma/acceleration.py +152 -0
- physicskit/plasma/instabilities.py +417 -0
- physicskit/plasma/kinetic.py +588 -0
- physicskit/plasma/mhd.py +463 -0
- physicskit/plasma/single_particle.py +562 -0
- physicskit/plasma/tests/__init__.py +0 -0
- physicskit/plasma/tests/conftest.py +7 -0
- physicskit/plasma/tests/test_new_time_domain_features.py +222 -0
- physicskit/plasma/tests/test_plasma.py +232 -0
- physicskit/plasma/tests/test_visualizers.py +79 -0
- physicskit/plasma/turbulence.py +219 -0
- physicskit/plasma/visualizers.py +868 -0
- physicskit/plasma/waves.py +549 -0
- physicskit/quantum/__init__.py +180 -0
- physicskit/quantum/_compat.py +20 -0
- physicskit/quantum/chapters/__init__.py +0 -0
- physicskit/quantum/chapters/entanglement.py +489 -0
- physicskit/quantum/chapters/harmonic_spin.py +517 -0
- physicskit/quantum/chapters/hydrogen_am.py +292 -0
- physicskit/quantum/chapters/perturbation.py +350 -0
- physicskit/quantum/chapters/potentials.py +997 -0
- physicskit/quantum/chapters/spin.py +306 -0
- physicskit/quantum/chapters/wave_packets.py +541 -0
- physicskit/quantum/core/__init__.py +0 -0
- physicskit/quantum/core/eigensolvers.py +311 -0
- physicskit/quantum/core/operators.py +296 -0
- physicskit/quantum/core/solvers.py +271 -0
- physicskit/quantum/tests/__init__.py +0 -0
- physicskit/quantum/tests/conftest.py +7 -0
- physicskit/quantum/tests/test_animations.py +225 -0
- physicskit/quantum/tests/test_compat.py +43 -0
- physicskit/quantum/tests/test_eigensolvers.py +24 -0
- physicskit/quantum/tests/test_entanglement.py +127 -0
- physicskit/quantum/tests/test_harmonic_spin.py +140 -0
- physicskit/quantum/tests/test_hydrogen_am.py +48 -0
- physicskit/quantum/tests/test_measure.py +110 -0
- physicskit/quantum/tests/test_operators.py +105 -0
- physicskit/quantum/tests/test_perturbation.py +112 -0
- physicskit/quantum/tests/test_physics_checks.py +131 -0
- physicskit/quantum/tests/test_potentials.py +191 -0
- physicskit/quantum/tests/test_solvers.py +70 -0
- physicskit/quantum/tests/test_spin.py +22 -0
- physicskit/quantum/tests/test_unitarity.py +84 -0
- physicskit/quantum/tests/test_wave_packets.py +53 -0
- physicskit/quantum/utils/__init__.py +0 -0
- physicskit/quantum/utils/measure.py +253 -0
- physicskit/quantum/visualizers/__init__.py +0 -0
- physicskit/quantum/visualizers/bloch_sphere.py +205 -0
- physicskit/quantum/visualizers/entanglement.py +58 -0
- physicskit/quantum/visualizers/orbitals.py +187 -0
- physicskit/quantum/visualizers/phase_space.py +179 -0
- physicskit/quantum/visualizers/wavefunctions.py +230 -0
- physicskit/relativity/__init__.py +61 -0
- physicskit/relativity/chapters/__init__.py +33 -0
- physicskit/relativity/chapters/cosmology.py +190 -0
- physicskit/relativity/chapters/gw_merger.py +399 -0
- physicskit/relativity/chapters/kerr.py +371 -0
- physicskit/relativity/chapters/lensing.py +196 -0
- physicskit/relativity/chapters/neutron_star.py +149 -0
- physicskit/relativity/chapters/schwarzschild.py +412 -0
- physicskit/relativity/chapters/timekeeping.py +133 -0
- physicskit/relativity/core/__init__.py +12 -0
- physicskit/relativity/core/geodesics.py +216 -0
- physicskit/relativity/core/kerr_raytracer.py +259 -0
- physicskit/relativity/core/raytracer.py +241 -0
- physicskit/relativity/core/tensors.py +468 -0
- physicskit/relativity/tests/__init__.py +0 -0
- physicskit/relativity/tests/test_conservations.py +54 -0
- physicskit/relativity/tests/test_constants.py +34 -0
- physicskit/relativity/tests/test_cosmology.py +61 -0
- physicskit/relativity/tests/test_gw_merger.py +117 -0
- physicskit/relativity/tests/test_kerr.py +116 -0
- physicskit/relativity/tests/test_kerr_raytracer.py +103 -0
- physicskit/relativity/tests/test_lensing.py +75 -0
- physicskit/relativity/tests/test_neutron_star.py +48 -0
- physicskit/relativity/tests/test_raytracer.py +67 -0
- physicskit/relativity/tests/test_schwarzschild.py +126 -0
- physicskit/relativity/tests/test_shadow_render.py +81 -0
- physicskit/relativity/tests/test_tensors.py +86 -0
- physicskit/relativity/tests/test_timekeeping.py +51 -0
- physicskit/relativity/tests/test_visualizers_misc.py +115 -0
- physicskit/relativity/utils/__init__.py +1 -0
- physicskit/relativity/utils/constants.py +232 -0
- physicskit/relativity/visualizers/__init__.py +46 -0
- physicskit/relativity/visualizers/interactive.py +127 -0
- physicskit/relativity/visualizers/shadow_render.py +367 -0
- physicskit/relativity/visualizers/spacetime_3d.py +92 -0
- physicskit/relativity/visualizers/spacetime_diagrams.py +198 -0
- physicskit/relativity/visualizers/wave_plots.py +185 -0
- physicskit/rmt/__init__.py +8 -0
- physicskit/rmt/ensembles/__init__.py +108 -0
- physicskit/rmt/ensembles/banded.py +114 -0
- physicskit/rmt/ensembles/base.py +135 -0
- physicskit/rmt/ensembles/bdg.py +218 -0
- physicskit/rmt/ensembles/chiral.py +308 -0
- physicskit/rmt/ensembles/circular.py +104 -0
- physicskit/rmt/ensembles/crossover.py +82 -0
- physicskit/rmt/ensembles/density_matrix.py +148 -0
- physicskit/rmt/ensembles/effective_hamiltonian.py +230 -0
- physicskit/rmt/ensembles/embedded.py +207 -0
- physicskit/rmt/ensembles/gaussian.py +153 -0
- physicskit/rmt/ensembles/ginibre.py +110 -0
- physicskit/rmt/ensembles/girko.py +190 -0
- physicskit/rmt/ensembles/graph_laplacian.py +92 -0
- physicskit/rmt/ensembles/haar.py +57 -0
- physicskit/rmt/ensembles/jacobi.py +182 -0
- physicskit/rmt/ensembles/poisson.py +77 -0
- physicskit/rmt/ensembles/polynomial.py +139 -0
- physicskit/rmt/ensembles/pt_symmetric.py +120 -0
- physicskit/rmt/ensembles/single_ring.py +170 -0
- physicskit/rmt/ensembles/sparse.py +95 -0
- physicskit/rmt/ensembles/syk.py +170 -0
- physicskit/rmt/ensembles/truncated_unitary.py +80 -0
- physicskit/rmt/ensembles/universality.py +92 -0
- physicskit/rmt/ensembles/wishart.py +88 -0
- physicskit/rmt/py.typed +0 -0
- physicskit/rmt/spectrum.py +82 -0
- physicskit/rmt/stats/__init__.py +160 -0
- physicskit/rmt/stats/characteristic_polynomial.py +77 -0
- physicskit/rmt/stats/circular_law.py +54 -0
- physicskit/rmt/stats/correlations.py +162 -0
- physicskit/rmt/stats/density.py +70 -0
- physicskit/rmt/stats/entanglement.py +36 -0
- physicskit/rmt/stats/free_probability.py +202 -0
- physicskit/rmt/stats/localization.py +338 -0
- physicskit/rmt/stats/marchenko_pastur.py +55 -0
- physicskit/rmt/stats/pt_symmetric.py +265 -0
- physicskit/rmt/stats/ratios.py +110 -0
- physicskit/rmt/stats/real_ginibre.py +134 -0
- physicskit/rmt/stats/rigidity.py +272 -0
- physicskit/rmt/stats/single_ring.py +95 -0
- physicskit/rmt/stats/spacing.py +150 -0
- physicskit/rmt/stats/tracy_widom.py +175 -0
- physicskit/rmt/stats/truncated_unitary.py +40 -0
- physicskit/rmt/stats/unfolding.py +37 -0
- physicskit/rmt/stats/wachter.py +67 -0
- physicskit/rmt/tests/__init__.py +0 -0
- physicskit/rmt/tests/cache_utils.py +107 -0
- physicskit/rmt/tests/conftest.py +8 -0
- physicskit/rmt/tests/test_banded.py +86 -0
- physicskit/rmt/tests/test_base.py +29 -0
- physicskit/rmt/tests/test_bdg.py +133 -0
- physicskit/rmt/tests/test_characteristic_polynomial.py +50 -0
- physicskit/rmt/tests/test_chiral.py +273 -0
- physicskit/rmt/tests/test_circular.py +225 -0
- physicskit/rmt/tests/test_crossover.py +72 -0
- physicskit/rmt/tests/test_density.py +23 -0
- physicskit/rmt/tests/test_density_matrix.py +181 -0
- physicskit/rmt/tests/test_effective_hamiltonian.py +140 -0
- physicskit/rmt/tests/test_embedded.py +169 -0
- physicskit/rmt/tests/test_free_probability.py +81 -0
- physicskit/rmt/tests/test_gaussian_ensembles.py +22 -0
- physicskit/rmt/tests/test_gaussian_semicircle.py +127 -0
- physicskit/rmt/tests/test_ginibre_circular_law.py +131 -0
- physicskit/rmt/tests/test_girko.py +178 -0
- physicskit/rmt/tests/test_graph_laplacian.py +102 -0
- physicskit/rmt/tests/test_haar.py +118 -0
- physicskit/rmt/tests/test_jacobi_wachter.py +136 -0
- physicskit/rmt/tests/test_localization.py +240 -0
- physicskit/rmt/tests/test_poisson.py +149 -0
- physicskit/rmt/tests/test_polynomial.py +107 -0
- physicskit/rmt/tests/test_pt_symmetric.py +178 -0
- physicskit/rmt/tests/test_random_state.py +19 -0
- physicskit/rmt/tests/test_real_ginibre.py +112 -0
- physicskit/rmt/tests/test_rigidity_universality.py +167 -0
- physicskit/rmt/tests/test_single_ring.py +132 -0
- physicskit/rmt/tests/test_spacing_and_ratios.py +122 -0
- physicskit/rmt/tests/test_sparse.py +71 -0
- physicskit/rmt/tests/test_spectrum.py +27 -0
- physicskit/rmt/tests/test_syk.py +136 -0
- physicskit/rmt/tests/test_tracy_widom.py +113 -0
- physicskit/rmt/tests/test_tridiagonal.py +41 -0
- physicskit/rmt/tests/test_truncated_unitary.py +80 -0
- physicskit/rmt/tests/test_validation_base.py +25 -0
- physicskit/rmt/tests/test_validation_misc.py +67 -0
- physicskit/rmt/tests/test_wishart_marchenko_pastur.py +120 -0
- physicskit/rmt/utils/__init__.py +0 -0
- physicskit/rmt/utils/haar.py +128 -0
- physicskit/rmt/utils/random_state.py +24 -0
- physicskit/rmt/utils/tridiagonal.py +167 -0
- physicskit/rmt/validation/__init__.py +36 -0
- physicskit/rmt/validation/base.py +126 -0
- physicskit/rmt/validation/circular_law.py +80 -0
- physicskit/rmt/validation/marchenko_pastur.py +53 -0
- physicskit/rmt/validation/ratio_distribution.py +53 -0
- physicskit/rmt/validation/real_ginibre.py +60 -0
- physicskit/rmt/validation/sine_kernel.py +57 -0
- physicskit/rmt/validation/single_ring.py +68 -0
- physicskit/rmt/validation/tracy_widom.py +89 -0
- physicskit/rmt/validation/universality.py +100 -0
- physicskit/rmt/validation/wachter.py +52 -0
- physicskit/rmt/validation/wigner_semicircle.py +40 -0
- physicskit/rmt/validation/wigner_surmise.py +58 -0
- physicskit/semiclassical/__init__.py +94 -0
- physicskit/semiclassical/_compat.py +5 -0
- physicskit/semiclassical/core/__init__.py +41 -0
- physicskit/semiclassical/core/gutzwiller.py +215 -0
- physicskit/semiclassical/core/path_integral.py +594 -0
- physicskit/semiclassical/core/propagators.py +579 -0
- physicskit/semiclassical/core/wkb.py +308 -0
- physicskit/semiclassical/systems/__init__.py +13 -0
- physicskit/semiclassical/systems/scarring.py +278 -0
- physicskit/semiclassical/tests/__init__.py +0 -0
- physicskit/semiclassical/tests/test_gutzwiller.py +35 -0
- physicskit/semiclassical/tests/test_path_integral.py +194 -0
- physicskit/semiclassical/tests/test_propagators.py +82 -0
- physicskit/semiclassical/tests/test_scarring.py +43 -0
- physicskit/semiclassical/tests/test_visualizers.py +89 -0
- physicskit/semiclassical/tests/test_wkb.py +30 -0
- physicskit/semiclassical/visualizers/__init__.py +17 -0
- physicskit/semiclassical/visualizers/gutzwiller.py +55 -0
- physicskit/semiclassical/visualizers/path_integral.py +195 -0
- physicskit/semiclassical/visualizers/propagators.py +89 -0
- physicskit/semiclassical/visualizers/scarring.py +146 -0
- physicskit/semiclassical/visualizers/wkb.py +55 -0
- physicskit/statphys/__init__.py +80 -0
- physicskit/statphys/chapters/__init__.py +43 -0
- physicskit/statphys/chapters/ehrenfest_urn.py +112 -0
- physicskit/statphys/chapters/ising_lattice.py +431 -0
- physicskit/statphys/chapters/kpz_growth.py +129 -0
- physicskit/statphys/chapters/molecular_dynamics.py +258 -0
- physicskit/statphys/chapters/nonequilibrium_work.py +146 -0
- physicskit/statphys/chapters/percolation.py +305 -0
- physicskit/statphys/chapters/random_walk.py +142 -0
- physicskit/statphys/chapters/renormalization.py +148 -0
- physicskit/statphys/chapters/sandpile.py +109 -0
- physicskit/statphys/chapters/spin_glass.py +275 -0
- physicskit/statphys/core/__init__.py +10 -0
- physicskit/statphys/core/kpz_engine.py +53 -0
- physicskit/statphys/core/md_engine.py +157 -0
- physicskit/statphys/core/monte_carlo.py +462 -0
- physicskit/statphys/core/random_walk_engine.py +68 -0
- physicskit/statphys/core/sandpile_engine.py +52 -0
- physicskit/statphys/tests/__init__.py +0 -0
- physicskit/statphys/tests/test_dynamics.py +66 -0
- physicskit/statphys/tests/test_ehrenfest_urn.py +44 -0
- physicskit/statphys/tests/test_finite_size_scaling.py +62 -0
- physicskit/statphys/tests/test_interactive.py +33 -0
- physicskit/statphys/tests/test_ising.py +68 -0
- physicskit/statphys/tests/test_kpz.py +55 -0
- physicskit/statphys/tests/test_landau_theory.py +49 -0
- physicskit/statphys/tests/test_md_engine.py +31 -0
- physicskit/statphys/tests/test_molecular_dynamics.py +72 -0
- physicskit/statphys/tests/test_nonequilibrium_work.py +33 -0
- physicskit/statphys/tests/test_partition_function.py +26 -0
- physicskit/statphys/tests/test_percolation.py +116 -0
- physicskit/statphys/tests/test_potts_model.py +46 -0
- physicskit/statphys/tests/test_random_walk.py +50 -0
- physicskit/statphys/tests/test_renormalization.py +44 -0
- physicskit/statphys/tests/test_sandpile.py +44 -0
- physicskit/statphys/tests/test_spin_glass.py +73 -0
- physicskit/statphys/tests/test_thermodynamics.py +121 -0
- physicskit/statphys/tests/test_xy_model.py +45 -0
- physicskit/statphys/utils/__init__.py +1 -0
- physicskit/statphys/utils/dynamics.py +100 -0
- physicskit/statphys/utils/finite_size_scaling.py +171 -0
- physicskit/statphys/utils/landau_theory.py +151 -0
- physicskit/statphys/utils/partition_function.py +109 -0
- physicskit/statphys/utils/thermodynamics.py +356 -0
- physicskit/statphys/visualizers/__init__.py +87 -0
- physicskit/statphys/visualizers/interactive.py +161 -0
- physicskit/statphys/visualizers/jarzynski_render.py +44 -0
- physicskit/statphys/visualizers/kpz_render.py +65 -0
- physicskit/statphys/visualizers/lattice_render.py +212 -0
- physicskit/statphys/visualizers/particle_render.py +121 -0
- physicskit/statphys/visualizers/random_walk_render.py +106 -0
- physicskit/statphys/visualizers/rg_render.py +45 -0
- physicskit/statphys/visualizers/sandpile_render.py +65 -0
- physicskit/statphys/visualizers/spin_glass_render.py +40 -0
- physicskit/statphys/visualizers/urn_render.py +38 -0
- physicskit/statphys/visualizers/vortex_render.py +84 -0
- physicskit/tests/__init__.py +0 -0
- physicskit/tests/test_constants.py +38 -0
- physicskit-0.1.0.dist-info/METADATA +196 -0
- physicskit-0.1.0.dist-info/RECORD +484 -0
- physicskit-0.1.0.dist-info/WHEEL +5 -0
- physicskit-0.1.0.dist-info/licenses/LICENSE +21 -0
- physicskit-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
r"""Quantum measurement simulator and expectation-value / uncertainty monitors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from .._compat import trapz
|
|
10
|
+
|
|
11
|
+
__all__ = ["expectation_value", "uncertainty", "momentum_density", "ExpectationMonitor", "simulate_position_measurement"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def expectation_value(operator_action, x: np.ndarray, psi: np.ndarray) -> complex:
|
|
15
|
+
r"""Expectation value of a local/differential operator.
|
|
16
|
+
|
|
17
|
+
.. math::
|
|
18
|
+
|
|
19
|
+
\langle\psi\rvert\hat A\lvert\psi\rangle
|
|
20
|
+
= \int \psi^*(x)\, [\hat A\psi](x)\, dx.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
operator_action : callable
|
|
25
|
+
A function ``operator_action(x, psi) -> A_psi`` applying
|
|
26
|
+
:math:`\hat A` to ``psi``.
|
|
27
|
+
x : numpy.ndarray
|
|
28
|
+
Positions.
|
|
29
|
+
psi : numpy.ndarray
|
|
30
|
+
Wavefunction sampled on ``x``.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
complex
|
|
35
|
+
"""
|
|
36
|
+
A_psi = operator_action(x, psi)
|
|
37
|
+
return complex(trapz(np.conj(psi) * A_psi, x))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def position_expectation(x: np.ndarray, psi: np.ndarray) -> float:
|
|
41
|
+
r"""Position expectation value :math:`\langle x\rangle = \int x\,\lvert\psi(x)\rvert^2\,dx`.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
x : numpy.ndarray
|
|
46
|
+
psi : numpy.ndarray
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
float
|
|
51
|
+
"""
|
|
52
|
+
return float(np.real(trapz(x * np.abs(psi) ** 2, x)))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def position_variance(x: np.ndarray, psi: np.ndarray) -> float:
|
|
56
|
+
r"""Position variance :math:`\langle x^2\rangle - \langle x\rangle^2`.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
x : numpy.ndarray
|
|
61
|
+
psi : numpy.ndarray
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
float
|
|
66
|
+
"""
|
|
67
|
+
density = np.abs(psi) ** 2
|
|
68
|
+
mean = trapz(x * density, x)
|
|
69
|
+
mean_sq = trapz(x**2 * density, x)
|
|
70
|
+
return float(np.real(mean_sq - mean**2))
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def momentum_density(x: np.ndarray, psi: np.ndarray, hbar: float = 1.0):
|
|
74
|
+
"""FFT-based momentum-space wavefunction and probability density.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
x : numpy.ndarray
|
|
79
|
+
Positions (uniform grid).
|
|
80
|
+
psi : numpy.ndarray
|
|
81
|
+
Wavefunction sampled on ``x``.
|
|
82
|
+
hbar : float, default=1.0
|
|
83
|
+
Value of :math:`\\hbar` to use.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
p : numpy.ndarray
|
|
88
|
+
Momentum grid, ascending.
|
|
89
|
+
psi_p : numpy.ndarray
|
|
90
|
+
Normalized momentum-space wavefunction.
|
|
91
|
+
"""
|
|
92
|
+
dx = x[1] - x[0]
|
|
93
|
+
N = x.shape[0]
|
|
94
|
+
k = 2 * np.pi * np.fft.fftfreq(N, d=dx)
|
|
95
|
+
psi_k = np.fft.fft(psi) * dx / np.sqrt(2 * np.pi)
|
|
96
|
+
p = hbar * k
|
|
97
|
+
order = np.argsort(p)
|
|
98
|
+
p_sorted, psi_k_sorted = p[order], psi_k[order]
|
|
99
|
+
norm = np.sqrt(trapz(np.abs(psi_k_sorted) ** 2, p_sorted))
|
|
100
|
+
return p_sorted, psi_k_sorted / norm
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def momentum_expectation(x: np.ndarray, psi: np.ndarray, hbar: float = 1.0) -> float:
|
|
104
|
+
r"""Momentum expectation value :math:`\langle p\rangle`, via :func:`momentum_density`.
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
x : numpy.ndarray
|
|
109
|
+
psi : numpy.ndarray
|
|
110
|
+
hbar : float, default=1.0
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
float
|
|
115
|
+
"""
|
|
116
|
+
p, psi_p = momentum_density(x, psi, hbar)
|
|
117
|
+
return float(np.real(trapz(p * np.abs(psi_p) ** 2, p)))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def momentum_variance(x: np.ndarray, psi: np.ndarray, hbar: float = 1.0) -> float:
|
|
121
|
+
r"""Momentum variance :math:`\langle p^2\rangle - \langle p\rangle^2`, via :func:`momentum_density`.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
x : numpy.ndarray
|
|
126
|
+
psi : numpy.ndarray
|
|
127
|
+
hbar : float, default=1.0
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
float
|
|
132
|
+
"""
|
|
133
|
+
p, psi_p = momentum_density(x, psi, hbar)
|
|
134
|
+
density = np.abs(psi_p) ** 2
|
|
135
|
+
mean = trapz(p * density, p)
|
|
136
|
+
mean_sq = trapz(p**2 * density, p)
|
|
137
|
+
return float(np.real(mean_sq - mean**2))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def uncertainty(x: np.ndarray, psi: np.ndarray, hbar: float = 1.0) -> tuple[float, float, float]:
|
|
141
|
+
r"""Position/momentum uncertainties and their product.
|
|
142
|
+
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
x : numpy.ndarray
|
|
146
|
+
psi : numpy.ndarray
|
|
147
|
+
hbar : float, default=1.0
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
dx, dp, product : float
|
|
152
|
+
:math:`\Delta x`, :math:`\Delta p`, and :math:`\Delta x\,\Delta p`,
|
|
153
|
+
for checking the Heisenberg bound :math:`\Delta x\,\Delta p \ge \hbar/2`.
|
|
154
|
+
"""
|
|
155
|
+
dx = np.sqrt(position_variance(x, psi))
|
|
156
|
+
dp = np.sqrt(momentum_variance(x, psi, hbar))
|
|
157
|
+
return dx, dp, dx * dp
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@dataclass
|
|
161
|
+
class ExpectationMonitor:
|
|
162
|
+
"""Tracks expectation values along a time-evolution trajectory.
|
|
163
|
+
|
|
164
|
+
Records :math:`\\langle x\\rangle(t)`, :math:`\\langle p\\rangle(t)`,
|
|
165
|
+
:math:`\\Delta x(t)`, :math:`\\Delta p(t)`, and the norm, e.g. from the
|
|
166
|
+
frames returned by a
|
|
167
|
+
:meth:`~physicskit.quantum.core.solvers.SplitOperatorSolver1D.propagate` call.
|
|
168
|
+
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
x : numpy.ndarray
|
|
172
|
+
Positions the wavefunction is sampled on.
|
|
173
|
+
hbar : float, default=1.0
|
|
174
|
+
Value of :math:`\\hbar` to use.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
x: np.ndarray
|
|
178
|
+
hbar: float = 1.0
|
|
179
|
+
history: dict = field(default_factory=lambda: {"t": [], "norm": [], "x": [], "p": [], "dx": [], "dp": []})
|
|
180
|
+
|
|
181
|
+
def record(self, t: float, psi: np.ndarray):
|
|
182
|
+
"""Record one snapshot.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
t : float
|
|
187
|
+
Time of the snapshot.
|
|
188
|
+
psi : numpy.ndarray
|
|
189
|
+
Wavefunction at time ``t``, sampled on ``self.x``.
|
|
190
|
+
"""
|
|
191
|
+
norm = trapz(np.abs(psi) ** 2, self.x)
|
|
192
|
+
dx, dp, _ = uncertainty(self.x, psi, self.hbar)
|
|
193
|
+
self.history["t"].append(t)
|
|
194
|
+
self.history["norm"].append(float(norm))
|
|
195
|
+
self.history["x"].append(position_expectation(self.x, psi))
|
|
196
|
+
self.history["p"].append(momentum_expectation(self.x, psi, self.hbar))
|
|
197
|
+
self.history["dx"].append(dx)
|
|
198
|
+
self.history["dp"].append(dp)
|
|
199
|
+
|
|
200
|
+
def record_all(self, times: np.ndarray, frames: np.ndarray):
|
|
201
|
+
"""Record a full trajectory.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
times : numpy.ndarray
|
|
206
|
+
Times of each snapshot.
|
|
207
|
+
frames : numpy.ndarray
|
|
208
|
+
Wavefunction snapshots, shape ``(len(times), len(self.x))``.
|
|
209
|
+
"""
|
|
210
|
+
for t, psi in zip(times, frames):
|
|
211
|
+
self.record(t, psi)
|
|
212
|
+
|
|
213
|
+
def as_arrays(self) -> dict:
|
|
214
|
+
"""Return the recorded history as arrays.
|
|
215
|
+
|
|
216
|
+
Returns
|
|
217
|
+
-------
|
|
218
|
+
dict
|
|
219
|
+
Maps ``'t'``, ``'norm'``, ``'x'``, ``'p'``, ``'dx'``, ``'dp'``
|
|
220
|
+
to :class:`numpy.ndarray`.
|
|
221
|
+
"""
|
|
222
|
+
return {k: np.array(v) for k, v in self.history.items()}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def simulate_position_measurement(x: np.ndarray, psi: np.ndarray, n_samples: int = 1, rng: np.random.Generator | None = None) -> np.ndarray:
|
|
226
|
+
r"""Sample simulated projective position measurements.
|
|
227
|
+
|
|
228
|
+
Draws :math:`x_i \sim \lvert\psi(x)\rvert^2` (the Born rule), via
|
|
229
|
+
inverse-CDF sampling on the discretized density.
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
x : numpy.ndarray
|
|
234
|
+
Positions.
|
|
235
|
+
psi : numpy.ndarray
|
|
236
|
+
Wavefunction sampled on ``x``.
|
|
237
|
+
n_samples : int, default=1
|
|
238
|
+
Number of simulated measurement outcomes to draw.
|
|
239
|
+
rng : numpy.random.Generator or None, optional
|
|
240
|
+
Random number generator; a fresh default one is used if omitted.
|
|
241
|
+
|
|
242
|
+
Returns
|
|
243
|
+
-------
|
|
244
|
+
numpy.ndarray
|
|
245
|
+
Simulated measurement outcomes, shape ``(n_samples,)``.
|
|
246
|
+
"""
|
|
247
|
+
rng = rng or np.random.default_rng()
|
|
248
|
+
density = np.abs(psi) ** 2
|
|
249
|
+
density = density / trapz(density, x)
|
|
250
|
+
cdf = np.concatenate([[0.0], np.cumsum((density[1:] + density[:-1]) / 2 * np.diff(x))])
|
|
251
|
+
cdf /= cdf[-1]
|
|
252
|
+
u = rng.random(n_samples)
|
|
253
|
+
return np.interp(u, cdf, x)
|
|
File without changes
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
r"""Interactive 3D Bloch-sphere qubit trajectories (Plotly), and a frame-by-frame
|
|
2
|
+
matplotlib animation of the vector advancing along a trajectory."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
import numpy as np
|
|
8
|
+
import plotly.graph_objects as go
|
|
9
|
+
from matplotlib.animation import FuncAnimation
|
|
10
|
+
|
|
11
|
+
from ..core.operators import sigma_x, sigma_y, sigma_z
|
|
12
|
+
|
|
13
|
+
__all__ = ["bloch_vector", "state_to_bloch_trajectory", "plot_bloch_sphere", "animate_bloch_sphere"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def bloch_vector(psi: np.ndarray) -> np.ndarray:
|
|
17
|
+
r"""The Bloch-sphere coordinates of a single-qubit pure state.
|
|
18
|
+
|
|
19
|
+
.. math::
|
|
20
|
+
|
|
21
|
+
\mathbf n = \left(\langle\psi\rvert\sigma_x\lvert\psi\rangle,\;
|
|
22
|
+
\langle\psi\rvert\sigma_y\lvert\psi\rangle,\;
|
|
23
|
+
\langle\psi\rvert\sigma_z\lvert\psi\rangle\right).
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
psi : numpy.ndarray
|
|
28
|
+
A 2-component qubit state vector.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
numpy.ndarray
|
|
33
|
+
The 3-component Bloch vector ``(x, y, z)``.
|
|
34
|
+
"""
|
|
35
|
+
psi = np.asarray(psi, dtype=complex)
|
|
36
|
+
x = np.real(np.vdot(psi, sigma_x @ psi))
|
|
37
|
+
y = np.real(np.vdot(psi, sigma_y @ psi))
|
|
38
|
+
z = np.real(np.vdot(psi, sigma_z @ psi))
|
|
39
|
+
return np.array([x, y, z])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def state_to_bloch_trajectory(states: np.ndarray) -> np.ndarray:
|
|
43
|
+
"""Convert a time series of qubit states to Bloch-vector coordinates.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
states : numpy.ndarray
|
|
48
|
+
Qubit state vectors over time, shape ``(n_times, 2)``.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
numpy.ndarray
|
|
53
|
+
Bloch vectors, shape ``(n_times, 3)``.
|
|
54
|
+
"""
|
|
55
|
+
return np.array([bloch_vector(psi) for psi in states])
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _sphere_mesh(n: int = 40):
|
|
59
|
+
u = np.linspace(0, 2 * np.pi, n)
|
|
60
|
+
v = np.linspace(0, np.pi, n)
|
|
61
|
+
xs = np.outer(np.cos(u), np.sin(v))
|
|
62
|
+
ys = np.outer(np.sin(u), np.sin(v))
|
|
63
|
+
zs = np.outer(np.ones_like(u), np.cos(v))
|
|
64
|
+
return xs, ys, zs
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def plot_bloch_sphere(trajectory: np.ndarray | None = None, vectors: list[np.ndarray] | None = None, labels: list[str] | None = None) -> go.Figure:
|
|
68
|
+
"""Render the Bloch sphere.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
trajectory : numpy.ndarray or None, optional
|
|
73
|
+
Bloch vectors traced over time, shape ``(n_times, 3)`` (e.g. from
|
|
74
|
+
:func:`state_to_bloch_trajectory`).
|
|
75
|
+
vectors : list of numpy.ndarray or None, optional
|
|
76
|
+
Static vectors to mark, each a 3-component array.
|
|
77
|
+
labels : list of str or None, optional
|
|
78
|
+
Labels for ``vectors``; defaults to ``v0, v1, ...``.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
plotly.graph_objects.Figure
|
|
83
|
+
"""
|
|
84
|
+
xs, ys, zs = _sphere_mesh()
|
|
85
|
+
fig = go.Figure()
|
|
86
|
+
fig.add_trace(go.Surface(x=xs, y=ys, z=zs, opacity=0.15, showscale=False, colorscale=[[0, "lightblue"], [1, "lightblue"]]))
|
|
87
|
+
|
|
88
|
+
axis_len = 1.3
|
|
89
|
+
for axis, name in zip(np.eye(3), ["x", "y", "z"]):
|
|
90
|
+
fig.add_trace(
|
|
91
|
+
go.Scatter3d(
|
|
92
|
+
x=[-axis_len * axis[0], axis_len * axis[0]],
|
|
93
|
+
y=[-axis_len * axis[1], axis_len * axis[1]],
|
|
94
|
+
z=[-axis_len * axis[2], axis_len * axis[2]],
|
|
95
|
+
mode="lines",
|
|
96
|
+
line=dict(color="gray", width=2),
|
|
97
|
+
showlegend=False,
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
fig.add_trace(go.Scatter3d(x=[axis_len * axis[0]], y=[axis_len * axis[1]], z=[axis_len * axis[2]], mode="text", text=[name], showlegend=False))
|
|
101
|
+
|
|
102
|
+
if trajectory is not None:
|
|
103
|
+
fig.add_trace(
|
|
104
|
+
go.Scatter3d(
|
|
105
|
+
x=trajectory[:, 0],
|
|
106
|
+
y=trajectory[:, 1],
|
|
107
|
+
z=trajectory[:, 2],
|
|
108
|
+
mode="lines+markers",
|
|
109
|
+
marker=dict(size=3, color=np.arange(len(trajectory)), colorscale="Viridis"),
|
|
110
|
+
line=dict(color="darkred", width=4),
|
|
111
|
+
name="trajectory",
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if vectors is not None:
|
|
116
|
+
for i, v in enumerate(vectors):
|
|
117
|
+
label = labels[i] if labels else f"v{i}"
|
|
118
|
+
fig.add_trace(
|
|
119
|
+
go.Scatter3d(
|
|
120
|
+
x=[0, v[0]],
|
|
121
|
+
y=[0, v[1]],
|
|
122
|
+
z=[0, v[2]],
|
|
123
|
+
mode="lines+markers",
|
|
124
|
+
line=dict(width=6),
|
|
125
|
+
marker=dict(size=[0, 6]),
|
|
126
|
+
name=label,
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
fig.update_layout(
|
|
131
|
+
scene=dict(
|
|
132
|
+
xaxis=dict(range=[-1.4, 1.4]),
|
|
133
|
+
yaxis=dict(range=[-1.4, 1.4]),
|
|
134
|
+
zaxis=dict(range=[-1.4, 1.4]),
|
|
135
|
+
aspectmode="cube",
|
|
136
|
+
),
|
|
137
|
+
margin=dict(l=0, r=0, t=30, b=0),
|
|
138
|
+
title="Bloch sphere",
|
|
139
|
+
)
|
|
140
|
+
return fig
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def animate_bloch_sphere(trajectory: np.ndarray, times: np.ndarray | None = None, interval: int = 30, trail: bool = True, ax=None) -> FuncAnimation:
|
|
144
|
+
"""A matplotlib mplot3d ``FuncAnimation`` of the Bloch vector advancing along a trajectory.
|
|
145
|
+
|
|
146
|
+
Unlike :func:`plot_bloch_sphere` (which draws the whole path as one
|
|
147
|
+
static Plotly trace), this genuinely animates: the arrow from the
|
|
148
|
+
origin sweeps frame-by-frame along ``trajectory``, optionally leaving a
|
|
149
|
+
fading trail.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
trajectory : numpy.ndarray
|
|
154
|
+
Bloch vectors over time, shape ``(n_frames, 3)`` (e.g. from
|
|
155
|
+
:func:`state_to_bloch_trajectory`).
|
|
156
|
+
times : numpy.ndarray or None, optional
|
|
157
|
+
Time of each frame, used to label the animation title.
|
|
158
|
+
interval : int, default=30
|
|
159
|
+
Delay between frames, in milliseconds.
|
|
160
|
+
trail : bool, default=True
|
|
161
|
+
Whether to draw the path swept out so far.
|
|
162
|
+
ax : mpl_toolkits.mplot3d.axes3d.Axes3D or None, optional
|
|
163
|
+
Axis to draw on; a new 3D figure/axis is created if omitted.
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
matplotlib.animation.FuncAnimation
|
|
168
|
+
"""
|
|
169
|
+
if ax is None:
|
|
170
|
+
fig = plt.figure(figsize=(6, 6))
|
|
171
|
+
ax = fig.add_subplot(111, projection="3d")
|
|
172
|
+
else:
|
|
173
|
+
fig = ax.figure
|
|
174
|
+
|
|
175
|
+
u = np.linspace(0, 2 * np.pi, 30)
|
|
176
|
+
v = np.linspace(0, np.pi, 30)
|
|
177
|
+
xs = np.outer(np.cos(u), np.sin(v))
|
|
178
|
+
ys = np.outer(np.sin(u), np.sin(v))
|
|
179
|
+
zs = np.outer(np.ones_like(u), np.cos(v))
|
|
180
|
+
ax.plot_wireframe(xs, ys, zs, color="lightblue", alpha=0.2, linewidth=0.5)
|
|
181
|
+
|
|
182
|
+
axis_len = 1.3
|
|
183
|
+
for axis in np.eye(3):
|
|
184
|
+
ax.plot(*zip(-axis_len * axis, axis_len * axis), color="gray", lw=1)
|
|
185
|
+
|
|
186
|
+
ax.set_xlim(-1.3, 1.3)
|
|
187
|
+
ax.set_ylim(-1.3, 1.3)
|
|
188
|
+
ax.set_zlim(-1.3, 1.3)
|
|
189
|
+
ax.set_box_aspect((1, 1, 1))
|
|
190
|
+
|
|
191
|
+
(arrow_line,) = ax.plot([0, trajectory[0, 0]], [0, trajectory[0, 1]], [0, trajectory[0, 2]], color="darkred", lw=3, marker="o", markevery=[1])
|
|
192
|
+
(trail_line,) = ax.plot([], [], [], color="darkorange", lw=1.5, alpha=0.7)
|
|
193
|
+
|
|
194
|
+
def update(i):
|
|
195
|
+
vec = trajectory[i]
|
|
196
|
+
arrow_line.set_data([0, vec[0]], [0, vec[1]])
|
|
197
|
+
arrow_line.set_3d_properties([0, vec[2]])
|
|
198
|
+
if trail:
|
|
199
|
+
trail_line.set_data(trajectory[: i + 1, 0], trajectory[: i + 1, 1])
|
|
200
|
+
trail_line.set_3d_properties(trajectory[: i + 1, 2])
|
|
201
|
+
title = f"t = {times[i]:.3f}" if times is not None else f"frame {i}"
|
|
202
|
+
ax.set_title(title)
|
|
203
|
+
return arrow_line, trail_line
|
|
204
|
+
|
|
205
|
+
return FuncAnimation(fig, update, frames=len(trajectory), interval=interval, blit=False)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
r"""Animated growth of an entanglement measure over time."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
import numpy as np
|
|
7
|
+
from matplotlib.animation import FuncAnimation
|
|
8
|
+
|
|
9
|
+
__all__ = ["animate_entanglement_growth"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def animate_entanglement_growth(t_values: np.ndarray, metric_values: np.ndarray, ylabel: str = "concurrence", interval: int = 30, ax=None) -> FuncAnimation:
|
|
13
|
+
"""Animate a point tracing out an entanglement-measure curve as it builds up over time.
|
|
14
|
+
|
|
15
|
+
Draws the curve ``metric_values`` vs. ``t_values`` progressively (rather
|
|
16
|
+
than all at once), with a marker at the current time -- e.g. the
|
|
17
|
+
concurrence or reduced-state purity of
|
|
18
|
+
:class:`~physicskit.quantum.chapters.entanglement.IsingEntangler` growing
|
|
19
|
+
from 0 (product state) toward 1 (maximally entangled) as the coupling acts.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
t_values : numpy.ndarray
|
|
24
|
+
Times.
|
|
25
|
+
metric_values : numpy.ndarray
|
|
26
|
+
The entanglement measure evaluated at each time in ``t_values``.
|
|
27
|
+
ylabel : str, default='concurrence'
|
|
28
|
+
Label for the y-axis.
|
|
29
|
+
interval : int, default=30
|
|
30
|
+
Delay between frames, in milliseconds.
|
|
31
|
+
ax : matplotlib.axes.Axes or None, optional
|
|
32
|
+
Axis to draw on; a new figure/axis is created if omitted.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
matplotlib.animation.FuncAnimation
|
|
37
|
+
"""
|
|
38
|
+
if ax is None:
|
|
39
|
+
fig, ax = plt.subplots(figsize=(7, 4))
|
|
40
|
+
else:
|
|
41
|
+
fig = ax.figure
|
|
42
|
+
|
|
43
|
+
ax.set_xlim(t_values.min(), t_values.max())
|
|
44
|
+
ymax = metric_values.max() * 1.1 if metric_values.max() > 0 else 1.0
|
|
45
|
+
ax.set_ylim(0, ymax)
|
|
46
|
+
ax.set_xlabel("t")
|
|
47
|
+
ax.set_ylabel(ylabel)
|
|
48
|
+
|
|
49
|
+
(line,) = ax.plot([], [], color="C0", lw=2)
|
|
50
|
+
(point,) = ax.plot([], [], "o", color="darkred", markersize=8)
|
|
51
|
+
|
|
52
|
+
def update(i):
|
|
53
|
+
line.set_data(t_values[: i + 1], metric_values[: i + 1])
|
|
54
|
+
point.set_data([t_values[i]], [metric_values[i]])
|
|
55
|
+
ax.set_title(f"t = {t_values[i]:.3f}")
|
|
56
|
+
return line, point
|
|
57
|
+
|
|
58
|
+
return FuncAnimation(fig, update, frames=len(t_values), interval=interval, blit=False)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
r"""3D volumetric rendering of hydrogen electron density clouds (Plotly)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import plotly.graph_objects as go
|
|
7
|
+
|
|
8
|
+
from ..chapters.hydrogen_am import HydrogenOrbital, orbital_superposition_density
|
|
9
|
+
|
|
10
|
+
__all__ = ["orbital_density_grid", "plot_orbital_cloud", "animate_orbital_beating"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def orbital_density_grid(orbital: HydrogenOrbital, extent: float | None = None, n_points: int = 60):
|
|
14
|
+
r"""Evaluate :math:`\lvert\psi_{nlm}\rvert^2` on a Cartesian grid.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
orbital : physicskit.quantum.chapters.hydrogen_am.HydrogenOrbital
|
|
19
|
+
The orbital to evaluate.
|
|
20
|
+
extent : float or None, optional
|
|
21
|
+
Half-width of the cubic grid; defaults to a value scaled to the
|
|
22
|
+
orbital's expected extent.
|
|
23
|
+
n_points : int, default=60
|
|
24
|
+
Number of grid points along each Cartesian axis.
|
|
25
|
+
|
|
26
|
+
Returns
|
|
27
|
+
-------
|
|
28
|
+
X, Y, Z : numpy.ndarray
|
|
29
|
+
Cartesian coordinate meshgrid.
|
|
30
|
+
density : numpy.ndarray
|
|
31
|
+
:math:`\lvert\psi_{nlm}\rvert^2` on the grid.
|
|
32
|
+
"""
|
|
33
|
+
if extent is None:
|
|
34
|
+
extent = 3 * orbital.n**2 * orbital.a0 / orbital.Z + 8
|
|
35
|
+
|
|
36
|
+
lin = np.linspace(-extent, extent, n_points)
|
|
37
|
+
X, Y, Z = np.meshgrid(lin, lin, lin, indexing="ij")
|
|
38
|
+
r = np.sqrt(X**2 + Y**2 + Z**2)
|
|
39
|
+
r_safe = np.where(r == 0, 1e-9, r)
|
|
40
|
+
theta = np.arccos(np.clip(Z / r_safe, -1, 1))
|
|
41
|
+
phi = np.arctan2(Y, X) % (2 * np.pi)
|
|
42
|
+
|
|
43
|
+
density = orbital.density(r, theta, phi)
|
|
44
|
+
return X, Y, Z, density
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def plot_orbital_cloud(
|
|
48
|
+
orbital: HydrogenOrbital, extent: float | None = None, n_points: int = 55, iso_fraction: float = 0.02, surface_count: int = 12
|
|
49
|
+
) -> go.Figure:
|
|
50
|
+
r"""Volumetric isosurface render of the electron probability density.
|
|
51
|
+
|
|
52
|
+
Renders :math:`\lvert\psi_{nlm}(r,\theta,\phi)\rvert^2` for a hydrogen
|
|
53
|
+
orbital as a set of nested isosurfaces.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
orbital : physicskit.quantum.chapters.hydrogen_am.HydrogenOrbital
|
|
58
|
+
The orbital to render.
|
|
59
|
+
extent : float or None, optional
|
|
60
|
+
Half-width of the cubic grid; see :func:`orbital_density_grid`.
|
|
61
|
+
n_points : int, default=55
|
|
62
|
+
Number of grid points along each Cartesian axis.
|
|
63
|
+
iso_fraction : float, default=0.02
|
|
64
|
+
Lowest isosurface level, as a fraction of the peak density.
|
|
65
|
+
surface_count : int, default=12
|
|
66
|
+
Number of nested isosurfaces to draw.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
plotly.graph_objects.Figure
|
|
71
|
+
"""
|
|
72
|
+
X, Y, Z, density = orbital_density_grid(orbital, extent, n_points)
|
|
73
|
+
dmax = density.max()
|
|
74
|
+
|
|
75
|
+
fig = go.Figure(
|
|
76
|
+
data=go.Volume(
|
|
77
|
+
x=X.flatten(),
|
|
78
|
+
y=Y.flatten(),
|
|
79
|
+
z=Z.flatten(),
|
|
80
|
+
value=density.flatten(),
|
|
81
|
+
isomin=iso_fraction * dmax,
|
|
82
|
+
isomax=dmax,
|
|
83
|
+
opacity=0.12,
|
|
84
|
+
surface_count=surface_count,
|
|
85
|
+
colorscale="Plasma",
|
|
86
|
+
caps=dict(x_show=False, y_show=False, z_show=False),
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
fig.update_layout(
|
|
90
|
+
title=f"|psi_{{{orbital.n},{orbital.l},{orbital.m}}}|^2",
|
|
91
|
+
scene=dict(xaxis_title="x", yaxis_title="y", zaxis_title="z", aspectmode="cube"),
|
|
92
|
+
margin=dict(l=0, r=0, t=30, b=0),
|
|
93
|
+
)
|
|
94
|
+
return fig
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def animate_orbital_beating(
|
|
98
|
+
orb_a: HydrogenOrbital,
|
|
99
|
+
orb_b: HydrogenOrbital,
|
|
100
|
+
times: np.ndarray,
|
|
101
|
+
extent: float | None = None,
|
|
102
|
+
n_points: int = 35,
|
|
103
|
+
ca: complex = 2**-0.5,
|
|
104
|
+
cb: complex = 2**-0.5,
|
|
105
|
+
iso_fraction: float = 0.05,
|
|
106
|
+
surface_count: int = 8,
|
|
107
|
+
) -> go.Figure:
|
|
108
|
+
r"""Plotly ``frames``-based animation of a two-orbital density beating.
|
|
109
|
+
|
|
110
|
+
Unlike a single stationary orbital (:func:`plot_orbital_cloud`, static in
|
|
111
|
+
time since :math:`\lvert\psi_{nlm}\rvert^2` is time-independent), the
|
|
112
|
+
density of a coherent superposition of two eigenstates
|
|
113
|
+
(:func:`~physicskit.quantum.chapters.hydrogen_am.orbital_superposition_density`)
|
|
114
|
+
genuinely reshapes at the Bohr frequency :math:`\omega_{ab}=E_a-E_b` --
|
|
115
|
+
rendered here as a play-button-driven sequence of isosurface frames.
|
|
116
|
+
|
|
117
|
+
Parameters
|
|
118
|
+
----------
|
|
119
|
+
orb_a, orb_b : HydrogenOrbital
|
|
120
|
+
The two eigenstates in the superposition.
|
|
121
|
+
times : numpy.ndarray
|
|
122
|
+
Times to render frames at.
|
|
123
|
+
extent : float or None, optional
|
|
124
|
+
Half-width of the cubic grid; defaults to a value scaled to
|
|
125
|
+
``orb_a``'s expected extent.
|
|
126
|
+
n_points : int, default=35
|
|
127
|
+
Number of grid points along each Cartesian axis (kept modest since
|
|
128
|
+
a full 3D grid is evaluated at every frame).
|
|
129
|
+
ca, cb : complex, default=1/sqrt(2) each
|
|
130
|
+
Superposition amplitudes.
|
|
131
|
+
iso_fraction : float, default=0.05
|
|
132
|
+
Lowest isosurface level, as a fraction of the peak density (over all
|
|
133
|
+
frames).
|
|
134
|
+
surface_count : int, default=8
|
|
135
|
+
Number of nested isosurfaces to draw per frame.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
plotly.graph_objects.Figure
|
|
140
|
+
With a "Play"/"Pause" button stepping through ``times``.
|
|
141
|
+
"""
|
|
142
|
+
if extent is None:
|
|
143
|
+
extent = 3 * orb_a.n**2 * orb_a.a0 / orb_a.Z + 8
|
|
144
|
+
|
|
145
|
+
lin = np.linspace(-extent, extent, n_points)
|
|
146
|
+
X, Y, Z = np.meshgrid(lin, lin, lin, indexing="ij")
|
|
147
|
+
r = np.sqrt(X**2 + Y**2 + Z**2)
|
|
148
|
+
r_safe = np.where(r == 0, 1e-9, r)
|
|
149
|
+
theta = np.arccos(np.clip(Z / r_safe, -1, 1))
|
|
150
|
+
phi = np.arctan2(Y, X) % (2 * np.pi)
|
|
151
|
+
|
|
152
|
+
densities = [orbital_superposition_density(orb_a, orb_b, r, theta, phi, t, ca, cb) for t in times]
|
|
153
|
+
dmax = max(d.max() for d in densities)
|
|
154
|
+
|
|
155
|
+
def volume_trace(density):
|
|
156
|
+
return go.Volume(
|
|
157
|
+
x=X.flatten(),
|
|
158
|
+
y=Y.flatten(),
|
|
159
|
+
z=Z.flatten(),
|
|
160
|
+
value=density.flatten(),
|
|
161
|
+
isomin=iso_fraction * dmax,
|
|
162
|
+
isomax=dmax,
|
|
163
|
+
opacity=0.12,
|
|
164
|
+
surface_count=surface_count,
|
|
165
|
+
colorscale="Plasma",
|
|
166
|
+
caps=dict(x_show=False, y_show=False, z_show=False),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
frames = [go.Frame(data=[volume_trace(d)], name=f"{i}") for i, d in enumerate(densities)]
|
|
170
|
+
|
|
171
|
+
fig = go.Figure(data=[volume_trace(densities[0])], frames=frames)
|
|
172
|
+
fig.update_layout(
|
|
173
|
+
title=f"|c_a psi_{{{orb_a.n},{orb_a.l},{orb_a.m}}} + c_b psi_{{{orb_b.n},{orb_b.l},{orb_b.m}}}|^2",
|
|
174
|
+
scene=dict(xaxis_title="x", yaxis_title="y", zaxis_title="z", aspectmode="cube"),
|
|
175
|
+
margin=dict(l=0, r=0, t=30, b=0),
|
|
176
|
+
updatemenus=[
|
|
177
|
+
dict(
|
|
178
|
+
type="buttons",
|
|
179
|
+
showactive=False,
|
|
180
|
+
buttons=[
|
|
181
|
+
dict(label="Play", method="animate", args=[None, dict(frame=dict(duration=100, redraw=True), fromcurrent=True)]),
|
|
182
|
+
dict(label="Pause", method="animate", args=[[None], dict(frame=dict(duration=0, redraw=False), mode="immediate")]),
|
|
183
|
+
],
|
|
184
|
+
)
|
|
185
|
+
],
|
|
186
|
+
)
|
|
187
|
+
return fig
|