Exemplo n.º 1
0
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 
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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 )
Exemplo n.º 4
0
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))
Exemplo n.º 5
0
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)
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
        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
Exemplo n.º 8
0
    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 ) 
Exemplo n.º 9
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
     #
     from ostap.math.rootfinder import findroot
     return findroot(ifun, xmn, xmx, args=args)
Exemplo n.º 10
0
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
Exemplo n.º 11
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 )
Exemplo n.º 12
0
    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 )
Exemplo n.º 13
0
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
Exemplo n.º 14
0
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
Exemplo n.º 15
0
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
Exemplo n.º 16
0
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
Exemplo n.º 17
0
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 
Exemplo n.º 18
0
    >>> 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 = [
Exemplo n.º 19
0
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])