"""
File    quantile.py
Desc    computes sample quantiles
Author  Ernesto P. Adorio, PhD.
                UPDEPP (U.P. at Clarkfield)
Version 0.0.1 August 7. 2009
"""
from __future__ import print_function

from math import floor
from math import modf


def quantile(x, q, qtype=7, issorted=False):
    """
    Args:
        x - input data
        q - quantile
        qtype - algorithm
        issorted- True if x already sorted.

    Compute quantiles from input array x given q.For median,
    specify q=0.5.

    References:
        http://reference.wolfram.com/mathematica/ref/Quantile.html
        http://wiki.r-project.org/rwiki/doku.php?id=rdoc:stats:quantile

    Author:
        Ernesto P.Adorio Ph.D.
        UP Extension Program in Pampanga, Clark Field.
    """

    if not issorted:
        y = sorted(x)
    else:
        y = x
        if not (1 <= qtype <= 9):
            return None  # error!

    # Parameters for the Hyndman and Fan algorithm
    abcd = [
        # inverse empirical distrib.function., R type 1
        (0,   0, 1, 0),
        # similar to type 1, averaged, R type 2
        (0.5, 0, 1, 0),
        # nearest order statistic,(SAS) R type 3
        (0.5, 0, 0, 0),
        # California linear interpolation, R type 4
        (0,   0, 0, 1),
        # hydrologists method, R type 5
        (0.5, 0, 0, 1),
        # mean-based estimate(Weibull method), (SPSS, Minitab), type 6
        (0,   1, 0, 1),
        # mode-based method,(S, S-Plus), R type 7
        (1,  -1, 0, 1),
        # median-unbiased ,  R type 8
        (1.0 / 3, 1.0 / 3, 0, 1),
        # normal-unbiased, R type 9.
        (3 / 8.0, 0.25, 0, 1)
    ]

    a, b, c, d = abcd[qtype - 1]
    n = len(x)
    g, j = modf(a + (n + b) * q - 1)
    if j < 0:
        return y[0]
    elif j >= n:
        # oct. 8, 2010 y[n]???!! uncaught  off by 1 error!!!
        return y[n - 1]

    j = int(floor(j))
    if g == 0:
        return y[j]
    else:
        return y[j] + (y[j + 1] - y[j]) * (c + d * g)


def Test():
    x = [11.4, 17.3, 21.3, 25.9, 40.1, 50.5, 60.0, 70.0, 75]

    for qtype in range(1, 10):
        print(qtype, quantile(x, 0.35, qtype))


if __name__ == "__main__":
    Test()
