eaebec39创建于 2024年10月24日历史提交
package scientific.stats.continuous

import std.math.*
import std.unittest.*
import std.unittest.testmacro.*

import scientific.numbers.*
import scientific.stats.random.*

/*
 * Log of Probability density function
 */
public func genextremeLogPDF(x: Float64, k: Float64, loc!: Float64 = 0.0, scale!: Float64 = 1.0): Float64 {
    let y = (x - loc) / scale

    if (k > 0.0) {
        if (x > 1.0) {
            throw IllegalArgumentException("genextremeLogPDF: input value out of bound.")
        }
    } else if (k < 0.0) {
        if (x < 1.0 / k) {
            throw IllegalArgumentException("genextremeLogPDF: input value out of bound.")
        }
    } else {
        return gumbel_rLogPDF(x, loc: loc, scale: scale)
    }

    let temp = 1.0 - k * y
    return -pow(temp, 1.0/k) + (1.0/k - 1.0) * log(temp) - log(scale)
}

/*
 * Probability density function
 */
public func genextremePDF(x: Float64, k: Float64, loc!: Float64 = 0.0, scale!: Float64 = 1.0): Float64 {
    let y = (x - loc) / scale

    if (k > 0.0) {
        if (x > 1.0) {
            throw IllegalArgumentException("genextremePDF: input value out of bound.")
        }
    } else if (k < 0.0) {
        if (x < 1.0 / k) {
            throw IllegalArgumentException("genextremePDF: input value out of bound.")
        }
    } else {
        return gumbel_rPDF(x, loc: loc, scale: scale)
    }

    return exp(genextremeLogPDF(x, k, loc: loc, scale: scale))

}

/*
 * Cumulative probability density function
 */
public func genextremeCDF(x: Float64, k: Float64, loc!: Float64 = 0.0, scale!: Float64 = 1.0): Float64 {
    let y = (x - loc) / scale

    if (k > 0.0) {
        if (x > 1.0) {
            throw IllegalArgumentException("genextremeCDF: input value out of bound.")
        }
    } else if (k < 0.0) {
        if (x < 1.0 / k) {
            throw IllegalArgumentException("genextremeCDF: input value out of bound.")
        }
    } else {
        return gumbel_rCDF(x, loc: loc, scale: scale)
    }

    return exp(genextremeLogCDF(x, k ,loc: loc, scale: scale))
}

/*
 * Log of Cumulative probability density function
 */
public func genextremeLogCDF(x: Float64, k: Float64, loc!: Float64 = 0.0, scale!: Float64 = 1.0): Float64 {
    let y = (x - loc) / scale

    if (k > 0.0) {
        if (x > 1.0) {
            throw IllegalArgumentException("genextremeLogCDF: input value out of bound.")
        }
    } else if (k < 0.0) {
        if (x < 1.0 / k) {
            throw IllegalArgumentException("genextremeLogCDF: input value out of bound.")
        }
    } else {
        return gumbel_rLogCDF(x, loc: loc, scale: scale)
    }

    let temp = log(1.0 - k * y) / k
    return -exp(temp)
}


/*
 * ppf
 */
public func genextremePPF(q: Float64, k: Float64, loc!: Float64 = 0.0, scale!: Float64 = 1.0): Float64 {
    if (q <= 0.0 || q >= 1.0) {
        throw IllegalArgumentException("genextremePPF: quantile out of bound.")
    }

    if (k == 0.0) {
        return gumbel_rPPF(q, loc: loc, scale: scale)
    }

    let t = -log(-log(q))
    let res = (1.0 - exp(-k * t)) / k
    return res * scale + loc
}


@Test
public class TestGenextreme {
    @TestCase
    func testGenextreme(): Unit {
        @Assert(approxEqual(genextremeLogPDF(0.0, 2.0, loc: 1.0, scale: 2.0), -2.453934333213013,  atol:1e-13))
        @Assert(approxEqual(genextremeLogCDF(0.0, 2.0, loc: 1.0, scale: 2.0), -1.414213562373095,  atol:1e-13)) 
        @Assert(approxEqual(genextremePPF(0.2, 2.0, loc: 1.0, scale: 2.0),    -0.5902903939802346, atol:1e-13)) 
    }
}