parquet_debug_gamma_path Subroutine

public pure subroutine parquet_debug_gamma_path(rng, shape, r, path, squeeze_ok)

Runs the Philox block function directly, on raw counter and key words. Test-only.

This exists so the LIBRARY'S OWN kernel can be known-answer-checked against all three published Random123 vectors, rather than only the one the public API can reach. The mapping puts the 0-based block index in counter words 0 and 1, and the block index comes from an integer(int64) draw — so it cannot exceed roughly 2**62, while KAT 2 needs 0xffffffff there and KAT 3 about 9.6e18. Both are unreachable through pf_random_at and friends by construction, for any seed, stream or draw. Note the key is not restricted in the same way: it is derived from the seed by a bijection, so every 64-bit key is reachable; it is only the counter that is bounded.

Without this, KAT 2 and KAT 3 could only be asserted against test_random_reference.f90, and the library kernel was tied to them transitively — directly known-answer-checked once and indirectly twice, through a reference that is itself checked three times. That chain is sound but it is a chain, and it leaves the one arithmetic that actually ships less directly evidenced than the reference written to check it. This hook makes all three direct.

Public only because it has to be, exactly as parquet_debug_random_uses_int128 is: this module reaches no bind(C) surface, so the C++-side debug-hook convention is unavailable to it. It is excluded from README's API overview, no library code calls it, and it is a pure observation with no setter — it cannot change what any draw returns.

Arguments are the module's own coordinates, not Philox's four counter words: key splits into key words 0 and 1 (low half first), stream into counter words 2 and 3, and index into counter words 0 and 1. So KAT 2 — every counter and key word 0xffffffff — is the call parquet_debug_random_block(-1_int64, -1_int64, -1_int64, ...). Reports which branch a coordinate-addressed normal draw took, and what it cost. Test-only.

Public only because it has to be: this module reaches no bind(C) surface, so the C++-side debug-hook convention the rest of the library uses is unavailable to it (see CLAUDE.md, "A Fortran-side debug hook has to be PUBLIC, so prefer a C++ one"). It is excluded from README.md's API overview and no library code calls it.

It is an OBSERVATION hook, not an override, which is why it needs no process-global state at all: it re-runs the same construction the ordinary call runs and reports what happened. (It is not pure only because it can be asked for the polar form, which routes through exp_key.) A test asserts that all three Ziggurat branches occur over a fixture and the reported value equals the ordinary call's -- without which a rejection branch could be compiled and never entered while every test passed.

path is 1 for the immediate rectangle acceptance, 2 for the wedge test and 3 for the tail; the polar form has one acceptance branch and always reports 1, its rejections showing up as pairs > 2. pairs counts 32-bit word PAIRS, so the word cost is twice it. Reports which branch a %gamma draw took. Test-only; see parquet_debug_normal_path for why a Fortran-side hook has to be public here.

It advances rng exactly as %gamma does and returns the same value, so a test can walk a stream through it and census the branches. path is 1 for a squeeze acceptance and 2 for the full logarithmic test, plus 2 more when the shape < 1 boost was applied -- so all four combinations are distinguishable.

Arguments

Type IntentOptional Attributes Name
type(pf_random_stream), intent(inout) :: rng

the stream to advance, as %gamma would

real(kind=real64), intent(in) :: shape

the shape parameter; must be > 0

real(kind=real64), intent(out) :: r

the draw, equal to %gamma's

integer(kind=int32), intent(out) :: path

1/2 squeeze/log; +2 when boosted

logical, intent(out), optional :: squeeze_ok

.false. iff the squeeze accepted a candidate the full test would reject


Source Code

    pure subroutine parquet_debug_gamma_path(rng, shape, r, path, squeeze_ok)
        type(pf_random_stream), intent(inout) :: rng    !! the stream to advance, as `%gamma` would
        real(real64), intent(in) :: shape               !! the shape parameter; must be > 0
        real(real64), intent(out) :: r                  !! the draw, equal to `%gamma`'s
        integer(int32), intent(out) :: path             !! 1/2 squeeze/log; +2 when boosted
        logical, intent(out), optional :: squeeze_ok    !! `.false.` iff the squeeze accepted a
                                                        !! candidate the full test would reject
        call gamma_draw(rng, shape, r, path, squeeze_ok)
    end subroutine parquet_debug_gamma_path