diff --git a/Project.toml b/Project.toml index db5c6f4..f23a853 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "AbstractQAtlas" uuid = "dcea2817-62f8-4a75-b498-1b50a9ed1e4d" -version = "0.7.13" +version = "0.7.14" authors = ["sota shimozono "] [deps] diff --git a/docs/references.bib b/docs/references.bib index baf8b46..556fa09 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -858,3 +858,25 @@ @article{Peterson1967 publisher = {American Physical Society (APS)}, doi = {10.1103/RevModPhys.39.69} } + +@article{AharonyHarris1996, + title = {Absence of Self-Averaging and Universal Fluctuations in Random Systems near Critical Points}, + author = {Aharony, Amnon and Harris, A. B.}, + journal = {Physical Review Letters}, + volume = {77}, + number = {18}, + pages = {3700--3703}, + year = {1996}, + doi = {10.1103/PhysRevLett.77.3700} +} + +@article{WisemanDomany1998, + title = {Finite-Size Scaling and Lack of Self-Averaging in Critical Disordered Systems}, + author = {Wiseman, Shai and Domany, Eytan}, + journal = {Physical Review Letters}, + volume = {81}, + number = {1}, + pages = {22--25}, + year = {1998}, + doi = {10.1103/PhysRevLett.81.22} +} diff --git a/src/AbstractQAtlas.jl b/src/AbstractQAtlas.jl index f91ca36..0dfe6d5 100644 --- a/src/AbstractQAtlas.jl +++ b/src/AbstractQAtlas.jl @@ -95,6 +95,7 @@ include("relations/interface.jl") "Equilibrium statistical mechanics: occupation statistics → ensembles → thermodynamic potentials → response, FDT & stability." module StatisticalMechanics using ..AbstractQAtlas + import ..AbstractQAtlas: fetch # unexported, so bare `fetch` here would be Base's using ..AbstractQAtlas: _beta # β-or-T normalization (occupation functions) import ..AbstractQAtlas: _solve # extended for a non-affine variable (FreeEnergyFromZ:Z) include("relations/thermodynamic.jl") @@ -107,6 +108,8 @@ end "Critical phenomena and conformal field theory: scaling laws, finite-size scaling, Cardy, the c-theorem." module Criticality using ..AbstractQAtlas + import ..AbstractQAtlas: fetch # unexported, so bare `fetch` here would be Base's + import ..AbstractQAtlas: _solve # extended for a non-affine variable (PseudocriticalWidthScaling:ν) include("relations/scaling.jl") include("relations/cft.jl") end @@ -114,6 +117,7 @@ end "Correlations, Green's functions and response: the spectral graph (Dyson, A=−ImG/π), the Keldysh RAK structure + fluctuation–dissipation, Wick / Bloch–De Dominicis (Gaussian factorization), Kramers–Kronig, detailed balance." module Correlations using ..AbstractQAtlas + import ..AbstractQAtlas: fetch # unexported, so bare `fetch` here would be Base's using LinearAlgebra: inv, det include("relations/spectral.jl") include("relations/keldysh.jl") @@ -123,12 +127,14 @@ end "Transport: DC/AC conductivity, thermal & thermoelectric coefficients, the Hall family, Onsager, Wiedemann–Franz, optical sum rule, Johnson–Nyquist." module Transport using ..AbstractQAtlas + import ..AbstractQAtlas: fetch # unexported, so bare `fetch` here would be Base's include("relations/transport.jl") end "Quantum information & entanglement: the entropy zoo, its inequalities, multipartite entanglement, measurement and topological entanglement entropy." module QuantumInformation using ..AbstractQAtlas + import ..AbstractQAtlas: fetch # unexported, so bare `fetch` here would be Base's using ExperimentalAPI: @experimental include("relations/entanglement.jl") end @@ -136,18 +142,21 @@ end "Quantum-mechanical foundations & bounds: virial, Hellmann–Feynman, Ehrenfest, zero-variance eigenstate, the uncertainty relation and the Lieb–Robinson bound." module QuantumFoundations using ..AbstractQAtlas + import ..AbstractQAtlas: fetch # unexported, so bare `fetch` here would be Base's include("relations/quantum.jl") end "Universal bounds stated against a fetched bounding value: Bell (CHSH, Mermin), chaos (MSS), speed limits, fast scrambling, BB84 key rate, optimal cloning, Bekenstein." module UniversalBounds using ..AbstractQAtlas + import ..AbstractQAtlas: fetch # unexported, so bare `fetch` here would be Base's include("relations/bounds.jl") end "Topological invariants: Chern number, TKNN, winding, bulk–boundary correspondence." module Topology using ..AbstractQAtlas + import ..AbstractQAtlas: fetch # unexported, so bare `fetch` here would be Base's using LinearAlgebra: det, eigen, Hermitian include("relations/topology.jl") end diff --git a/src/relations/quantity_links.jl b/src/relations/quantity_links.jl index 2108ead..3534cb8 100644 --- a/src/relations/quantity_links.jl +++ b/src/relations/quantity_links.jl @@ -147,6 +147,11 @@ quantities(::HolevoMixingBound) = (VonNeumannEntropy,) quantities(::RenyiMonotonicity) = (RenyiEntropy,) quantities(::RelativeEntropyNonNegativity) = (RelativeEntropy,) +# The three self-averaging relations name no quantity: `R_X = Var(X)/[X]²` leaves `X` +# generic, and a width is not a mean, so neither `Typical` nor `DisorderAveraged` +# names it and `CriticalTemperature` would name the thing `δT_c` is the spread of. +# Same abstention as the two below, for the same reason. + # ── Disorder statistics ── # Both are fully symbol-keyed: `X_typ`/`X_avg` and `F_quenched`/`F_annealed` are # REDUCTIONS over an ensemble, and no single quantity names a reduction, so there diff --git a/src/relations/scaling.jl b/src/relations/scaling.jl index a06f42d..5cf7094 100644 --- a/src/relations/scaling.jl +++ b/src/relations/scaling.jl @@ -702,6 +702,72 @@ autocorrelation `G(t) ∼ exp(−A|ln t|^d)` of Eq. (A.34) (= Eq. (9.7), §9.1.3 @relation :scaling OrderedGriffithsEnergyScale(dloglogΩ_dloglogL, d::SpatialDimension) = dloglogΩ_dloglogL * d - 1 +""" + StrongSelfAveraging <: AbstractRelation + +`R_X ∼ (L/ξ)^{-d}` for `L ≫ ξ`, so `d ln R_X/d ln(L/ξ) = -d`, where +`R_X = Var(X)/[X]²` over an ensemble of samples (Aharony & Harris, +[AharonyHarris1996](@cite)). + +Off criticality only, and the abscissa is `L/ξ` rather than `L`, which is also +what keeps this slope a different variable from +[`CriticalSelfAveraging`](@ref)'s: one number cannot be both, and a graph that +shared the name would read an off-critical law off a critical measurement. + +Variables: `dlogR_dlogLξ` (caller-computed), `d`. +""" +@relation :scaling StrongSelfAveraging(dlogR_dlogLξ, d::SpatialDimension) = dlogR_dlogLξ + d + +""" + CriticalSelfAveraging <: AbstractRelation + +`R_X ∼ L^{α/ν}` at criticality when the randomness is IRRELEVANT, so +`d ln R_X/d ln L = α/ν` ([AharonyHarris1996](@cite)). + +The exponents are the PURE system's, so they are `α_pure` and `ν_pure` and stay +untyped: [`SpecificHeatExponent`](@ref) elsewhere in the registry means the system +under study, and at a random fixed point that is a different number. Wiseman and +Domany conjectured this form with the random fixed point's exponents; +[AharonyHarris1996](@cite) and the simulations in [WisemanDomany1998](@cite) both +contradict it, the width going to a constant there instead. + +At `α = 0`, the marginal case this literature is largely about, the residual does +not depend on `ν` and a passing check says nothing about it. + +Variables: `dlogR_dlogL` (caller-computed), `α_pure`, `ν_pure`. +""" +@relation :scaling CriticalSelfAveraging(dlogR_dlogL, α_pure, ν_pure) = + dlogR_dlogL - α_pure / ν_pure + +""" + PseudocriticalWidthScaling <: AbstractRelation + +`δT_c(L) ∼ L^{-1/ν}`, so `d ln δT_c/d ln L = -1/ν`, where `δT_c` is the width of +the sample-to-sample distribution of pseudocritical temperatures +([WisemanDomany1998](@cite), measured directly). + +Not `L^{-d/2}`, the central-limit answer, which holds only where the Harris +criterion does. The two are close and the measurement has to be good enough to +tell them apart: the site-dilute Ising model in `d = 3` gives `1.449(8)` against +`d/2 = 1.5`, six of its own errors away, agreeing with that model's separately +fitted `1/ν = 1.467(5)`. + +Variables: `dlogδTc_dlogL` (caller-computed), `ν`. +""" +@relation :scaling PseudocriticalWidthScaling(dlogδTc_dlogL, ν::CorrelationLengthExponent) = + dlogδTc_dlogL + 1 / ν + +# `1/ν` is not affine in `ν`, so the generic three-probe inverter refuses it. That +# inverter also refuses a non-finite probe; this one has to refuse its own pole, or +# a flat slope returns an infinity whose SIGN comes from the caller's zero. +function _solve(::PseudocriticalWidthScaling, ::Val{:ν}; dlogδTc_dlogL, _extra...) + iszero(dlogδTc_dlogL) && error( + "solve: PseudocriticalWidthScaling has no ν at dlogδTc_dlogL = 0. A width " * + "that does not shift with L does not identify a correlation-length exponent.", + ) + return -1 / dlogδTc_dlogL +end + """ WeinribHalperinExponent <: AbstractRelation diff --git a/test/relations/test_interface.jl b/test/relations/test_interface.jl index edb2a90..9b3f041 100644 --- a/test/relations/test_interface.jl +++ b/test/relations/test_interface.jl @@ -18,9 +18,9 @@ AbstractQAtlas.domain(::_NonAffineDemo) = :test_only # domain that has no line here shows up as a mismatch in this number alone. # Universal-only: the model-specific relations (spin glass, Drude mobility, # single-band Hall) live in QAtlas. - @test length(rels) == 170 + @test length(rels) == 173 @test allunique(typeof.(rels)) - @test length(all_relations(; domain=:scaling)) == 30 # +ActivatedDynamicalScaling, ActivatedFiniteSizeScaling, +14 Appendix-A scaling types, +WeinribHalperinExponent, +QuantumHyperscaling; +TypicalCorrelationLength, GriffithsExponentDivergence, GriffithsSusceptibility, GriffithsSpecificHeat, ActivatedMomentGrowth; +CriticalCorrelationDecay, ActivatedCriticalCorrelation (#158) + @test length(all_relations(; domain=:scaling)) == 33 # +ActivatedDynamicalScaling, ActivatedFiniteSizeScaling, +14 Appendix-A scaling types, +WeinribHalperinExponent, +QuantumHyperscaling; +TypicalCorrelationLength, GriffithsExponentDivergence, GriffithsSusceptibility, GriffithsSpecificHeat, ActivatedMomentGrowth; +CriticalCorrelationDecay, ActivatedCriticalCorrelation (#158); +3 self-averaging @test length(all_relations(; domain=:thermodynamic)) == 15 @test length(all_relations(; domain=:fundamental)) == 9 # +GrandPotentialLegendre, ParticleNumberResponse (grand-canonical); +ElectricCurrentResponse (j = −∂H/∂A) @test length(all_relations(; domain=:topology)) == 3 diff --git a/test/relations/test_scaling.jl b/test/relations/test_scaling.jl index e9eb4ce..053fab1 100644 --- a/test/relations/test_scaling.jl +++ b/test/relations/test_scaling.jl @@ -6,7 +6,7 @@ # pins the no-float-promotion contract. using AbstractQAtlas -using AbstractQAtlas: residual, check, solve +using AbstractQAtlas: residual, check, solve, derive using LinearAlgebra const ISING2D = (α=0//1, β=1//8, γ=7//4, δ=15//1, ν=1//1, η=1//4) @@ -604,7 +604,7 @@ end rs = relations_constraining(SpatialDimension()) # Every relation that takes a d, named. Listing a subset leaves the rest # resting on the soft coverage ratio, which cannot see one missing entry. - @test length(rs) == 13 + @test length(rs) == 14 for r in ( Josephson(), QuantumHyperscaling(), @@ -619,6 +619,7 @@ end FixedPointDisorderStrength(), ConventionalFieldSusceptibility(), ConventionalFieldSpecificHeat(), + StrongSelfAveraging(), ) @test r in rs end @@ -684,3 +685,63 @@ end @test CriticalCorrelationDecay() in relations_constraining(DisorderAveraged{ConnectedSpinCorrelation}) end + +@testset "how the sample-to-sample width scales says which fixed point it is" begin + # `R_X = Var(X)/[X]²` over an ensemble of samples, which is what a disorder + # calculation already produces per size. + d, α, ν = 3, -0.1, 0.7 + @test solve(StrongSelfAveraging(), Val(:d); dlogR_dlogLξ=(-d)) ≈ d + @test solve(CriticalSelfAveraging(), Val(:α_pure); dlogR_dlogL=α / ν, ν_pure=ν) ≈ α + @test check(StrongSelfAveraging(); dlogR_dlogLξ=(-d), d=d, atol=1e-12) + @test check(CriticalSelfAveraging(); dlogR_dlogL=α / ν, α_pure=α, ν_pure=ν, atol=1e-12) + @test !check(StrongSelfAveraging(); dlogR_dlogLξ=(+d), d=d, atol=1e-9) # sign + @test !check( + CriticalSelfAveraging(); dlogR_dlogL=(-α / ν), α_pure=α, ν_pure=ν, atol=1e-9 + ) + + # Relevant randomness means no decay at all, so both decay laws are refused. + @test !check(StrongSelfAveraging(); dlogR_dlogLξ=0.0, d=d, atol=1e-6) + @test !check(CriticalSelfAveraging(); dlogR_dlogL=0.0, α_pure=α, ν_pure=ν, atol=1e-6) + + # The two abscissas are different variables and must stay so. Sharing the name let + # an off-critical law be read off a critical slope and, through `d`, put a wrong ν + # on the far side of Josephson with no error. + @test isdisjoint(variables(StrongSelfAveraging()), variables(CriticalSelfAveraging())) + @test_throws "not reachable" derive(:ν; dlogR_dlogL=α / ν, α=α) + + # At α = 0 the residual does not depend on ν, so a pass says nothing about it. + # Documented rather than refused: α = 0 is the marginal case, not a bad input. + @test all( + x -> check(CriticalSelfAveraging(); dlogR_dlogL=0.0, α_pure=0.0, ν_pure=x, atol=0), + (0.001, 0.63, 999.0), + ) + + # `δT_c ∼ L^{-1/ν}`, not `L^{-d/2}`. The site-dilute Ising model in d = 3 measures + # 1.449(8), which is six of its own errors from d/2 = 1.5, so the discriminator + # discriminates. Asserted in units of that error, the two being 3.4% apart. + ρ, σρ = 1.449, 0.008 + @test abs(ρ - d / 2) / σρ > 5 + # Round-tripped through `check` rather than compared to the hand-written inverse, + # which would be that formula against itself. + ν_solved = solve(PseudocriticalWidthScaling(), Val(:ν); dlogδTc_dlogL=(-ρ)) + @test check(PseudocriticalWidthScaling(); dlogδTc_dlogL=(-ρ), ν=ν_solved, atol=1e-12) + # Not a test of this package: a guard on the two numbers the docstring quotes, so + # editing one without the other is caught. They are separate measurement channels + # on the same model and agree at 1.9 of their combined error. + @test abs(ρ - 1.467) < 2.5 * sqrt(σρ^2 + 0.005^2) + @test !check( + PseudocriticalWidthScaling(); dlogδTc_dlogL=(-d / 2), ν=ν_solved, atol=1e-3 + ) + + # A flat width identifies no exponent, so the specialized inverse refuses its own + # pole rather than returning an infinity signed by the caller's zero. + @test_throws "no ν at" solve(PseudocriticalWidthScaling(), Val(:ν); dlogδTc_dlogL=0.0) + @test_throws "no ν at" solve(PseudocriticalWidthScaling(), Val(:ν); dlogδTc_dlogL=-0.0) + + @test variable_types(StrongSelfAveraging()) == (SpatialDimension,) + @test variable_types(PseudocriticalWidthScaling()) == (CorrelationLengthExponent,) + # Untyped on purpose: these are the PURE system's exponents, and the registry's + # exponent types mean the system under study. `WeinribHalperinExponent` leaves + # `ν_dis` bare for the same reason. + @test isempty(variable_types(CriticalSelfAveraging())) +end