def interpret_complete_cdf( cdfs_p: List[Union[list, np.ndarray]], cdfs_v: List[Union[list, np.ndarray]], distribution: str = None, ) -> Union[List[Union[list, np.ndarray]], Tuple[List[Union[list, np.ndarray]], List[Union[list, np.ndarray]]], ot.DistributionImplementation, ]: """Interpret the given points on the cumulative distribution function to represent a complete CDF. The default policy is to assume discrete probabilities. If a distribution name is specified, the CDF is returned as an openturns distribution object. Supported openturns distributions are the following: - discrete: all residual probability is attributed to the highest given value - normal or gaussian: derived from the first two point only - uniform: interpolates linearly between points, with residual probability attributed to the min and max values """ # Todo: refactor, currently too many possible types of output if distribution is None: for cdf_p in cdfs_p: cdf_p[-1] = 1 # Last value is the highest return cdfs_p, cdfs_v cdfs = [] if distribution == "discrete": for cdf_p, cdf_v in zip(cdfs_p, cdfs_v): cdf_p[-1] = 1 # Last value is the highest cdfs.append(ot.UserDefined([[v] for v in cdf_v], cp_to_p(cdf_p))) elif distribution in ["normal", "gaussian"]: for cdf_p, cdf_v in zip(cdfs_p, cdfs_v): if len(cdf_v) > 1: x1 = cdf_v[0] x2 = cdf_v[1] y1 = cdf_p[0] y2 = cdf_p[1] mu = (x1 * pyerf.erfinv(1 - 2 * y2) - x2 * pyerf.erfinv(1 - 2 * y1)) / ( pyerf.erfinv(1 - 2 * y2) - pyerf.erfinv(1 - 2 * y1)) sigma = (2**0.5 * x1 - 2**0.5 * x2) / (2 * pyerf.erfinv(1 - 2 * y2) - 2 * pyerf.erfinv(1 - 2 * y1)) cdfs.append(ot.Normal(mu, sigma)) else: cdfs.append(ot.UserDefined([[v] for v in cdf_v], cdf_p)) elif distribution == "uniform": for cdf_p, cdf_v in zip(cdfs_p, cdfs_v): if len(cdf_v) == 1: cdfs.append(ot.UserDefined([cdf_v])) elif len(cdf_v) > 1: coll = ([ot.UserDefined([[cdf_v[0]]])] + [ ot.Uniform(float(cdf_v[i]), float(cdf_v[i + 1])) for i in range(len(cdf_v) - 1) ] + [ot.UserDefined([[cdf_v[-1]]])]) weights = np.append(cp_to_p(cdf_p), 1 - cdf_p[-1]) cdfs.append(ot.Mixture(coll, weights)) else: return NotImplementedError return cdfs
def interpret_complete_cdf( cdfs_p: List[Union[list, np.ndarray]], cdfs_v: List[Union[list, np.ndarray]], distribution: str = None, ) -> Union[List[Union[list, np.ndarray]], Tuple[List[Union[list, np.ndarray]], List[Union[list, np.ndarray]]], ot.DistributionImplementation, ]: """Interpret the given points on the cumulative distribution function to represent a complete CDF. The default policy is to assume discrete probabilities. If a distribution name is specified, the CDF is returned as an openturns distribution object. Supported openturns distributions are the following: - discrete: all residual probability is attributed to the highest given value - normal or gaussian: derived from the first two point only - uniform: derived from the first and last points and extended to range from cp=0 to cp=1 """ # Todo: refactor, currently too many possible types of output if distribution is None: for cdf_p in cdfs_p: cdf_p[-1] = 1 # Last value is the highest return cdfs_p, cdfs_v cdfs = [] if distribution == "discrete": for cdf_p, cdf_v in zip(cdfs_p, cdfs_v): cdf_p[-1] = 1 # Last value is the highest cdfs.append(ot.UserDefined([[v] for v in cdf_v], cdf_p)) elif distribution in ["normal", "gaussian"]: for cdf_p, cdf_v in zip(cdfs_p, cdfs_v): x1 = cdf_v[0] x2 = cdf_v[1] y1 = cdf_p[0] y2 = cdf_p[1] mu = (x1 * pyerf.erfinv(1 - 2 * y2) - x2 * pyerf.erfinv(1 - 2 * y1) ) / (pyerf.erfinv(1 - 2 * y2) - pyerf.erfinv(1 - 2 * y1)) sigma = (2**0.5 * x1 - 2**0.5 * x2) / ( 2 * pyerf.erfinv(1 - 2 * y2) - 2 * pyerf.erfinv(1 - 2 * y1)) cdfs.append(ot.Normal(mu, sigma)) elif distribution is "uniform": for cdf_p, cdf_v in zip(cdfs_p, cdfs_v): x1 = cdf_v[0] x2 = cdf_v[-1] y1 = cdf_p[0] y2 = cdf_p[-1] dydx = (y2 - y1) / (x2 - x1) a = x1 - y1 / dydx b = x2 + (1 - y2) / dydx cdfs.append(ot.Uniform(a, b)) else: return NotImplementedError return cdfs
def _nppf_py(x): return s2 * pyerf.erfinv(2 * x - 1)
def fractile(p): return math.sqrt(2) * pyerf.erfinv(2 * p - 1)