@@ -1248,6 +1248,7 @@ def fast_eval( # noqa: C901
12481248 ne_args : dict = kwargs .pop ("_ne_args" , {})
12491249 if ne_args is None :
12501250 ne_args = {}
1251+ fp_accuracy = kwargs .pop ("fp_accuracy" , blosc2 .FPAccuracy .DEFAULT )
12511252 dtype = kwargs .pop ("dtype" , None )
12521253 where : dict | None = kwargs .pop ("_where_args" , None )
12531254 if where is not None :
@@ -1306,11 +1307,10 @@ def fast_eval( # noqa: C901
13061307 if use_miniexpr :
13071308 cparams = kwargs .pop ("cparams" , blosc2 .CParams ())
13081309 # All values will be overwritten, so we can use an uninitialized array
1309- fp_accuracy = kwargs .pop ("fp_accuracy" , blosc2 .FPAccuracy .DEFAULT )
13101310 res_eval = blosc2 .uninit (shape , dtype , chunks = chunks , blocks = blocks , cparams = cparams , ** kwargs )
13111311 try :
13121312 res_eval ._set_pref_expr (expression , operands , fp_accuracy = fp_accuracy )
1313- print ("expr->miniexpr:" , expression )
1313+ print ("expr->miniexpr:" , expression , fp_accuracy )
13141314 # Data to compress is fetched from operands, so it can be uninitialized here
13151315 data = np .empty (res_eval .schunk .chunksize , dtype = np .uint8 )
13161316 # Exercise prefilter for each chunk
@@ -1522,7 +1522,10 @@ def slices_eval( # noqa: C901
15221522 # Typically, we enter here when using UDFs, and out is a NumPy array.
15231523 # Use operands to get the shape and chunks
15241524 # operand will be a 'fake' NDArray just to get the necessary chunking information
1525+ fp_accuracy = kwargs .pop ("fp_accuracy" , None )
15251526 temp = blosc2 .empty (shape , dtype = dtype )
1527+ if fp_accuracy is not None :
1528+ kwargs ["fp_accuracy" ] = fp_accuracy
15261529 chunks = temp .chunks
15271530 del temp
15281531
@@ -1607,7 +1610,10 @@ def slices_eval( # noqa: C901
16071610 if "chunks" in kwargs and (where is not None and len (where ) < 2 and len (shape_ ) > 1 ):
16081611 # Remove the chunks argument if the where condition is not a tuple with two elements
16091612 kwargs .pop ("chunks" )
1613+ fp_accuracy = kwargs .pop ("fp_accuracy" , None )
16101614 out = blosc2 .empty (shape_ , dtype = dtype_ , ** kwargs )
1615+ if fp_accuracy is not None :
1616+ kwargs ["fp_accuracy" ] = fp_accuracy
16111617 # Check if the in out partitions are well-behaved (i.e. no padding)
16121618 behaved = blosc2 .are_partitions_behaved (out .shape , out .chunks , out .blocks )
16131619 # Evaluate the expression using chunks of operands
@@ -1892,6 +1898,7 @@ def reduce_slices( # noqa: C901
18921898 ne_args : dict = kwargs .pop ("_ne_args" , {})
18931899 if ne_args is None :
18941900 ne_args = {}
1901+ fp_accuracy = kwargs .pop ("fp_accuracy" , blosc2 .FPAccuracy .DEFAULT )
18951902 where : dict | None = kwargs .pop ("_where_args" , None )
18961903 reduce_op = reduce_args .pop ("op" )
18971904 reduce_op_str = reduce_args .pop ("op_str" , None )
@@ -2014,7 +2021,6 @@ def reduce_slices( # noqa: C901
20142021 if use_miniexpr :
20152022 # Experiments say that not splitting is best (at least on Apple Silicon M4 Pro)
20162023 cparams = kwargs .pop ("cparams" , blosc2 .CParams (splitmode = blosc2 .SplitMode .NEVER_SPLIT ))
2017- fp_accuracy = kwargs .pop ("fp_accuracy" , blosc2 .FPAccuracy .DEFAULT )
20182024 # Create a fake NDArray just to drive the miniexpr evaluation (values won't be used)
20192025 res_eval = blosc2 .uninit (shape , dtype , chunks = chunks , blocks = blocks , cparams = cparams , ** kwargs )
20202026 # Compute the number of blocks in the result
@@ -2044,7 +2050,7 @@ def reduce_slices( # noqa: C901
20442050 else :
20452051 expression_miniexpr = f"{ reduce_op_str } ({ expression } )"
20462052 res_eval ._set_pref_expr (expression_miniexpr , operands , fp_accuracy , aux_reduc )
2047- print ("expr->miniexpr:" , expression , reduce_op )
2053+ print ("expr->miniexpr:" , expression , reduce_op , fp_accuracy )
20482054 # Data won't even try to be compressed, so buffers can be unitialized and reused
20492055 data = np .empty (res_eval .schunk .chunksize , dtype = np .uint8 )
20502056 chunk_data = np .empty (res_eval .schunk .chunksize + blosc2 .MAX_OVERHEAD , dtype = np .uint8 )
@@ -2849,25 +2855,39 @@ def where(self, value1=None, value2=None):
28492855 new_expr ._dtype = dtype
28502856 return new_expr
28512857
2852- def sum (self , axis = None , dtype = None , keepdims = False , ** kwargs ):
2858+ def sum (
2859+ self ,
2860+ axis = None ,
2861+ dtype = None ,
2862+ keepdims = False ,
2863+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
2864+ ** kwargs ,
2865+ ):
28532866 reduce_args = {
28542867 "op" : ReduceOp .SUM ,
28552868 "op_str" : "sum" ,
28562869 "axis" : axis ,
28572870 "dtype" : dtype ,
28582871 "keepdims" : keepdims ,
28592872 }
2860- return self .compute (_reduce_args = reduce_args , ** kwargs )
2873+ return self .compute (_reduce_args = reduce_args , fp_accuracy = fp_accuracy , ** kwargs )
28612874
2862- def prod (self , axis = None , dtype = None , keepdims = False , ** kwargs ):
2875+ def prod (
2876+ self ,
2877+ axis = None ,
2878+ dtype = None ,
2879+ keepdims = False ,
2880+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
2881+ ** kwargs ,
2882+ ):
28632883 reduce_args = {
28642884 "op" : ReduceOp .PROD ,
28652885 "op_str" : "prod" ,
28662886 "axis" : axis ,
28672887 "dtype" : dtype ,
28682888 "keepdims" : keepdims ,
28692889 }
2870- return self .compute (_reduce_args = reduce_args , ** kwargs )
2890+ return self .compute (_reduce_args = reduce_args , fp_accuracy = fp_accuracy , ** kwargs )
28712891
28722892 def get_num_elements (self , axis , item ):
28732893 if hasattr (self , "_where_args" ) and len (self ._where_args ) == 1 :
@@ -2889,9 +2909,22 @@ def get_num_elements(self, axis, item):
28892909 axis = tuple (a if a >= 0 else a + len (shape ) for a in axis ) # handle negative indexing
28902910 return math .prod ([shape [i ] for i in axis ])
28912911
2892- def mean (self , axis = None , dtype = None , keepdims = False , ** kwargs ):
2912+ def mean (
2913+ self ,
2914+ axis = None ,
2915+ dtype = None ,
2916+ keepdims = False ,
2917+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
2918+ ** kwargs ,
2919+ ):
28932920 item = kwargs .pop ("item" , ())
2894- total_sum = self .sum (axis = axis , dtype = dtype , keepdims = keepdims , item = item )
2921+ total_sum = self .sum (
2922+ axis = axis ,
2923+ dtype = dtype ,
2924+ keepdims = keepdims ,
2925+ item = item ,
2926+ fp_accuracy = fp_accuracy ,
2927+ )
28952928 num_elements = self .get_num_elements (axis , item )
28962929 if num_elements == 0 :
28972930 raise ValueError ("mean of an empty array is not defined" )
@@ -2904,17 +2937,25 @@ def mean(self, axis=None, dtype=None, keepdims=False, **kwargs):
29042937 out = blosc2 .asarray (out , ** kwargs )
29052938 return out
29062939
2907- def std (self , axis = None , dtype = None , keepdims = False , ddof = 0 , ** kwargs ):
2940+ def std (
2941+ self ,
2942+ axis = None ,
2943+ dtype = None ,
2944+ keepdims = False ,
2945+ ddof = 0 ,
2946+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
2947+ ** kwargs ,
2948+ ):
29082949 item = kwargs .pop ("item" , ())
29092950 if item == (): # fast path
2910- mean_value = self .mean (axis = axis , dtype = dtype , keepdims = True )
2951+ mean_value = self .mean (axis = axis , dtype = dtype , keepdims = True , fp_accuracy = fp_accuracy )
29112952 expr = (self - mean_value ) ** 2
29122953 else :
2913- mean_value = self .mean (axis = axis , dtype = dtype , keepdims = True , item = item )
2954+ mean_value = self .mean (axis = axis , dtype = dtype , keepdims = True , item = item , fp_accuracy = fp_accuracy )
29142955 # TODO: Not optimal because we load the whole slice in memory. Would have to write
29152956 # a bespoke std function that executed within slice_eval to avoid this probably.
29162957 expr = (self .slice (item ) - mean_value ) ** 2
2917- out = expr .mean (axis = axis , dtype = dtype , keepdims = keepdims )
2958+ out = expr .mean (axis = axis , dtype = dtype , keepdims = keepdims , fp_accuracy = fp_accuracy )
29182959 if ddof != 0 :
29192960 num_elements = self .get_num_elements (axis , item )
29202961 out = np .sqrt (out * num_elements / (num_elements - ddof ))
@@ -2928,17 +2969,25 @@ def std(self, axis=None, dtype=None, keepdims=False, ddof=0, **kwargs):
29282969 out = blosc2 .asarray (out , ** kwargs )
29292970 return out
29302971
2931- def var (self , axis = None , dtype = None , keepdims = False , ddof = 0 , ** kwargs ):
2972+ def var (
2973+ self ,
2974+ axis = None ,
2975+ dtype = None ,
2976+ keepdims = False ,
2977+ ddof = 0 ,
2978+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
2979+ ** kwargs ,
2980+ ):
29322981 item = kwargs .pop ("item" , ())
29332982 if item == (): # fast path
2934- mean_value = self .mean (axis = axis , dtype = dtype , keepdims = True )
2983+ mean_value = self .mean (axis = axis , dtype = dtype , keepdims = True , fp_accuracy = fp_accuracy )
29352984 expr = (self - mean_value ) ** 2
29362985 else :
2937- mean_value = self .mean (axis = axis , dtype = dtype , keepdims = True , item = item )
2986+ mean_value = self .mean (axis = axis , dtype = dtype , keepdims = True , item = item , fp_accuracy = fp_accuracy )
29382987 # TODO: Not optimal because we load the whole slice in memory. Would have to write
29392988 # a bespoke var function that executed within slice_eval to avoid this probably.
29402989 expr = (self .slice (item ) - mean_value ) ** 2
2941- out = expr .mean (axis = axis , dtype = dtype , keepdims = keepdims )
2990+ out = expr .mean (axis = axis , dtype = dtype , keepdims = keepdims , fp_accuracy = fp_accuracy )
29422991 if ddof != 0 :
29432992 num_elements = self .get_num_elements (axis , item )
29442993 out = out * num_elements / (num_elements - ddof )
@@ -2950,57 +2999,93 @@ def var(self, axis=None, dtype=None, keepdims=False, ddof=0, **kwargs):
29502999 out = blosc2 .asarray (out , ** kwargs )
29513000 return out
29523001
2953- def min (self , axis = None , keepdims = False , ** kwargs ):
3002+ def min (
3003+ self ,
3004+ axis = None ,
3005+ keepdims = False ,
3006+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
3007+ ** kwargs ,
3008+ ):
29543009 reduce_args = {
29553010 "op" : ReduceOp .MIN ,
29563011 "op_str" : "min" ,
29573012 "axis" : axis ,
29583013 "keepdims" : keepdims ,
29593014 }
2960- return self .compute (_reduce_args = reduce_args , ** kwargs )
3015+ return self .compute (_reduce_args = reduce_args , fp_accuracy = fp_accuracy , ** kwargs )
29613016
2962- def max (self , axis = None , keepdims = False , ** kwargs ):
3017+ def max (
3018+ self ,
3019+ axis = None ,
3020+ keepdims = False ,
3021+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
3022+ ** kwargs ,
3023+ ):
29633024 reduce_args = {
29643025 "op" : ReduceOp .MAX ,
29653026 "op_str" : "max" ,
29663027 "axis" : axis ,
29673028 "keepdims" : keepdims ,
29683029 }
2969- return self .compute (_reduce_args = reduce_args , ** kwargs )
3030+ return self .compute (_reduce_args = reduce_args , fp_accuracy = fp_accuracy , ** kwargs )
29703031
2971- def any (self , axis = None , keepdims = False , ** kwargs ):
3032+ def any (
3033+ self ,
3034+ axis = None ,
3035+ keepdims = False ,
3036+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
3037+ ** kwargs ,
3038+ ):
29723039 reduce_args = {
29733040 "op" : ReduceOp .ANY ,
29743041 "op_str" : "any" ,
29753042 "axis" : axis ,
29763043 "keepdims" : keepdims ,
29773044 }
2978- return self .compute (_reduce_args = reduce_args , ** kwargs )
3045+ return self .compute (_reduce_args = reduce_args , fp_accuracy = fp_accuracy , ** kwargs )
29793046
2980- def all (self , axis = None , keepdims = False , ** kwargs ):
3047+ def all (
3048+ self ,
3049+ axis = None ,
3050+ keepdims = False ,
3051+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
3052+ ** kwargs ,
3053+ ):
29813054 reduce_args = {
29823055 "op" : ReduceOp .ALL ,
29833056 "op_str" : "all" ,
29843057 "axis" : axis ,
29853058 "keepdims" : keepdims ,
29863059 }
2987- return self .compute (_reduce_args = reduce_args , ** kwargs )
3060+ return self .compute (_reduce_args = reduce_args , fp_accuracy = fp_accuracy , ** kwargs )
29883061
2989- def argmax (self , axis = None , keepdims = False , ** kwargs ):
3062+ def argmax (
3063+ self ,
3064+ axis = None ,
3065+ keepdims = False ,
3066+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
3067+ ** kwargs ,
3068+ ):
29903069 reduce_args = {
29913070 "op" : ReduceOp .ARGMAX ,
29923071 "axis" : axis ,
29933072 "keepdims" : keepdims ,
29943073 }
2995- return self .compute (_reduce_args = reduce_args , ** kwargs )
3074+ return self .compute (_reduce_args = reduce_args , fp_accuracy = fp_accuracy , ** kwargs )
29963075
2997- def argmin (self , axis = None , keepdims = False , ** kwargs ):
3076+ def argmin (
3077+ self ,
3078+ axis = None ,
3079+ keepdims = False ,
3080+ fp_accuracy : blosc2 .FPAccuracy = blosc2 .FPAccuracy .DEFAULT ,
3081+ ** kwargs ,
3082+ ):
29983083 reduce_args = {
29993084 "op" : ReduceOp .ARGMIN ,
30003085 "axis" : axis ,
30013086 "keepdims" : keepdims ,
30023087 }
3003- return self .compute (_reduce_args = reduce_args , ** kwargs )
3088+ return self .compute (_reduce_args = reduce_args , fp_accuracy = fp_accuracy , ** kwargs )
30043089
30053090 def _eval_constructor (self , expression , constructor , operands ):
30063091 """Evaluate a constructor function inside a string expression."""
@@ -3174,6 +3259,7 @@ def compute(
31743259 kwargs ["_ne_args" ] = self ._ne_args
31753260 if hasattr (self , "_where_args" ):
31763261 kwargs ["_where_args" ] = self ._where_args
3262+ kwargs .setdefault ("fp_accuracy" , fp_accuracy )
31773263 kwargs ["dtype" ] = self .dtype
31783264 kwargs ["shape" ] = self .shape
31793265 if hasattr (self , "_indices" ):
@@ -3192,7 +3278,15 @@ def compute(
31923278 and not isinstance (result , blosc2 .NDArray )
31933279 ):
31943280 # Get rid of all the extra kwargs that are not accepted by blosc2.asarray
3195- kwargs_not_accepted = {"_where_args" , "_indices" , "_order" , "_ne_args" , "dtype" , "shape" }
3281+ kwargs_not_accepted = {
3282+ "_where_args" ,
3283+ "_indices" ,
3284+ "_order" ,
3285+ "_ne_args" ,
3286+ "dtype" ,
3287+ "shape" ,
3288+ "fp_accuracy" ,
3289+ }
31963290 kwargs = {key : value for key , value in kwargs .items () if key not in kwargs_not_accepted }
31973291 result = blosc2 .asarray (result , ** kwargs )
31983292 return result
0 commit comments