Esempio n. 1
0
float normalized_diffusion_pdf(
    const float     r,
    const float     l,
    const float     s)
{
    return normalized_diffusion_pdf(r, l / s);
}
Esempio n. 2
0
double normalized_diffusion_pdf(
    const double    r,
    const double    l,
    const double    s)
{
    return normalized_diffusion_pdf(r, l / s);
}
Esempio n. 3
0
double normalized_diffusion_sample(
    const double    u,
    const double    l,
    const double    s,
    const double    eps,
    const size_t    max_iterations)
{
    assert(u >= 0.0);
    assert(u < 1.0);

    const double d = l / s;

    // Handle the case where u is greater than the value we consider 1 in our CDF.
    if (u >= nd_cdf_rmax)
        return NdCdfTableRmax * d;

    // Use the CDF to find an initial interval for the root of cdf(r, 1) - u = 0.
    const size_t i = sample_cdf(nd_cdf_table, nd_cdf_table + NdCdfTableSize, u);
    assert(i > 0);
    assert(nd_cdf_table[i - 1] <= u);
    assert(nd_cdf_table[i] > u);

    // Transform the cdf(r, 1) interval to cdf(r, d) using the fact that cdf(r, d) == cdf(r/d, 1).
    double rmin = fit<size_t, double>(i - 1, 0, NdCdfTableSize - 1, 0.0, NdCdfTableRmax) * d;
    double rmax = fit<size_t, double>(i,     0, NdCdfTableSize - 1, 0.0, NdCdfTableRmax) * d;
    assert(normalized_diffusion_cdf(rmin, d) <= u);
    assert(normalized_diffusion_cdf(rmax, d) > u);

    double r = (rmax + rmin) * 0.5;

    // Refine the root.
    for (size_t i = 0; i < max_iterations; ++i)
    {
        // Use bisection if we go out of bounds.
        if (r < rmin || r > rmax)
            r = (rmax + rmin) * 0.5;

        const double f = normalized_diffusion_cdf(r, d) - u;

        // Convergence test.
        if (abs(f) <= eps)
            break;

        // Update bounds.
        f < 0.0 ? rmin = r : rmax = r;

        // Newton step.
        const double df = normalized_diffusion_pdf(r, d);
        r -= f / df;
    }

    return r;
}