def lcm ( f , g ) : """Find the least common multiple for two bernstein polynomials - see https://en.wikipedia.org/wiki/Least_common_multiple :Example: >>> b1 = ... >>> b2 = ... >>> r = b1.lcm ( b2 ) >>> r = lcm ( b1 , b2 ) ## ditto """ fn = f.norm() while 0 < f.degree() and isequal ( f.head() + fn , fn ) : f = f.reduce ( 1 ) fn = f.norm ( ) gn = g.norm() while 0 < g.degree() and isequal ( g.head() + gn , gn ) : g = g.reduce ( 1 ) gn = g.norm ( ) if f.degree() < g.degree() : return lcm ( g , f ) if 0 == f.degree() : return g elif 0 == g.degree() : return f d = f.gcd ( g ) return ( g // d ) * f
def _laguerre_ ( x , f , d1 = None , d2 = None ) : """ Root finding for Bernstein polnomials using Laguerre's method - https://en.wikipedia.org/wiki/Laguerre%27s_method """ fn = f.norm() / 10 n = f.degree() xmin = f.xmin () xmax = f.xmax () l = xmax - xmin if not d1 : d1 = f.derivative() if not d2 : d2 = d1.derivative() if not f.xmin() <= x <= f.xmax() : x = 0.5 * ( xmin + xmax ) if 1 == f.degree() : p0 = f [ 0 ] p1 = f [ 1 ] s0 = signum ( p0 ) s1 = signum ( p1 ) return ( p1 * xmin - p0 * xmax ) / ( p1 - p0) , ## the convergency is cubic, therefore 16 is *very* larger number of iterations for i in range(16) : if not xmin <= x <= xmax : ## something goes wrong: multiple root? go to derivative break vx = f.evaluate(x) if iszero ( vx ) or isequal ( fn + vx , fn ) : return x, G = d1 ( x ) / vx H = G * G - d2 ( x ) / vx d = math.sqrt ( ( n - 1 ) * ( n * H - G * G ) ) if G < 0 : d = -d a = n / ( G + d ) x -= a if isequal ( a + x , x ) : return x, ## look for derivative r = _laguerre_ ( x , d1 , d2 , d2.derivative() ) if r : r = r[:1] + r return r
def gcd ( f , g ) : """ Find the greatest common divisor for two Bernstein polynomials >>> b1 = ... >>> b2 = ... >>> r = b1.gcd ( b2 ) >>> r = gcd ( b1 , b2 ) ## ditto - see https://en.wikipedia.org/wiki/Greatest_common_divisor - see https://en.wikipedia.org/wiki/Euclidean_algorithm """ fn = f.norm() while 0 < f.degree() and isequal ( f.head() + fn , fn ) : f = f.reduce ( 1 ) fn = f.norm ( ) gn = g.norm() while 0 < g.degree() and isequal ( g.head() + gn , gn ) : g = g.reduce ( 1 ) gn = g.norm ( ) if f.degree() < g.degree() : return gcd ( g , f ) if 0 == f.degree() : return f elif 0 == g.degree() : return g if f.zero() or f.small ( gn ) : return g elif g.zero() or g.small ( fn ) : return f ## scale them properly import math sf = math.frexp( fn )[1] sg = math.frexp( gn )[1] scale = 0 if 1 != sf : f = f.ldexp ( 1 - sf ) if 1 != sg : g = g.ldexp ( 1 - sg ) return gcd ( f , g ).ldexp( sg - 1 ) a , b = divmod ( f , g ) fn = f.norm () gn = g.norm () an = a.norm () bn = b.norm () if isequal ( an * gn + fn + bn , fn + an * gn ) : return g if isequal ( fn + bn + gn * an , fn + bn ) : return b return gcd ( g , b )
def correlation(mtrx, i, j): """Get the correlation element from the matrix-like object >>> mtrx = ... >>> corr = correlation ( mtrx , 1 , 2 ) """ v = matrix(mtrx, i, j) if abs(v) <= 1: return v elif 0 < v and isequal(v, 1): return 1 elif 0 > v and isequal(v, -1): return -1 return TypeError("Can't get corr(%d,%d) for m=%s" % (i, j, mtrx))
def _merge_(roots, dx): """Merge duplicated roots together """ merged = [] for x in roots: found = False n = len(merged) for i in range(n): y = merged[i] if isequal(x, y) or isequal(x - y + dx, dx): found = True merged[i] = 0.5 * (x + y) if not found: merged.append(x) return tuple(merged)
def __call__(self, x): """Make the actual interpolation""" s1 = None s2 = 0 x = float(x) for i, item in enumerate(self.__table): xi, yi = item if x == xi or isequal(x, xi): return yi ## RETURN ## calculate weight wi = self.weight(i) * 1.0 / (x - xi) if 0 == i: s1 = self.__scaler(yi, wi) else: s1 = self.__adder(s1, self.__scaler(yi, wi)) s2 += wi return self.__scaler(s1, 1.0 / s2)
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
def __call__ ( self , args , cor = None ) : """Calcualte the value of the scalar function of N arguments with uncertainties and correlations >>> fun2 = lambda x , y : ... >>> fun2e = EvalNVEcor ( fun2 , 2 ) >>> cor = ... # 2x2 symmetric correlation matrix >>> x = ... >>> y = ... >>> result = fun2e ( (x,y) , cor ) ## """ n = self.N assert len ( args ) == n , 'Invalid argument size' ## get value of the function val = self.func ( *args ) c2 = 0 x = n * [ 0 ] ## argument g = n * [ 0 ] ## gradient for i in range ( n ) : xi = VE ( args[i] ) x [i] = x ci = xi.cov2() if ci < 0 or iszero ( ci ) : continue di = self.partial[i] ( *args ) if iszero ( di ) : continue ei = xi.error() g [i] = di e [i] = ei ## diagonal correlation coefficients are assumed to be 1 and ignored! c2 += ci * di * di for j in range ( i ) : xj = x [ j ] cj = xj.cov2 () if cj < 0 or iszero ( cj ) : continue dj = d [ j ] if iszero ( dj ) : continue ej = e [ j ] rij = self.__corr ( cor , i , j ) if cor else 0 assert -1 <= rij <= 1 or isequal ( abs ( rij ) , 1 ) ,\ 'Invalid correlaation coefficient (%d,%d)=%s ' % ( i , j , rij ) c2 += 2.0 * di * dj * rij * ei * ej return VE ( val , c2 )
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 _ve_b2s_(s): """Get background-over-signal ratio B/S estimate from the equation: error(S) = 1/sqrt(S) * sqrt ( 1 + B/S). >>> v = ... >>> b2s = v.b2s() ## get B/S estimate """ # vv = s.value() if vv <= 0 or iszero(vv): return VE(-1, 0) # c2 = s.cov2() if c2 <= 0 or iszero(c2): return VE(-1, 0) elif isequal(vv, c2): return VE(1, 0) elif c2 < vv: return VE(-1, 0) # return c2 / s - 1.0
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 # ## use scipy to find solution from scipy import optimize return optimize.brentq ( ifun , xmn , xmx , args = args )
def __call__ ( self , x , y , cxy = 0 ) : """Evaluate the function >>> func2 = lambda x,y : x*x + y*y >>> eval2 = Eval2VE ( func2 ) >>> x = VE(1,0.1**2) >>> y = VE(2,0.1**2) >>> print eval2(x,y) ## treat x,y as uncorrelated >>> print eval2(x,y, 0) ## ditto >>> print eval2(x,y,+1) ## treat x,y as 100% correlated >>> print eval2(x,y,-1) ## treat x,y as 100% anti-correlated """ assert isinstance ( cxy , num_types ) and \ ( abs ( cxy ) <= 1 or isequal ( abs ( cxy ) , 1 ) ) , \ 'Invalid correlation coefficient %s' % cxy x = VE ( x ) y = VE ( y ) xv = x.value() yv = y.value() val = self.func ( xv , yv ) xc2 = x.cov2() yc2 = x.cov2() x_plain = xc2 <= 0 or iszero ( xc2 ) y_plain = yc2 <= 0 or iszero ( yc2 ) # if x_plain and y_plain : return VE ( val , 0 ) # ## here we need to calculate the uncertainties # dx = self.partial[0] ( xv , yv ) if not x_plain else 0 dy = self.partial[1] ( xv , yv ) if not y_plain else 0 # cov2 = dx * dx * xc2 + dy * dy * yc2 if cxy and xc2 and yc2 : cov2 += 2 * cxy * dx * dy * math.sqrt ( xc2 * yc2 ) return VE ( val , cov2 )
def _vector_eq_(a, b): """Equality for vectors >>> vector1 = ... >>> vector2 = ... >>> print vector1 == vector2 >>> print vector1 == ( 0, 2, 3 ) >>> print vector1 == [ 0, 2, 3 ] """ if a is b: return True elif not hasattr(b, '__len__'): return False elif len(a) != len(b): return False # ops = _get_eq_op_(a.__class__, b.__class__) if ops: return ops.equal(a, b) ## RETURN ## compare elements for i in range(len(a)): if not isequal(a[i], b[i]): return False return True
def _ve_purity_(s): """Calculate the ``effective purity'' ratio using the identity p = S/(S+B) = 1/( 1 + B/S ), - and the effective ``background-to-signal'' ratio B/S is estimated as B/S = sigma^2(S)/S - 1 - Finally one gets p = S / sigma^2(S) - see Ostap::Math::b2s - see Ostap::Math::purity """ # vv = s.value() if vv <= 0 or iszero(vv): return VE(-1, 0) # c2 = s.cov2() if c2 <= 0 or iszero(c2): return VE(-1, 0) elif isequal(vv, c2): return VE(1, 0) elif c2 < vv: return VE(-1, 0) # return s / cov2
def solve(bs, C=0, split=5): """Solve equation B(x) = C bs : (input) b-spline C : (input) right-hand side :Example: >>> bs = ... >>> print bs.solve() """ _bs = bs - C if 1 >= _bs.degree(): return _bs.crossing_points(True) ## scale if needed _bs = _scale_(_bs) ## check zeroes of control polygon cps = _bs.crossing_points() ncp = len(cps) bsn = _bs.norm() ## xmin = _bs.xmin() xmax = _bs.xmax() for i in range(20): if not cps: return () ## RETURN inserted = False for x in cps: if isequal(x, _bs.xmin()): continue ## CONTINUE if isequal(x, _bs.xmax()): continue ## CONTINUE bx = _bs(x) if iszero(bx) or isequal(bx + bsn, bsn): continue if _bs.insert(x): inserted = True ## all zeroes are already inserted.... if not inserted: return cps ## RETURN cps = _bs.crossing_points(False) if not cps: ## roots have disapperead.. it could happen near multiple roots cps = _bs.crossing_points(True) ## merge duplicates (if any) cps = _merge_(cps, max(abs(xmin), abs(xmax))) ## if no convergency.... ## if not cps or 1 == len(cps) or split <= 0 : return cps if not cps or split <= 0: return cps ## come back to the original spline _bs = bs - C ## add the current/best estimates of roots for x in cps: _bs.insert(x) ## get internal roots only (no edges) _cps = cps _bsn = _bs.norm() left_root = False right_root = False if isequal(_bs[0] + _bsn, _bsn): left_root = True _cps = _cps[1:] if isequal(_bs[-1] + _bsn, _bsn): right_root = True _cps = _cps[:-1] cpmin = _cps[0] cpmax = _cps[-1] dc = cpmax - cpmin xmin = _bs.xmin() xmax = _bs.xmax() dx = xmax - xmin ## if 1 == len(cps): x1 = 0.05 * xmin + 0.95 * cpmin x2 = 0.05 * xmax + 0.95 * cpmax b1 = _scale_(Ostap.Math.BSpline(_bs, xmin, x1)) b2 = _scale_(Ostap.Math.BSpline(_bs, x1, x2)) b3 = _scale_(Ostap.Math.BSpline(_bs, x2, xmax)) split -= 1 return _merge_( solve(b1, C=0, split=split) + solve(b2, C=0, split=split) + solve(b3, C=0, split=split), max(abs(xmin), abs(xmax))) dl = 0.05 * min(cpmin - xmin, dc) dr = 0.05 * min(xmax - cpmax, dc) x_left = cpmin - dl x_right = cpmax + dr x_mid = 0.5 * (cpmin + cpmax) import random ntry = 50 for i in range(ntry): if not isequal(_bs(x_left) + _bsn, _bsn): break alpha = random.uniform(0.05, 1) x_left = max(xmin, cpmin - alpha * dl) for i in range(ntry): if not isequal(_bs(x_mid) + _bsn, _bsn): break alpha = random.uniform(-1, 1) x_mid = 0.5 * (cpmin + cpmax) + alpha * dc / 20 for i in range(ntry): if not isequal(_bs(x_right) + _bsn, _bsn): break alpha = random.uniform(0.05, 1) x_right = min(xmax, cpmax + alpha * dr) ## split! split -= 1 if dc > 0.1 * dx: ## split bs1 = _scale_(Ostap.Math.BSpline(_bs, x_left, x_mid)) bs2 = _scale_(Ostap.Math.BSpline(_bs, x_mid, x_right)) roots = _merge_( solve(bs1, C=0, split=split) + solve(bs2, C=0, split=split), max(abs(xmin), abs(xmax))) else: ## trim bst = _scale_(Ostap.Math.BSpline(_bs, x_left, x_right)) roots = _merge_(solve(bst, C=0, split=split), max(abs(xmin), abs(xmax))) if left_root: roots = (xmin, ) + roots if right_root: roots = roots + (xmax, ) return roots
def romberg( fun, x0, x, err=False, epsabs=1.49e-8, epsrel=1.49e-8, limit=10, ## ignored, kept to mimic consistency with args=(), nmax=8, ## steps in Richardson's extrapolation maxdepth=10 ## the maxmal depth ): """Straw-man replacement of scipy.integrate.quad when it is not available. Actually it is a primitive form of Romberg's adaptive integration - see https://en.wikipedia.org/wiki/Romberg's_method - see https://en.wikipedia.org/wiki/Richardson_extrapolation - see https://en.wikipedia.org/wiki/Numerical_integration#Adaptive_algorithms CPU performance is not superb, but it is numerically stable. >>> func = lamnda x : x*x >>> v = romberg ( func , 0 , 1 ) """ # ========================================================================= ## internal recursive function # Romberg's adaptive integration wirh Richardson's extrapolation def _romberg_(f, a, b, ea, er, nmax, depth=0): rp = nmax * [0.0] rc = nmax * [0.0] ## starting value for integration step: full interval h = (b - a) ## here we have R(0,0) rc[0] = 0.5 * h * (f(b) + f(a)) i2 = 1 nf = 2 ## number of function calls for n in range(1, nmax): nf += i2 ## count number of function calls rp, rc = rc, rp ## swap rows h *= 0.5 ## decrement the step ## use simple trapezoid rule to calculate R(n,0) rr = 0.0 i2 *= 2 for k in xrange(1, i2, 2): rr += f(a + h * k) ## here we have R(n,0) rc[0] = 0.5 * rp[0] + h * rr ## calculate R(n,m) using Richardson's extrapolation p4 = 1 for m in xrange(1, n + 1): p4 *= 4 ## here we have R(n,m) rc[m] = rc[m - 1] + (rc[m - 1] - rp[m - 1]) / (p4 - 1) ## inspect last two elements in the row e = rc[n] p = rc[n - 1] ## check their absolute and relative difference d = abs(e - p) ae = max(abs(e), abs(p), abs(rc[0])) if d <= 0.5 * max(ea, 0.5 * ae * er): return e, d, depth, nf ## RETURN # ===================================================================== ## Need to split the interval into subintervals # ===================================================================== ## first check the maximal depth if 0 < maxdepth <= depth: warnings.warn('Romberg integration: maximal depth is reached') return e, d, depth, nf ## prepare to split the interval into 2**n subintervals n2 = 2**n ## the absolute uncertainty needs to be adjusted new_ea = ea / n2 ## ok ## keep the same relative uncertainty new_er = er ## the final result, its uncertainty and the max-depth rr, ee, dd = 0.0, 0.0, 0 ## split the region and start recursion: for i in range(n2): ai = a + i * h bi = ai + h ## recursion: # get result, error, depth and number of function calls from subinterval r, e, d, n = _romberg_(f, ai, bi, new_ea, new_er, nmax, depth + 1) rr += r ## get the integral as a sum over subintervals ee += abs(e) ## direct summation of uncertainties dd = max(dd, d) ## maximal depth from all sub-intervals nf += n ## total number of function calls return rr, ee, dd, nf ## RETURN ## adjust input data a = float(x0) b = float(x) ea = float(epsabs) er = float(epsrel) ## the same edges if isequal(a, b): return VE(0, 0) if err else 0.0 ## crazy settings for uncertainties if (ea <= 0 or iszero(ea)) and (er <= 0 or iszero(er)): raise AttributeError( "Romberg: absolute and relative tolerances can't be non-positive simultaneously" ) ## adjust maximal number of steps in Richardson's extrapolation nmax = max(2, nmax) ## ensure that function returns double values: func = lambda x: float(fun(x, *args)) ## finally use Romberg's integration v, e, d, nc = _romberg_(func, a, b, ea, er, nmax) ## form the final result : return VE(v, e * e) if err else v
def solve ( bp , C = 0 , split = 2 ) : """Solve equation B(x) = C, where B(x) is Bernstein polynomial, and C is e.g. constant or another polynomial >>> bernstein = ... >>> roots = bernstein.solve () >>> roots = solve ( bernstein , C = 0 ) ## ditto """ ## construct the equation b'(x)=0: bp = bp.bernstein() if C : bp = bp - C ## 1) zero-degree polynomial if 0 == bp.degree() : if iszero ( bp[0] ) : return bp.xmin(), return () ## 2) linear polynomial elif 1 == bp.degree() : x0 = bp.xmin() x1 = bp.xmax() p0 = bp[0] p1 = bp[1] s0 = signum ( p0 ) s1 = signum ( p1 ) bn = bp.norm() if iszero ( p0 ) or isequal ( p0 + bn , bn ) : s0 = 0 if iszero ( p1 ) or isequal ( p1 + bn , bn ) : s1 = 0 if s0 == 0 : return x0, ## elif s1 == 0 : return x1, ## elif s0 * s1 > 0 : return () ## no roots # return ( p1 * x0 - p0 * x1 ) / ( p1 - p0) , ## make a copy & scale is needed bp = _scale_ ( bp + 0 ) ## norm of polynomial bn = bp.norm() ## check number of roots nc = bp.sign_changes() if not nc : return () ## no roots ! RETURN ## treat separetely roots at the left and right edges roots = [] while 1 <= bp.degree() and isequal ( bp[0] + bn , bn ) : bp -= bp[0] bp = bp.deflate_left() bp = _scale_ ( bp ) bn = bp.norm () roots.append ( bp.xmin() ) if roots : return tuple(roots) + bp.solve ( split = split ) roots = [] while 1 <= bp.degree() and isequal ( bp[-1] + bn , bn ) : bp -= bp[-1] bp = bp.deflate_right() bp = _scale_ ( bp ) bn = bp.norm () roots.append ( bp.xmax() ) if roots : return bp.solve ( split = split ) + tuple(roots) ## check again number of roots nc = bp.sign_changes() if not nc : return () ## no roots ! RETURN # ========================================================================= ## there are many roots in the interval # ========================================================================= if 1 < nc : xmin = bp.xmin () xmax = bp.xmax () lcp = bp.left_line_hull() if ( not lcp is None ) and xmin <= lcp <= xmax : xmin = max ( xmin , lcp ) rcp = bp.right_line_hull() if ( not rcp is None ) and xmin <= rcp <= xmax : xmax = min ( xmax , rcp ) # ===================================================================== ## Two strategies for isolation of roots: # - use control polygon # - use the derivative # For both cases, the zeros of contol-polygon and/or derivatives # are tested to be the roots of polynomial.. # If they corresponds to the roots, polinomial is properly deflated and # deflated roots are collected # Remaining points are used to (recursively) split interval into smaller # intervals with presumably smaller number of roots # if 0 < split : cps = bp.crossing_points() splits = [ xmin ] for xp in cps : if xmin < xp < xmax : splits.append ( xp ) splits.append ( xmax ) split -= 1 else : ## use the roots of derivative dd = bp.derivative() rd = dd.solve ( split = split ) if not rd : ## use bisection nrd = xmin, 0.5 * ( xmin + xmax ), xmax else : ## use roots of derivative nrd = [ xmin , xmax ] for r in rd : if xmin < r < xmax : found = False for rr in nrd : if isequal ( r , rr ) : found = True break if not found : nrd.append ( r ) nrd.sort() splits = list(nrd) ## use simple bisection if 2 >= len ( splits ) : if xmin < xmax : splits = xmin , 0.5*( xmin + xmax ) , xmax else : splits = bp.xmin() , 0.5*(bp.xmin()+bp.xmax()) , bp.xmax() splits = list(splits) roots = [] for s in splits : bv = bp.evaluate ( s ) bn = bp.norm() while 1 <= bp.degree() and isequal ( bv + bn , bn ) : bp -= bv bp = bp.deflate ( s ) bp = _scale_ ( bp ) bn = bp.norm ( ) bv = bp.evaluate ( s ) roots.append ( s ) for q in splits : if isequal ( q , s ) : splits.remove ( q ) if roots : roots += list ( bp.solve ( split = ( split - 1 ) ) ) roots.sort() return tuple(roots) if 2 == len(splits) : if isequal ( bp.xmin() , splits[0] ) and isequal ( bp.xmax() , splits[1] ) : xmn = splits[0] xmx = splits[1] splits = [ xmn , 0.5*(xmn+xmx) , xmx ] ns = len(splits) for i in range(1,ns) : xl = splits[i-1] xr = splits[i ] bb = _scale_ ( Bernstein ( bp , xl , xr ) ) roots += bb.solve ( split = ( split - 1 ) ) roots.sort() return tuple ( roots ) ## RETURN # ========================================================================= ## there is exactly 1 root here # ========================================================================= l0 = ( bp.xmax() - bp.xmin() ) / ( bp.degree() + 1 ) ## trivial case if 1 == bp.degree() : y0 = bp[ 0] y1 = bp[-1] x = ( y1 * bp.xmin() - y0 * bp.xmax() ) / ( y1 - y0) return x, ## make several iterations (not to much) for better isolation of root for i in range ( bp.degree() + 1 ) : xmin = bp.xmin () xmax = bp.xmax () bn = bp.norm () lcp = bp.left_line_hull () if not lcp is None : if isequal ( lcp , xmin ) : return lcp, ## RETURN elif lcp <= xmax or isequal ( lcp , xmax ) : bv = bp.evaluate ( lcp ) if iszero ( bv ) or isequal ( bv + bn , bn ) : return lcp, ## RETURN xmin = max ( xmin , lcp ) rcp = bp.right_line_hull () if not rcp is None : if isequal ( lcp , xmax ) : return rcp, ## RETURN elif lcp >= xmin or isequal ( lcp , xmin ) : bv = bp.evaluate ( rcp ) if iszero ( bv ) or isequal ( bv + bn , bn ) : return rcp, ## RETURN xmax = min ( xmax , rcp ) ## if isequal ( xmin , xmax ) : return 0.5*(xmin+xmax), ## RETURN if xmin >= xmax : break ## BREAK ## avoid too iterations - it decreased the precision if 10 * ( xmax - xmin ) < l0 : break ## BREAK s0 = signum ( bp[ 0] ) s1 = signum ( bp[-1] ) smn = signum ( bp.evaluate ( xmin ) ) smx = signum ( bp.evaluate ( xmax ) ) ## we have lost the root ? if ( s0 * s1 ) * ( smn * smx ) < 0 : break ## BREAK ## refine the polynomial: _bp = Bernstein ( bp , xmin , xmax ) _bp = _scale_ ( _bp ) _nc = _bp.sign_changes() ## we have lost the root if not _nc : break ## BREAK bp = _bp bn = bp.norm() # ========================================================================= ## start the of root-polishing machinery # ========================================================================= f = bp d1 = f .derivative () d2 = d1.derivative () cps = bp.crossing_points() if cps : x = cps[0] else : x = 0.5*(bp.xmin()+bp.xmax()) ## use Laguerre's method to refine the isolated root l = _laguerre_ ( x , f , d1 , d2 ) return l
>>> x,mu, sigma = .... >>> cdf = gauss_cdf ( x , mu , sigma ) """ m = float(mu) s = abs(float(sigma)) y = (VE(x) - m) / s ## return _gauss_cdf_(y) if 0 < y.cov2() else _gauss_cdf_(y.value()) # ============================================================================= ## FIX # @see https://sft.its.cern.ch/jira/browse/ROOT-6627' _a = VE(1, 1) _b = VE(_a) if isequal(_a.error(), _b.error()): pass else: jira = 'https://sft.its.cern.ch/jira/browse/ROOT-6627' vers = ROOT.gROOT.GetVersion() logger.warning('The problem %s is not solved yet ( ROOT %s) ' % (jira, vers)) logger.warning('Temporarily disable cast of VE to float') del VE.__float__ # ============================================================================= if '__main__' == __name__: from ostap.utils.docme import docme docme(__name__, logger=logger) funcs = [
def _dp0_points_(dp, M, npoints=250): """Make a graph of Dalitz plot >>> d = Dalitz ( 0.1 , 0.2 , 0.3 ) >>> points = d.points ( M = 5 ) """ m1 = dp.m1() m2 = dp.m2() m3 = dp.m3() assert m1 + m2 + m3 <= M, \ 'Dalitz0.points: Invalid mass %s>%s+%s+%s' % ( M , m1 , m2 , m3 ) s = M * M s1_min = dp.s1_min() s1_max = dp.s1_max(M) s2_min = dp.s2_min() s2_max = dp.s2_max(M) s3_min = dp.s3_min() s3_max = dp.s3_max(M) ## four reference minmax points .. P = [(s1_min, dp.s2_minmax_for_s_s1(s, s1_min).first), (dp.s1_minmax_for_s_s2(s, s2_max).second, s2_max), (s1_max, dp.s2_minmax_for_s_s1(s, s1_max).second), (dp.s1_minmax_for_s_s2(s, s2_min).first, s2_min)] P = [p for p in P if s1_min <= p[0] <= s1_max and s2_min <= p[1] <= s2_max] pnts = [] from ostap.utils.utils import vrange ## fill branches 1 and 3 for v in vrange(s1_min, s1_max, npoints): s1 = v s2 = dp.s2_minmax_for_s_s1(s, s1) s2min = s2.first s2max = s2.second if not s2min < s2max: continue x = s1 y1, y2 = s2min, s2max if s1_min <= x <= s1_max: if s2_min <= y1 <= s2_max: pnts.append((x, y1)) if s2_min <= y2 <= s2_max: pnts.append((x, y2)) ## fill branches 2 and 4 : for v in vrange(s2_min, s2_max, npoints): s2 = v s1 = dp.s1_minmax_for_s_s2(s, s2) s1min = s1.first s1max = s1.second if s1min < s1max: y = s2 x1, x2 = s1min, s1max if s2_min <= y <= s2_max: if s1_min <= x1 <= s1_max: pnts.append((x1, y)) if s1_min <= x2 <= s1_max: pnts.append((x2, y)) pnts = P + pnts pnts = [ p for p in pnts if dp.inside(s, p[0], p[1]) or abs(dp.distance(s, p[0], p[1])) < 1.e-8 * s ] ## find some point "inside" Dalitz plot ## first guess x0 = 0.5 * (s1_min + s1_max) y0 = 0.5 * (s2_min + s2_max) ## find another point if needed while not dp.inside(s, x0, y0): import random x0 = random.uniform(s1_min, s1_max) y0 = random.uniform(s2_min, s2_max) ## collect, eliminate the duplicates and ogranize all points according to phi from ostap.math.base import isequal points = set() for p in pnts: x, y = p dx = x - x0 dy = y - y0 phi = math.atan2(dy, dx) in_list = False for entry in points: if isequal(phi, entry[0]): in_list = True break if in_list: continue point = phi, x, y points.add(point) ## convert set to the list points = list(points) ## sort the list according to phi points.sort() ## make a closed loop from the points if points and points[0][1:] != points[-1][1:]: points.append(points[0]) return tuple([p[1:] for p in points])