@@ -347,143 +347,211 @@ end
347347# ### Validation tests
348348# ###
349349
350- @testset " Validation testing (Gaussian)" begin
351- target = HighDimGaussian (2 )
352- rng = MersenneTwister (125 )
353- λ = 1e-2
350+ @testset " Validation testing" begin
351+ # 1D Wasserstein-1 distance
352+ function w1 (a:: AbstractVector , b:: AbstractVector )
353+ sa = sort (a)
354+ sb = sort (b)
355+ return mean (abs .(sa .- sb))
356+ end
354357
355- initial_θ = rand (rng, dim (target))
358+ @testset " Validation testing (Gaussian) " begin
356359
357- ℓπ = MCMCLogDensityProblems. gen_logpdf (target)
358- ∂ℓπ∂θ = MCMCLogDensityProblems. gen_logpdf_grad (target, initial_θ)
360+ # 1D normal Wasserstein-1 distance tolerance estimator
361+ function w1_tol_normal_1d (;
362+ n:: Int , reps:: Int = 200 , q:: Float64 = 0.999 , rng= Random. default_rng ()
363+ )
364+ poolN = max (50_000 , 50 n)
365+ pool = randn (rng, poolN)
366+
367+ vals = Vector {Float64} (undef, reps)
368+ for i in 1 : reps
369+ a = pool[rand (rng, 1 : poolN, n)]
370+ b = pool[rand (rng, 1 : poolN, n)]
371+ vals[i] = w1 (a, b)
372+ end
373+ sort! (vals)
374+ return vals[clamp (ceil (Int, q * reps), 1 , reps)]
375+ end
359376
360- _, _, G, ∂G∂θ = prepare_sample (ℓπ, initial_θ, λ)
377+ target = HighDimGaussian (2 )
378+ rng = MersenneTwister (125 )
379+ λ = 1e-2
361380
362- D = dim (target)
381+ initial_θ = rand (rng, dim (target) )
363382
364- n_samples = 100
365- n_adapts = 50
383+ ℓπ = MCMCLogDensityProblems . gen_logpdf (target)
384+ ∂ℓπ∂θ = MCMCLogDensityProblems . gen_logpdf_grad (target, initial_θ)
366385
367- mean_tol = 3 / sqrt (n_samples)
368- var_tol = 1.5 * sqrt (2 / (n_samples - 1 ))
386+ _, _, G, ∂G∂θ = prepare_sample (ℓπ, initial_θ, λ)
369387
370- @testset " RiemannianMetric (PDMat-style)" begin
371- metric = RiemannianMetric ((D,), G, ∂G∂θ)
372- kinetic = GaussianKinetic ()
373- hamiltonian = Hamiltonian (metric, kinetic, ℓπ, ∂ℓπ∂θ)
388+ D = dim (target)
374389
375- initial_ϵ = 0.01
376- integrator = GeneralizedLeapfrog (initial_ϵ, 15 )
377- kernel = HMCKernel (Trajectory {MultinomialTS} (integrator, GeneralisedNoUTurn ()))
378-
379- acceptance_rate = 0.9
380- adaptor = StepSizeAdaptor (acceptance_rate, integrator)
381-
382- samples, stats = sample (
383- rng,
384- hamiltonian,
385- kernel,
386- initial_θ,
387- n_samples,
388- adaptor,
389- n_adapts;
390- progress= false ,
391- )
392- @test mean (samples) ≈ zeros (D) atol = mean_tol
393- @test Statistics. var (samples) ≈ ones (D) atol = var_tol
390+ n_samples = 100
391+ n_adapts = 50
392+
393+ tol_w1 = w1_tol_normal_1d (; n= n_samples, rng= rng)
394+
395+ # Samples are RHMC so we relax the tolerance
396+ tol_w1 *= 2.0
397+
398+ x_true = randn (rng, n_samples)
399+ y_true = randn (rng, n_samples)
400+
401+ @testset " RiemannianMetric (PDMat-style)" begin
402+ metric = RiemannianMetric ((D,), G, ∂G∂θ)
403+ kinetic = GaussianKinetic ()
404+ hamiltonian = Hamiltonian (metric, kinetic, ℓπ, ∂ℓπ∂θ)
405+
406+ initial_ϵ = 0.01
407+ integrator = GeneralizedLeapfrog (initial_ϵ, 15 )
408+ kernel = HMCKernel (Trajectory {MultinomialTS} (integrator, GeneralisedNoUTurn ()))
409+
410+ acceptance_rate = 0.9
411+ adaptor = StepSizeAdaptor (acceptance_rate, integrator)
412+
413+ samples, stats = sample (
414+ rng,
415+ hamiltonian,
416+ kernel,
417+ initial_θ,
418+ n_samples,
419+ adaptor,
420+ n_adapts;
421+ progress= false ,
422+ )
423+ θ = reduce (vcat, (permutedims (s) for s in samples))
424+ # 1st marginal
425+ @test w1 (θ[:, 1 ], x_true) < tol_w1
426+ # 2nd marginal
427+ @test w1 (θ[:, 2 ], y_true) < tol_w1
428+ end
429+
430+ @testset " SoftAbsRiemannianMetric" begin
431+ # We do not need SoftAbs for Gaussian target, so using small α
432+ metric = SoftAbsRiemannianMetric ((D,), G, ∂G∂θ, 1.0 )
433+ kinetic = GaussianKinetic ()
434+ hamiltonian = Hamiltonian (metric, kinetic, ℓπ, ∂ℓπ∂θ)
435+
436+ initial_ϵ = 0.01
437+ integrator = GeneralizedLeapfrog (initial_ϵ, 15 )
438+ kernel = HMCKernel (Trajectory {MultinomialTS} (integrator, GeneralisedNoUTurn ()))
439+
440+ acceptance_rate = 0.9
441+ adaptor = StepSizeAdaptor (acceptance_rate, integrator)
442+
443+ samples, stats = sample (
444+ rng,
445+ hamiltonian,
446+ kernel,
447+ initial_θ,
448+ n_samples,
449+ adaptor,
450+ n_adapts;
451+ progress= false ,
452+ )
453+
454+ θ = reduce (vcat, (permutedims (s) for s in samples))
455+ # 1st marginal
456+ @test w1 (θ[:, 1 ], x_true) < tol_w1
457+ # 2nd marginal
458+ @test w1 (θ[:, 2 ], y_true) < tol_w1
459+ end
394460 end
395461
396- @testset " SoftAbsRiemannianMetric" begin
397- # We do not need SoftAbs for Gaussian target, so using small α
398- metric = SoftAbsRiemannianMetric ((D,), G, ∂G∂θ, 1.0 )
399- kinetic = GaussianKinetic ()
400- hamiltonian = Hamiltonian (metric, kinetic, ℓπ, ∂ℓπ∂θ)
462+ @testset " Validation testing (Funnel)" begin
463+
464+ # Funnel i.i.d. sampler
465+ # θ layout: [v, x1]
466+ function funnel_iid (rng:: AbstractRNG , n:: Int )
467+ v = 3.0 .* randn (rng, n)
468+ X = Matrix {Float64} (undef, n, 1 )
469+ for i in 1 : n
470+ s = exp (v[i] / 2 )
471+ @inbounds X[i, :] .= s .* randn (rng, 1 )
472+ end
473+ return v, X
474+ end
401475
402- initial_ϵ = 0.01
403- integrator = GeneralizedLeapfrog (initial_ϵ, 15 )
404- kernel = HMCKernel (Trajectory {MultinomialTS} (integrator, GeneralisedNoUTurn ()))
405-
406- acceptance_rate = 0.9
407- adaptor = StepSizeAdaptor (acceptance_rate, integrator)
408-
409- samples, stats = sample (
410- rng,
411- hamiltonian,
412- kernel,
413- initial_θ,
414- n_samples,
415- adaptor,
416- n_adapts;
417- progress= false ,
476+ # 1D Wasserstein-1 distance tolerances for Funnel marginals
477+ function funnel_w1_tols (;
478+ n:: Int ,
479+ reps:: Int = 200 ,
480+ q:: Float64 = 0.999 ,
481+ inflate:: Float64 = 2.0 ,
482+ rng:: AbstractRNG = Random. default_rng (),
418483 )
419- @test mean (samples) ≈ zeros (D) atol = mean_tol
420- @test Statistics. var (samples) ≈ ones (D) atol = var_tol
421- end
422- end
484+ vals_v = Vector {Float64} (undef, reps)
485+ vals_x1 = Vector {Float64} (undef, reps)
423486
424- @testset " Validation testing (Funnel)" begin
487+ for i in 1 : reps
488+ vA, XA = funnel_iid (rng, n)
489+ vB, XB = funnel_iid (rng, n)
425490
426- # 1D Wasserstein-1 distance
427- function w1 (a:: AbstractVector , b:: AbstractVector )
428- sa = sort (a)
429- sb = sort (b)
430- return mean (abs .(sa .- sb))
431- end
491+ x1A = XA[:, 1 ]
492+ x1B = XB[:, 1 ]
432493
433- target = Funnel ( )
434- rng = MersenneTwister ( 234 )
435- λ = 1e-2
494+ vals_v[i] = w1 (vA, vB )
495+ vals_x1[i] = w1 (x1A, x1B )
496+ end
436497
437- initial_θ = rand (rng, dim (target))
498+ sort! (vals_v)
499+ sort! (vals_x1)
500+ idx = clamp (ceil (Int, q * reps), 1 , reps)
438501
439- ℓπ = MCMCLogDensityProblems . gen_logpdf (target )
440- ∂ℓπ∂θ = MCMCLogDensityProblems . gen_logpdf_grad (target, initial_θ)
502+ return (tol_v = inflate * vals_v[idx], tol_x1 = inflate * vals_x1[idx] )
503+ end
441504
442- _, _, G, ∂G∂θ = prepare_sample (ℓπ, initial_θ, λ)
505+ target = Funnel ()
506+ rng = MersenneTwister (234 )
507+ λ = 1e-2
443508
444- D = dim (target)
509+ initial_θ = rand (rng, dim (target) )
445510
446- n_samples = 1000
447- n_adapts = 500
511+ ℓπ = MCMCLogDensityProblems . gen_logpdf (target)
512+ ∂ℓπ∂θ = MCMCLogDensityProblems . gen_logpdf_grad (target, initial_θ)
448513
449- # True samples
450- v_true = 3 .* randn (rng, n_samples)
451- X_true = Matrix {Float64} (undef, n_samples, 1 )
452- for n in 1 : n_samples
453- s = exp (v_true[n] / 2 )
454- @inbounds X_true[n, :] .= s .* randn (rng, 1 )
455- end
514+ _, _, G, ∂G∂θ = prepare_sample (ℓπ, initial_θ, λ)
456515
457- tol_1 = 10 / sqrt (n_samples)
458- tol_2 = 30 / sqrt (n_samples)
516+ D = dim (target)
459517
460- @testset " SoftAbsRiemannianMetric" begin
461- metric = SoftAbsRiemannianMetric ((D,), G, ∂G∂θ, 20.0 )
462- kinetic = GaussianKinetic ()
463- hamiltonian = Hamiltonian (metric, kinetic, ℓπ, ∂ℓπ∂θ)
518+ n_samples = 1000
519+ n_adapts = 500
464520
465- initial_ϵ = 0.01
466- integrator = GeneralizedLeapfrog (initial_ϵ, 15 )
467- kernel = HMCKernel (Trajectory {MultinomialTS} (integrator, GeneralisedNoUTurn ()))
468-
469- acceptance_rate = 0.9
470- adaptor = StepSizeAdaptor (acceptance_rate, integrator)
471-
472- samples, stats = sample (
473- rng,
474- hamiltonian,
475- kernel,
476- initial_θ,
477- n_samples,
478- adaptor,
479- n_adapts;
480- progress= false ,
481- )
521+ # True samples
522+ v_true, X_true = funnel_iid (rng, n_samples)
523+
524+ # Wasserstein-1 distance tolerances
525+ tols = funnel_w1_tols (; n= n_samples, rng= rng)
526+
527+ @testset " SoftAbsRiemannianMetric" begin
528+ metric = SoftAbsRiemannianMetric ((D,), G, ∂G∂θ, 20.0 )
529+ kinetic = GaussianKinetic ()
530+ hamiltonian = Hamiltonian (metric, kinetic, ℓπ, ∂ℓπ∂θ)
482531
483- θ = reduce (vcat, (permutedims (s) for s in samples))
484- # 1st marginal
485- @test w1 (θ[:, 1 ], v_true) < tol_1
486- # 2nd marginal
487- @test w1 (θ[:, 2 ], X_true[:, 1 ]) < tol_2
532+ initial_ϵ = 0.01
533+ integrator = GeneralizedLeapfrog (initial_ϵ, 15 )
534+ kernel = HMCKernel (Trajectory {MultinomialTS} (integrator, GeneralisedNoUTurn ()))
535+
536+ acceptance_rate = 0.9
537+ adaptor = StepSizeAdaptor (acceptance_rate, integrator)
538+
539+ samples, stats = sample (
540+ rng,
541+ hamiltonian,
542+ kernel,
543+ initial_θ,
544+ n_samples,
545+ adaptor,
546+ n_adapts;
547+ progress= false ,
548+ )
549+
550+ θ = reduce (vcat, (permutedims (s) for s in samples))
551+ # 1st marginal
552+ @test w1 (θ[:, 1 ], v_true) < tols. tol_v
553+ # 2nd marginal
554+ @test w1 (θ[:, 2 ], X_true[:, 1 ]) < tols. tol_x1
555+ end
488556 end
489557end
0 commit comments