def _median_(self, func, xmin, xmax, *args): ## need to know the integral from ostap.math.integral import Integral iint = Integral(func, xmin, err=False, args=args) half = 2.0 / iint(xmax) ifun = lambda x: iint(x) * half - 1.0 from ostap.math.rootfinder import findroot ## @see https://en.wikipedia.org/wiki/Median#Inequality_relating_means_and_medians try: meanv = Mean.__call__(self, func, *args) sigma = RMS.__call__(self, func, *args) import math xmn = meanv - 2 * sigma ## use 2 instead of 1 xmx = meanv + 2 * sigma ## use 2 instead of 1 # if isinstance(xmin, float): xmn = max(xmn, xmin) if isinstance(xmax, float): xmx = min(xmx, xmax) # result = findroot(ifun, xmn, xmx) except: result = findroot(ifun, xmin, xmax) return result
def __call__(self, func, mode=None, *args): ## ## mode is specified if isinstance ( mode , float ) and \ self.xmin < mode < self.xmax and \ func ( self.xmin ) < func ( mode ) and \ func ( self.xmax ) < func ( mode ) : m0 = mode else: ## mode needs to be calculated m0 = Mode.__call__(self, func, *args) ## function value at the maximum v0 = float(func(m0, *args)) ## half height vheight = 1.0 * v0 * self._hfactor ifun = lambda x, *a: float(func(x, *a)) - vheight from ostap.math.rootfinder import findroot x1 = findroot(ifun, self.xmin, m0, args=args) x2 = findroot(ifun, m0, self.xmax, args=args) return x1, x2
def __call__(self, func, *args): ## additional arguments args = args if args else self.args # ## define integration rules # if hasattr(func, 'integral'): _integral_ = lambda f, low, high: f.integral(low, high, *args) else: from ostap.math.integral import integral _integral_ = lambda f, low, high: integral(f, low, high, *args) # ## xmin/max # xmin, xmax = self.xmin, self.xmax # ## calculate x0 as "mean"-value # x0 = self.x0 if x0 is None: if hasattr(func, 'mean'): x0 = func.mean() else: m = Mean(xmin, xmax, False) x0 = m(func, *args) # ## check validity of x0 # if not xmin <= x0 <= xmax: raise AttributeError("Invalid x0 value %s<=%s<=%s" % (xmin, x0, xmax)) # ## get the normalization # norm = _integral_(func, xmin, xmax) if 0 >= norm: raise AttributeError("Normalization integral is not positive %s" % norm) # ## Equation: ifun(x) \equiv \int_{x0-x}^{x0+x}f(t)dt - N*prob = 0 # yval = self.prob * norm def ifun(x): if 0 >= x: return -yval return _integral_(func, max(xmin, x0 - x), min(xmax, x0 + x)) - yval from ostap.math.rootfinder import findroot s = findroot(ifun, 0, max(xmax - x0, x0 - xmin)) from ostap.math.ve import VE return VE(x0, s * s)
def __call__(self, func, *args): ## ## get the position of the mode m0 = Mode.__call__(self, func, *args) ## function value at the maximum v0 = func(m0, *args) ## half height vheight = 1.0 * v0 * self._hfactor ifun = lambda x, *a: float(func(x, *a)) - vheight from ostap.math.rootfinder import findroot x1 = findroot(ifun, self.xmin, m0, args=args) x2 = findroot(ifun, m0, self.xmax, args=args) return x1, x2
def test_root_sin(): fun = lambda x: -1.00 * math.sin(0.5 * (x - 1.0)) der1 = lambda x: -0.50 * math.cos(0.5 * (x - 1.0)) der2 = lambda x: +0.25 * math.sin(0.5 * (x - 1.0)) logger.info( 'sin/Halley: %.15g\n%s' % find_root(fun, -0.5, 2.5, deriv1=der1, deriv2=der2, full_output=True)) logger.info('sin/Newton: %.15g\n%s' % find_root(fun, -0.5, 2.5, deriv2=der1, full_output=True)) logger.info('sin/Plain : %.15g\n%s' % find_root(fun, -0.5, 2.5, full_output=True)) logger.info('sin/Brent : %.15g\n%s' % findroot(fun, -0.5, 2.5, full_output=True))
def _solve_(func, fval, xmn, xmx, *args): ## if isequal(xmn, xmx): return xmn ## ifun = lambda x, *a: func(x, *a) - fval ## fmn = ifun(xmn) if iszero(ifun(xmn)): return xmn fmx = ifun(xmx) if iszero(ifun(xmx)): return xmx ## if 0 < fmx * fmn: ## more or less arbitrary choice return xmx if abs(fmx) <= abs(fmn) else xmn # from ostap.math.rootfinder import findroot return findroot(ifun, xmn, xmx, args=args)
def test_root_mult(): K = 1 N = 2 * K + 1 fun = lambda x: 1.0 * (x - 1.0)**N der1 = lambda x: 1.0 * N * (x - 1.0)**(N - 1) der2 = lambda x: 1.0 * N * (N - 1) * (x - 1.0)**(N - 2) logger.info('mult/Halley: %.15g\n%s' % find_root( fun, -1, 10, deriv1=der1, deriv2=der2, full_output=True, disp=False)) logger.info( 'mult/Newton: %.15g\n%s' % find_root(fun, -1, 10, deriv1=der1, full_output=True, disp=False)) logger.info('mult/Plain : %.15g\n%s' % find_root(fun, -1, 10, full_output=True, disp=False)) logger.info('mult/Brent : %.15g\n%s' % findroot(fun, -1, 10, full_output=True, disp=False))
def __call__(self, func, *args): ## if 0.5 == self.Q: return Median.__call__(self, func, *args) elif 0.0 == self.Q: return self.xmin elif 1.0 == self.Q: return self.xmax ## need to know the integral from ostap.math.integral import IntegralCache iint = IntegralCache(func, self.xmin, err=False, args=args) quan = 1.0 / iint(self.xmax) / self.Q ifun = lambda x: iint(x) * quan - 1.0 xmn = self.xmin xmx = self.xmax p = 0.5 l = 0.5 ## make some bracketing before next step while (not isinstance(xmn, float)) or (not isinstance( xmx, float)) or l > 0.1: l /= 2 m = self._median_(func, xmn, xmx, *args) if self.Q < p: xmn = xmn xmx = float(m) p -= l elif self.Q > p: xmn = float(m) xmx = xmx p += l else: return m ## RETURN ## finally, calculate quantile from ostap.math.rootfinder import findroot result = findroot(ifun, xmn, xmx) return result
def __call__(self, func, *args): ## additional arguments args = args if args else self.args # ## define integration rules # if hasattr(func, 'integral'): _integral_ = lambda f, low, high: f.integral(low, high, *args) else: from ostap.math.integral import integral _integral_ = lambda f, low, high: integral(f, low, high, *args) # ## xmin/max # xmin, xmax = self.xmin, self.xmax # # calculate mode if hasattr(func, 'mode'): xmode = func.mode() else: md = Mode(xmin, xmax) xmode = md(func, *args) if not xmin <= xmode <= xmax: raise AttributeError("Invalid mode value %s<=%s<=%s" % (xmin, xmode, xmax)) # ## get the normalization # norm = _integral_(func, xmin, xmax) if 0 >= norm: raise AttributeError("Normalization integral is not positive %s" % norm) normL = _integral_(func, xmin, xmode) normR = _integral_(func, xmode, xmax) from ostap.math.base import isequal, iszero ## solve equation f(x)=a def _solve_(func, fval, xmn, xmx, *args): ## if isequal(xmn, xmx): return xmn ## ifun = lambda x, *a: func(x, *a) - fval ## fmn = ifun(xmn) if iszero(ifun(xmn)): return xmn fmx = ifun(xmx) if iszero(ifun(xmx)): return xmx ## if 0 < fmx * fmn: ## more or less arbitrary choice return xmx if abs(fmx) <= abs(fmn) else xmn # from ostap.math.rootfinder import findroot return findroot(ifun, xmn, xmx, args=args) yval = self.prob * norm fm = func(xmode) def iifun(f): if iszero(f): x1, x2 = xmin, xmax elif isequal(f, fm): return -yval else: x1 = _solve_(func, f, xmin, xmode) x2 = _solve_(func, f, xmode, xmax) return _integral_(func, x1, x2) - yval from ostap.math.rootfinder import findroot l = findroot(iifun, 0, func(xmode)) x1 = _solve_(func, l, xmin, xmode) x2 = _solve_(func, l, xmode, xmax) return x1, x2
def _solve_(self, func, fval, xmn, xmx, *args): ifun = lambda x, *a: func(x, *a) - fval from ostap.math.rootfinder import findroot return findroot(ifun, xmn, xmx, args=args)