4141from blosc2 import compute_chunks_blocks
4242from blosc2 .info import InfoReporter
4343from blosc2 .ndarray import (
44- _check_allowed_dtypes ,
4544 get_chunks_idx ,
4645 get_intersecting_chunks ,
4746 is_inside_new_expr ,
48- local_ufunc_map ,
4947 process_key ,
50- ufunc_map ,
51- ufunc_map_1param ,
5248)
5349
5450if not blosc2 .IS_WASM :
@@ -256,7 +252,7 @@ class LazyArrayEnum(Enum):
256252 UDF = 1
257253
258254
259- class LazyArray (ABC ):
255+ class LazyArray (ABC , blosc2 . Operand ):
260256 @abstractmethod
261257 def indices (self , order : str | list [str ] | None = None ) -> blosc2 .LazyArray :
262258 """
@@ -436,68 +432,6 @@ def save(self, **kwargs: Any) -> None:
436432 """
437433 pass
438434
439- @property
440- @abstractmethod
441- def dtype (self ) -> np .dtype :
442- """
443- Get the data type of the :ref:`LazyArray`.
444-
445- Returns
446- -------
447- out: np.dtype
448- The data type of the :ref:`LazyArray`.
449- """
450- pass
451-
452- @property
453- @abstractmethod
454- def shape (self ) -> tuple [int ]:
455- """
456- Get the shape of the :ref:`LazyArray`.
457-
458- Returns
459- -------
460- out: tuple
461- The shape of the :ref:`LazyArray`.
462- """
463- pass
464-
465- @property
466- @abstractmethod
467- def ndim (self ) -> int :
468- """
469- Get the number of dimensions of the :ref:`LazyArray`.
470-
471- Returns
472- -------
473- out: int
474- The number of dimensions of the :ref:`LazyArray`.
475- """
476- pass
477-
478- @property
479- @abstractmethod
480- def info (self ) -> InfoReporter :
481- """
482- Get information about the :ref:`LazyArray`.
483-
484- Returns
485- -------
486- out: InfoReporter
487- A printable class with information about the :ref:`LazyArray`.
488- """
489- pass
490-
491- # Provide minimal __array_interface__ to allow NumPy to work with this object
492- @property
493- def __array_interface__ (self ):
494- return {
495- "shape" : self .shape ,
496- "typestr" : self .dtype .str ,
497- "data" : self [()],
498- "version" : 3 ,
499- }
500-
501435 # Provide a way to serialize the LazyArray
502436 def to_cframe (self ) -> bytes :
503437 """
@@ -510,11 +444,6 @@ def to_cframe(self) -> bytes:
510444 """
511445 return self .compute ().to_cframe ()
512446
513- def __bool__ (self ) -> bool :
514- if math .prod (self .shape ) != 1 :
515- raise ValueError (f"The truth value of a LazyArray of shape { self .shape } is ambiguous." )
516- return self [()].__bool__ ()
517-
518447
519448def convert_inputs (inputs ):
520449 if not inputs or len (inputs ) == 0 :
@@ -2263,15 +2192,7 @@ def __init__(self, new_op): # noqa: C901
22632192 return
22642193 value1 , op , value2 = new_op
22652194 dtype_ = infer_dtype (op , value1 , value2 ) # perform some checks
2266- if value2 is None :
2267- if isinstance (value1 , LazyExpr ):
2268- self .expression = f"{ op } ({ value1 .expression } )"
2269- self .operands = value1 .operands
2270- else :
2271- self .operands = {"o0" : value1 }
2272- self .expression = "o0" if op is None else f"{ op } (o0)"
2273- return
2274- elif op in (
2195+ if op in (
22752196 "arctan2" ,
22762197 "contains" ,
22772198 "pow" ,
@@ -2283,7 +2204,7 @@ def __init__(self, new_op): # noqa: C901
22832204 "minimum" ,
22842205 ):
22852206 if np .isscalar (value1 ) and np .isscalar (value2 ):
2286- self .expression = f"{ op } (o0, o1 )"
2207+ self .expression = f"{ op } ({ value1 } , { value2 } )"
22872208 elif np .isscalar (value2 ):
22882209 self .operands = {"o0" : value1 }
22892210 self .expression = f"{ op } (o0, { value2 } )"
@@ -2294,6 +2215,22 @@ def __init__(self, new_op): # noqa: C901
22942215 self .operands = {"o0" : value1 , "o1" : value2 }
22952216 self .expression = f"{ op } (o0, o1)"
22962217 return
2218+ elif value2 is None :
2219+ if isinstance (value1 , LazyExpr ):
2220+ self .expression = f"{ op } ({ value1 .expression } )"
2221+ self .operands = value1 .operands
2222+ else :
2223+ self .operands = {"o0" : value1 }
2224+ self .expression = "o0" if op is None else f"{ op } (o0)"
2225+ return
2226+ elif isinstance (value1 , LazyExpr ) or isinstance (value2 , LazyExpr ):
2227+ if isinstance (value1 , LazyExpr ):
2228+ newexpr = value1 .update_expr (new_op )
2229+ else :
2230+ newexpr = value2 .update_expr (new_op )
2231+ self .expression = newexpr .expression
2232+ self .operands = newexpr .operands
2233+ return
22972234
22982235 self ._dtype = dtype_
22992236 if np .isscalar (value1 ) and np .isscalar (value2 ):
@@ -2314,16 +2251,6 @@ def __init__(self, new_op): # noqa: C901
23142251 if value1 is value2 :
23152252 self .operands = {"o0" : value1 }
23162253 self .expression = f"(o0 { op } o0)"
2317- elif isinstance (value1 , LazyExpr ) or isinstance (value2 , LazyExpr ):
2318- if isinstance (value1 , LazyExpr ):
2319- self .expression = value1 .expression
2320- self .operands = {"o0" : value2 }
2321- else :
2322- self .expression = value2 .expression
2323- self .operands = {"o0" : value1 }
2324- newexpr = self .update_expr (new_op )
2325- self .expression = newexpr .expression
2326- self .operands = newexpr .operands
23272254 else :
23282255 # This is the very first time that a LazyExpr is formed from two operands
23292256 # that are not LazyExpr themselves
@@ -2385,28 +2312,29 @@ def update_expr(self, new_op): # noqa: C901
23852312 new_operands , dup_op = fuse_operands (value1 .operands , value2 .operands )
23862313 # Take expression 2 and rebase the operands while removing duplicates
23872314 new_expr = fuse_expressions (value2 .expression , len (value1 .operands ), dup_op )
2388- expression = f"({ self .expression } { op } { new_expr } )"
2315+ expression = f"({ value1 .expression } { op } { new_expr } )"
2316+ self .operands = value1 .operands
23892317 elif isinstance (value1 , LazyExpr ):
23902318 if op == "~" :
2391- expression = f"({ op } { self .expression } )"
2319+ expression = f"({ op } { value1 .expression } )"
23922320 elif np .isscalar (value2 ):
2393- expression = f"({ self .expression } { op } { value2 } )"
2321+ expression = f"({ value1 .expression } { op } { value2 } )"
23942322 elif hasattr (value2 , "shape" ) and value2 .shape == ():
2395- expression = f"({ self .expression } { op } { value2 [()]} )"
2323+ expression = f"({ value1 .expression } { op } { value2 [()]} )"
23962324 else :
23972325 operand_to_key = {id (v ): k for k , v in value1 .operands .items ()}
23982326 try :
23992327 op_name = operand_to_key [id (value2 )]
24002328 except KeyError :
2401- op_name = f"o{ len (self .operands )} "
2329+ op_name = f"o{ len (value1 .operands )} "
24022330 new_operands = {op_name : value2 }
2403- expression = f"({ self .expression } { op } { op_name } )"
2331+ expression = f"({ value1 .expression } { op } { op_name } )"
24042332 self .operands = value1 .operands
24052333 else :
24062334 if np .isscalar (value1 ):
2407- expression = f"({ value1 } { op } { self .expression } )"
2335+ expression = f"({ value1 } { op } { value2 .expression } )"
24082336 elif hasattr (value1 , "shape" ) and value1 .shape == ():
2409- expression = f"({ value1 [()]} { op } { self .expression } )"
2337+ expression = f"({ value1 [()]} { op } { value2 .expression } )"
24102338 else :
24112339 operand_to_key = {id (v ): k for k , v in value2 .operands .items ()}
24122340 try :
@@ -2415,9 +2343,9 @@ def update_expr(self, new_op): # noqa: C901
24152343 op_name = f"o{ len (value2 .operands )} "
24162344 new_operands = {op_name : value1 }
24172345 if op == "[]" : # syntactic sugar for slicing
2418- expression = f"({ op_name } [{ self .expression } ])"
2346+ expression = f"({ op_name } [{ value2 .expression } ])"
24192347 else :
2420- expression = f"({ op_name } { op } { self .expression } )"
2348+ expression = f"({ op_name } { op } { value2 .expression } )"
24212349 self .operands = value2 .operands
24222350 # Return a new expression
24232351 operands = self .operands | new_operands
@@ -2521,107 +2449,6 @@ def blocks(self):
25212449 self ._chunks , self ._blocks = compute_chunks_blocks (self .shape , None , None , dtype = self .dtype )
25222450 return self ._blocks
25232451
2524- def __array_ufunc__ (self , ufunc , method , * inputs , ** kwargs ):
2525- # Handle operations at the array level
2526- if method != "__call__" :
2527- return NotImplemented
2528-
2529- if ufunc in local_ufunc_map :
2530- return local_ufunc_map [ufunc ](* inputs )
2531-
2532- if ufunc in ufunc_map :
2533- value = inputs [0 ] if inputs [1 ] is self else inputs [1 ]
2534- _check_allowed_dtypes (value )
2535- return blosc2 .LazyExpr (new_op = (value , ufunc_map [ufunc ], self ))
2536-
2537- if ufunc in ufunc_map_1param :
2538- value = inputs [0 ]
2539- _check_allowed_dtypes (value )
2540- return blosc2 .LazyExpr (new_op = (value , ufunc_map_1param [ufunc ], None ))
2541-
2542- return NotImplemented
2543-
2544- def __neg__ (self ):
2545- return self .update_expr (new_op = (0 , "-" , self ))
2546-
2547- def __add__ (self , value ):
2548- return self .update_expr (new_op = (self , "+" , value ))
2549-
2550- def __iadd__ (self , other ):
2551- return self .update_expr (new_op = (self , "+" , other ))
2552-
2553- def __radd__ (self , value ):
2554- return self .update_expr (new_op = (value , "+" , self ))
2555-
2556- def __sub__ (self , value ):
2557- return self .update_expr (new_op = (self , "-" , value ))
2558-
2559- def __isub__ (self , value ):
2560- return self .update_expr (new_op = (self , "-" , value ))
2561-
2562- def __rsub__ (self , value ):
2563- return self .update_expr (new_op = (value , "-" , self ))
2564-
2565- def __mul__ (self , value ):
2566- return self .update_expr (new_op = (self , "*" , value ))
2567-
2568- def __imul__ (self , value ):
2569- return self .update_expr (new_op = (self , "*" , value ))
2570-
2571- def __rmul__ (self , value ):
2572- return self .update_expr (new_op = (value , "*" , self ))
2573-
2574- def __truediv__ (self , value ):
2575- return self .update_expr (new_op = (self , "/" , value ))
2576-
2577- def __itruediv__ (self , value ):
2578- return self .update_expr (new_op = (self , "/" , value ))
2579-
2580- def __rtruediv__ (self , value ):
2581- return self .update_expr (new_op = (value , "/" , self ))
2582-
2583- def __and__ (self , value ):
2584- return self .update_expr (new_op = (self , "&" , value ))
2585-
2586- def __rand__ (self , value ):
2587- return self .update_expr (new_op = (value , "&" , self ))
2588-
2589- def __or__ (self , value ):
2590- return self .update_expr (new_op = (self , "|" , value ))
2591-
2592- def __ror__ (self , value ):
2593- return self .update_expr (new_op = (value , "|" , self ))
2594-
2595- def __invert__ (self ):
2596- return self .update_expr (new_op = (self , "~" , None ))
2597-
2598- def __pow__ (self , value ):
2599- return self .update_expr (new_op = (self , "**" , value ))
2600-
2601- def __rpow__ (self , value ):
2602- return self .update_expr (new_op = (value , "**" , self ))
2603-
2604- def __ipow__ (self , value ):
2605- return self .update_expr (new_op = (self , "**" , value ))
2606-
2607- def __lt__ (self , value ):
2608- return self .update_expr (new_op = (self , "<" , value ))
2609-
2610- def __le__ (self , value ):
2611- return self .update_expr (new_op = (self , "<=" , value ))
2612-
2613- def __eq__ (self , value ):
2614- return self .update_expr (new_op = (self , "==" , value ))
2615-
2616- def __ne__ (self , value ):
2617- return self .update_expr (new_op = (self , "!=" , value ))
2618-
2619- def __gt__ (self , value ):
2620- return self .update_expr (new_op = (self , ">" , value ))
2621-
2622- def __ge__ (self , value ):
2623- return self .update_expr (new_op = (self , ">=" , value ))
2624-
26252452 def where (self , value1 = None , value2 = None ):
26262453 """
26272454 Select value1 or value2 values based on the condition of the current expression.
0 commit comments