From 0850a9e1bd365c810173a632987a204eb6ff693e Mon Sep 17 00:00:00 2001 From: Vanya Belyaev Date: Wed, 6 Nov 2024 10:44:38 +0100 Subject: [PATCH] 1. add `isfinite` method for `SE` & `WSE` counters 1. `data_statistics` : add the check for the finite counters 1. add `isfinite` method for matrices and vectors 1. add `isfinite` method for `(W)Covariance` objects --- ReleaseNotes/release_notes.md | 2 + ostap/math/linalg2.py | 60 +++++++++++++++---------- ostap/stats/corr2d.py | 5 +++ ostap/stats/counters.py | 28 +----------- source/include/Ostap/Covariance.h | 16 +++++++ source/include/Ostap/MatrixUtils.h | 20 +++++++++ source/include/Ostap/MatrixUtils2.h | 5 --- source/include/Ostap/MatrixUtilsT.h | 41 +++++++++++++++++ source/include/Ostap/NStatEntity.h | 4 ++ source/include/Ostap/SVectorWithError.h | 10 +++++ source/include/Ostap/StatEntity.h | 10 +++++ source/include/Ostap/WStatEntity.h | 10 +++++ 12 files changed, 155 insertions(+), 56 deletions(-) diff --git a/ReleaseNotes/release_notes.md b/ReleaseNotes/release_notes.md index 0e2e4517..17bdb915 100644 --- a/ReleaseNotes/release_notes.md +++ b/ReleaseNotes/release_notes.md @@ -4,6 +4,8 @@ 1. add generalized Beta' distribution 1. add `isfinite` method for `SE` & `WSE` counters 1. `data_statistics` : add the check for the finite counters + 1. add `isfinite` method for matrices and vectors + 1. add `isfinite` method for `(W)Covariance` objects ## Backward incompatible diff --git a/ostap/math/linalg2.py b/ostap/math/linalg2.py index 154290e1..e7a513a3 100644 --- a/ostap/math/linalg2.py +++ b/ostap/math/linalg2.py @@ -96,7 +96,7 @@ def mgetter ( mtrx , i , j ) : # corr = correlation ( mtrx , 1 , 2 ) # @endcode def correlation ( mtrx , i , j ): - """Get the correlation element from the matrix-like object + """ Get the correlation element from the matrix-like object >>> mtrx = ... >>> corr = correlation ( mtrx , 1 , 2 ) """ @@ -113,7 +113,7 @@ def correlation ( mtrx , i , j ): ## @class Method # access and keep the method class Method(object) : - """Access and keep the method + """ Access and keep the method """ def __init__ ( self , factory ) : @@ -161,7 +161,7 @@ def clear ( self ) : ## @class Method2 # access and keep two methods class Method2(object) : - """Access and keep two methods + """ Access and keep two methods """ def __init__ ( self , factory1 , factory2 ) : @@ -204,12 +204,11 @@ def clear ( self ) : ## dummy function def dummy ( *a, **b ) : return NotImplemented - # ============================================================================== ## @class LinAlg # collection of decorators for vectors/matrices class LinAlg(object) : - """Collection of decorators for vectors/matrices + """ Collection of decorators for vectors/matrices """ with_numpy = np @@ -228,7 +227,6 @@ class LinAlg(object) : methods_DIV = Method2 ( Ostap.Math.Ops.Div , Ostap.Math.Ops.CanDiv ) methods_IDIV = Method2 ( Ostap.Math.Ops.IDiv , Ostap.Math.Ops.CanIDiv ) - methods_DOT = Method2 ( Ostap.Math.Ops.Dot , Ostap.Math.Ops.CanDot ) methods_CROSS = Method2 ( Ostap.Math.Ops.Cross , Ostap.Math.Ops.CanDot ) @@ -246,10 +244,8 @@ class LinAlg(object) : method_EIGEN = Method ( Ostap.Math.Ops.Eigen ) method_TM = Method ( Ostap.Math.Ops.TM ) - ## method_EQ = Method ( Ostap.Math.Ops.Eq ) - known_ssymmatrices = {} known_smatrices = {} known_svectors = {} @@ -307,7 +303,7 @@ def restore ( klass , delete = ( 'to_numpy' , 'to_array' , 'column' , 'columns' , 'cross' , 'dot' , 'sym' , 'asym' , 'skew' ) ) : - """restore useful attributes + """ Restore useful attributes """ oa = '__old_attributes__' @@ -327,7 +323,7 @@ def restore ( klass , delete = ( 'to_numpy' , 'to_array' , ## cleanup the LinAlg @staticmethod def CLEANUP () : - """Cleanup LinAlg + """ Cleanup LinAlg """ while LinAlg.decorated_matrices : @@ -449,7 +445,7 @@ def NUMPY ( arr ) : # @endcode @staticmethod def V_NUMPY ( vct ) : - """Convert vector to numpy array: + """ Convert vector to numpy array: >>> vct = ... >>> na = vct.to_numpy() """ @@ -463,7 +459,7 @@ def V_NUMPY ( vct ) : # @endcode @staticmethod def M_NUMPY ( mtrx ) : - """Convert matrix into numpy.matrix + """ Convert matrix into numpy.matrix >>> mtrx = ... >>> m = mtrx.to_numpy() """ @@ -480,7 +476,7 @@ def M_NUMPY ( mtrx ) : # @endcode @staticmethod def S_LA ( obj ) : - """Convert matrix/vector-like object to SMatrix/SVector + """ Convert matrix/vector-like object to SMatrix/SVector >>> obj = ... >>> res = LinAlg.S_LA ( obj ) """ @@ -538,7 +534,7 @@ def ADD ( a , b ) : # @endcode @staticmethod def IADD ( a , b ) : - """Increment of matrix/vector objects + """ Increment of matrix/vector objects >>> A += B """ @@ -669,7 +665,7 @@ def RSUB ( a , b ) : # @endcode @staticmethod def MUL ( a , b ) : - """ Multiplication/scaling of vector/matrix objects: + """ Multiplication/scaling of vector/matrix objects: >>> C = A * B """ @@ -721,7 +717,7 @@ def IMUL ( a , b ) : # @endcode @staticmethod def RMUL ( a , b ) : - """Right-multiplication of matrix/vector objects + """ Right-multiplication of matrix/vector objects >>> C = B * A """ @@ -770,7 +766,7 @@ def DIV ( a , b ) : # @endcode @staticmethod def IDIV ( a , b ) : - """Multiplicative decrement/scaling of matrix/vector objects + """ Multiplicative decrement/scaling of matrix/vector objects >>> A /= B """ @@ -790,7 +786,7 @@ def IDIV ( a , b ) : # @endcode @staticmethod def EQ ( a , b ) : - """Equality for matrix/vector objects + """ Equality for matrix/vector objects >>> A == B """ @@ -830,7 +826,7 @@ def EQ ( a , b ) : # @endcode @staticmethod def NE ( a , b ) : - """Non-equality for matrix/vector objects + """ Non-equality for matrix/vector objects >>> A != B """ @@ -896,7 +892,7 @@ def DOT ( a , b ) : # @endcode @staticmethod def CROSS ( a , b ) : - """Cross-product (D1xD2 matrix) of two vectors + """ Cross-product (D1xD2 matrix) of two vectors >>> matrix = v1.cross ( v2 ) """ @@ -924,7 +920,7 @@ def CROSS ( a , b ) : # @endcode @staticmethod def SIM ( a , b ) : - """Similarity operation: C = B A B^T + """ Similarity operation: C = B A B^T >>> A = ... >>> B = ... >>> C = A.Sim ( B ) @@ -954,7 +950,7 @@ def SIM ( a , b ) : raise NotImplementedError ( "No SIM for %s/%s and %s/%s" % ( a , typename ( a ) , b , typename ( b ) ) ) # ========================================================================= - ## Similarity operation \f$ C = B^T A B \f$ + ## Similarity operation \f$ C = B^T A B \f$ # @code # A = ... # B = ... @@ -963,7 +959,7 @@ def SIM ( a , b ) : # @endcode @staticmethod def SIMT ( a , b ) : - """Similarity operation C = B^T A B + """ Similarity operation C = B^T A B >>> A = ... >>> B = ... >>> C = A.SimT ( B ) @@ -1261,7 +1257,20 @@ def M_MAXABSDIAGONAL ( mtrx ) : """ return Ostap.Math.maxabs_diagonal( mtrx ) - + # ============================================================================= + ## Are all elements of matrix/vector finite? + # @code + # mtrx = ... + # mtrx.isfinite() + # @endcode + @staticmethod + def M_ISFINITE ( mtrx ) : + """ Are all elements of matrix/vector finite? + >>> mtrx = ... + >>> mtrx.isfinite() + """ + return Ostap.Math.isfinite ( mtrx ) + # ============================================================================= ## get matrix shape # @code @@ -2274,6 +2283,7 @@ def deco_vector ( t ) : t.__reduce__ = LinAlg.V_REDUCE + t.isfinite = LinAlg.M_ISFINITE s = revct.search ( t.__name__ ) if s : @@ -2366,6 +2376,8 @@ def deco_matrix ( m ) : m.lnorm = LinAlg.M_LNORM m.mnorm = LinAlg.M_MNORM + m.isfinite = LinAlg.M_ISFINITE + if m.kRows == m.kCols : m.inverse = LinAlg.M_INVERSE diff --git a/ostap/stats/corr2d.py b/ostap/stats/corr2d.py index 05dfb788..4c639a4d 100755 --- a/ostap/stats/corr2d.py +++ b/ostap/stats/corr2d.py @@ -88,9 +88,14 @@ def __init__ ( self , self.selection , *self.args ) + if not self.__wcov.isfinite() : logger.error ( "Invalid covariance for '%s` : `%s'" % ( self.var1 , self.var2 ) ) + self.__counter1 = self.__wcov.counter1 () self.__counter2 = self.__wcov.counter2 () + if not self.__counter1.isfinite() : logger.error ( "Invalid statistics for '%s'" % self.var1 ) + if not self.__counter2.isfinite() : logger.error ( "Invalid statistics for '%s'" % self.var2 ) + ## the covariance matrix self.__cov2 = Ostap.Math.covariance ( self.__wcov ) diff --git a/ostap/stats/counters.py b/ostap/stats/counters.py index e8514b8c..41f59ce0 100755 --- a/ostap/stats/counters.py +++ b/ostap/stats/counters.py @@ -24,7 +24,7 @@ ) # ============================================================================= from ostap.math.ve import Ostap, VE -from ostap.math.base import isequal, isequalf, iszero, isfinite +from ostap.math.base import isequal, isequalf, iszero from ostap.core.ostap_types import dictlike_types, sequence_types import ROOT, cppyy, math, sys # ============================================================================= @@ -148,18 +148,6 @@ def _se_ne_ ( s1 , s2 ) : SE.__eq__ = _se_eq_ SE.__ne__ = _se_ne_ -# ============================================================================= -## Is the content of counter finit? -def _se_isfinite_ ( cnt ) : - """ Is the content of counter finit? """ - return \ - isfinite ( cnt.min () ) and \ - isfinite ( cnt.max () ) and \ - isfinite ( cnt.mu () ) and \ - isfinite ( cnt.mu2 () ) - -SE.isfinite = _se_isfinite_ - _new_methods_ += [ SE.sum , SE.mean , @@ -172,7 +160,6 @@ def _se_isfinite_ ( cnt ) : SE.__str__ , SE.__eq__ , SE.__ne__ , - SE.isfinite , ] # ============================================================================= @@ -218,18 +205,6 @@ def _wse_ne_ ( s1 , s2 ) : WSE.__repr__ = lambda s : 'WStat: '+ s.toString() WSE.__str__ = lambda s : 'WStat: '+ s.toString() -# ============================================================================= -## Is the content of counter finit? -def _wse_isfinite_ ( cnt ) : - """ Is the content of counter finit? """ - return \ - isfinite ( cnt.mu () ) and \ - isfinite ( cnt.mu2 () ) and \ - cnt.values ().isfinite() and \ - cnt.weights().isfinite() - -WSE.isfinite = _wse_isfinite_ - _new_methods_ += [ WSE.sum , WSE.mean , @@ -240,7 +215,6 @@ def _wse_isfinite_ ( cnt ) : WSE.__str__ , WSE.__eq__ , WSE.__ne__ , - WSE.isfinite () ] # ============================================================================= diff --git a/source/include/Ostap/Covariance.h b/source/include/Ostap/Covariance.h index b4355531..6c2e0e2d 100644 --- a/source/include/Ostap/Covariance.h +++ b/source/include/Ostap/Covariance.h @@ -91,6 +91,14 @@ namespace Ostap /// reset counters void reset () ; // ====================================================================== + // everything is finite? + inline bool isfinite () const + { + return std::isfinite ( m_cov2m ) + && m_cnt1.isfinite() + && m_cnt2.isfinite() ; + } + // ====================================================================== private: // ====================================================================== Ostap::StatEntity m_cnt1 { } ; @@ -206,6 +214,14 @@ namespace Ostap /// reset counters void reset () ; // ====================================================================== + // everything is finite? + inline bool isfinite () const + { + return std::isfinite ( m_cov2m ) + && m_cnt1.isfinite() + && m_cnt2.isfinite() ; + } + // ====================================================================== private: // ====================================================================== Ostap::WStatEntity m_cnt1 { } ; diff --git a/source/include/Ostap/MatrixUtils.h b/source/include/Ostap/MatrixUtils.h index 38657438..0f14d2a3 100755 --- a/source/include/Ostap/MatrixUtils.h +++ b/source/include/Ostap/MatrixUtils.h @@ -1753,6 +1753,26 @@ namespace Ostap } } ; // ======================================================================== + + // ======================================================================== + /// Are all elements of the vector finite? + template + inline bool isfinite ( const ROOT::Math::SVector& vct ) + { + for ( const T& v : vct ) { if ( !std::isfinite ( v ) ) { return false ; } } + return true ; + } + // ======================================================================== + // Are all elements of the matrix finite? + template + inline bool isfinite ( const ROOT::Math::SMatrix& mtrx ) + { + for ( const T& v : mtrx ) { if ( !std::isfinite ( v ) ) { return false ; } } + return true ; + } + // ======================================================================== + + // ======================================================================== } // end of namespace Math // ========================================================================== } // end of namespace Ostap::Math diff --git a/source/include/Ostap/MatrixUtils2.h b/source/include/Ostap/MatrixUtils2.h index 54766058..7085aca6 100644 --- a/source/include/Ostap/MatrixUtils2.h +++ b/source/include/Ostap/MatrixUtils2.h @@ -188,10 +188,6 @@ namespace Ostap const double /* m2 */ ) { return true ; } } ; - - - - // ====================================================================== // Can be multiplied // ====================================================================== @@ -233,7 +229,6 @@ namespace Ostap } ; // ======================================================================== - // ======================================================================== template diff --git a/source/include/Ostap/MatrixUtilsT.h b/source/include/Ostap/MatrixUtilsT.h index eecc6115..3d75e730 100644 --- a/source/include/Ostap/MatrixUtilsT.h +++ b/source/include/Ostap/MatrixUtilsT.h @@ -33,6 +33,43 @@ namespace Ostap // ========================================================================== namespace Math { + // ======================================================================== + /// Are all elements are finite? + template + inline bool isfinite + ( const TVectorT& vct ) + { + if ( !vct.IsValid() ) { return false ; } + const T* begin = vct.GetMatrixArray () ; + const T* end = begin + vct.GetNrows () ; + for ( const T* v = begin ; v != end ; ++v ) + { if ( !std::isfinite ( *v ) ) { return false ; } } + return true ; + } + /// Are all elements are finite? + template + inline bool isfinite + ( const TMatrixT& mtrx ) + { + if ( !mtrx.IsValid() ) { return false ; } + const T* begin = mtrx.GetMatrixArray () ; + const T* end = begin + mtrx.GetNrows() * mtrx.GetNcols() ; + for ( const T* v = begin ; v != end ; ++v ) + { if ( !std::isfinite ( *v ) ) { return false ; } } + return true ; + } + /// Are all elements are finite? + template + inline bool isfinite + ( const TMatrixTSym& mtrx ) + { + if ( !mtrx.IsValid() ) { return false ; } + const T* begin = mtrx.GetMatrixArray () ; + const T* end = begin + mtrx.GetNrows() * mtrx.GetNcols() ; + for ( const T* v = begin ; v != end ; ++v ) + { if ( !std::isfinite ( *v ) ) { return false ; } } + return true ; + } // ======================================================================== /// specialisation for vectors template @@ -3289,6 +3326,10 @@ namespace Ostap // ====================================================================== } // The end of namespace Ostap::Math::Ops // ======================================================================== + + + + // ======================================================================== } // The end of namespace Ostap::Math // ========================================================================== } // The end of namespace Ostap::Math diff --git a/source/include/Ostap/NStatEntity.h b/source/include/Ostap/NStatEntity.h index eb4fa554..4cdbf222 100644 --- a/source/include/Ostap/NStatEntity.h +++ b/source/include/Ostap/NStatEntity.h @@ -109,6 +109,10 @@ namespace Ostap m_cnt2.reset() ; } // ===================================================================== + // all finite values ? + inline bool isfinite () const + { return m_cnt1.isfinite () && m_cnt2.isfinite() ; } + // ===================================================================== public: // the main method without decorations // ====================================================================== /// the main method without decorations diff --git a/source/include/Ostap/SVectorWithError.h b/source/include/Ostap/SVectorWithError.h index 404f85d4..cd89a4ad 100644 --- a/source/include/Ostap/SVectorWithError.h +++ b/source/include/Ostap/SVectorWithError.h @@ -852,6 +852,16 @@ namespace Ostap y.value () , y.cov2 () , ny ) ; } // ======================================================================== + /// Are all elements are finite? + template + inline bool isfinite + ( const SVectorWithError& vct ) + { + return + Ostap::Math::isfinite ( vct.value () ) && + Ostap::Math::isfinite ( vct.cov2 () ) ; + } + // ======================================================================== } // ========================================================================== } diff --git a/source/include/Ostap/StatEntity.h b/source/include/Ostap/StatEntity.h index c0383897..87fa6f6f 100644 --- a/source/include/Ostap/StatEntity.h +++ b/source/include/Ostap/StatEntity.h @@ -326,6 +326,16 @@ namespace Ostap /// printout to std::ostream std::ostream& fillStream ( std::ostream& o ) const ; // ====================================================================== + // all finite values ? + inline bool isfinite () const + { + return + std::isfinite ( m_mu ) && + std::isfinite ( m_mu2 ) && + std::isfinite ( m_min ) && + std::isfinite ( m_max ) ; + } + // ====================================================================== private: // data members // ====================================================================== /// number of calls diff --git a/source/include/Ostap/WStatEntity.h b/source/include/Ostap/WStatEntity.h index bb28a693..5c25cab4 100644 --- a/source/include/Ostap/WStatEntity.h +++ b/source/include/Ostap/WStatEntity.h @@ -122,6 +122,16 @@ namespace Ostap /// printout to std::ostream std::ostream& fillStream ( std::ostream& o ) const ; // ====================================================================== + // all finite values ? + inline bool isfinite () const + { + return + std::isfinite ( m_mu ) && + std::isfinite ( m_mu2 ) && + m_values .isfinite () && + m_weights.isfinite () ; + } + // ====================================================================== public: // the main methods // ====================================================================== /** the only one important method: add value with the given weight