1111import builtins
1212import inspect
1313import math
14+ import warnings
1415import tempfile
1516from collections import OrderedDict , namedtuple
1617from functools import reduce
@@ -1420,6 +1421,13 @@ def blocksize(self) -> int:
14201421 """
14211422 return self ._schunk .blocksize
14221423
1424+ @property
1425+ def T (self ):
1426+ """Return the transpose of a 2-dimensional array."""
1427+ if self .ndim != 2 :
1428+ raise ValueError ("This property only works for 2-dimensional arrays." )
1429+ return permute_dims (self )
1430+
14231431 def __getitem__ ( # noqa: C901
14241432 self ,
14251433 key : int | slice | Sequence [slice | int ] | np .ndarray [np .bool_ ] | NDArray | blosc2 .LazyExpr | str ,
@@ -3878,6 +3886,114 @@ def matmul(x1: NDArray, x2: NDArray, **kwargs: Any) -> NDArray:
38783886 return result .squeeze ()
38793887
38803888
3889+ def permute_dims (arr : NDArray , axes : tuple [int ] | list [int ] | None = None , ** kwargs : Any ) -> NDArray :
3890+ """
3891+ Permutes the axes (dimensions) of an array.
3892+
3893+ Parameters
3894+ ----------
3895+ arr: :ref:`NDArray`
3896+ The input array.
3897+ axes: tuple[int], list[int], optional
3898+ The desired permutation of axes. If None, the axes are reversed by default.
3899+ If specified, axes must be a tuple or list representing a permutation of
3900+ ``[0, 1, ..., N-1]``, where ``N`` is the number of dimensions of the input array.
3901+ Negative indices are also supported. The *i*-th axis of the result will correspond
3902+ to the axis numbered ``axes[i]`` of the input.
3903+ kwargs: Any, optional
3904+ Keyword arguments that are supported by the :func:`empty` constructor.
3905+
3906+ Returns
3907+ -------
3908+ out: :ref:`NDArray`
3909+ A Blosc2 :ref:`NDArray` with axes transposed.
3910+
3911+ Raises
3912+ ------
3913+ ValueError
3914+ If ``axes`` is not a valid permutation of the dimensions of ``arr``.
3915+
3916+ References
3917+ ----------
3918+ `numpy.transpose <https://numpy.org/doc/2.2/reference/generated/numpy.transpose.html>`_
3919+
3920+ `permute_dims <https://data-apis.org/array-api/latest/API_specification/generated/array_api.permute_dims.html#permute-dims>`_
3921+
3922+ Examples
3923+ --------
3924+ For 2-D arrays it is the matrix transposition as usual:
3925+
3926+ >>> import blosc2
3927+ >>> a = blosc2.arange(1, 10).reshape((3, 3))
3928+ >>> a[:]
3929+ array([[1, 2, 3],
3930+ [4, 5, 6],
3931+ [7, 8, 9]])
3932+ >>> at = blosc2.permute_dims(a)
3933+ >>> at[:]
3934+ array([[1, 4, 7],
3935+ [2, 5, 8],
3936+ [3, 6, 9]])
3937+
3938+ For 3-D arrays:
3939+
3940+ >>> import blosc2
3941+ >>> a = blosc2.arange(1, 25).reshape((2, 3, 4))
3942+ >>> a[:]
3943+ array([[[ 1, 2, 3, 4],
3944+ [ 5, 6, 7, 8],
3945+ [ 9, 10, 11, 12]],
3946+ [[13, 14, 15, 16],
3947+ [17, 18, 19, 20],
3948+ [21, 22, 23, 24]]])
3949+
3950+
3951+
3952+ >>> at = blosc2.permute_dims(a, axes=(1, 0, 2))
3953+ >>> at[:]
3954+ array([[[ 1, 2, 3, 4],
3955+ [13, 14, 15, 16]],
3956+ [[ 5, 6, 7, 8],
3957+ [17, 18, 19, 20]],
3958+ [[ 9, 10, 11, 12],
3959+ [21, 22, 23, 24]]])
3960+
3961+ """
3962+
3963+ if np .isscalar (arr ) or arr .ndim < 2 :
3964+ return arr
3965+
3966+ if axes is None :
3967+ axes = range (arr .ndim )[::- 1 ]
3968+ else :
3969+ axes_transformed = tuple (axis if axis >= 0 else arr .ndim + axis for axis in axes )
3970+ if sorted (axes_transformed ) != list (range (arr .ndim )):
3971+ raise ValueError (f"axes { axes } is not a valid permutation of { arr .ndim } dimensions" )
3972+ axes = axes_transformed
3973+
3974+ new_shape = tuple (arr .shape [axis ] for axis in axes )
3975+ if "chunks" not in kwargs :
3976+ kwargs ["chunks" ] = tuple (arr .chunks [axis ] for axis in axes )
3977+
3978+ result = blosc2 .empty (shape = new_shape , dtype = arr .dtype , ** kwargs )
3979+
3980+ chunk_slices = [
3981+ [slice (start , builtins .min (dim , start + chunk )) for start in range (0 , dim , chunk )]
3982+ for dim , chunk in zip (arr .shape , arr .chunks , strict = False )
3983+ ]
3984+
3985+ block_counts = [len (s ) for s in chunk_slices ]
3986+ grid = np .indices (block_counts ).reshape (len (block_counts ), - 1 ).T
3987+
3988+ for idx in grid :
3989+ block_slices = tuple (chunk_slices [axis ][i ] for axis , i in enumerate (idx ))
3990+ block = arr [block_slices ]
3991+ target_slices = tuple (block_slices [axis ] for axis in axes )
3992+ result [target_slices ] = np .transpose (block , axes = axes ).copy ()
3993+
3994+ return result
3995+
3996+
38813997def transpose (x , ** kwargs : Any ) -> NDArray :
38823998 """
38833999 Returns a Blosc2 NDArray with axes transposed.
@@ -3900,6 +4016,12 @@ def transpose(x, **kwargs: Any) -> NDArray:
39004016 ----------
39014017 `numpy.transpose <https://numpy.org/doc/2.2/reference/generated/numpy.transpose.html>`_
39024018 """
4019+ warnings .warn (
4020+ "transpose is deprecated and will be removed in a future version. "
4021+ "Use matrix_transpose or permute_dims instead." ,
4022+ DeprecationWarning ,
4023+ stacklevel = 2 ,
4024+ )
39034025
39044026 # If arguments are dimension < 2 they are returned
39054027 if np .isscalar (x ) or x .ndim < 2 :
@@ -3908,19 +4030,30 @@ def transpose(x, **kwargs: Any) -> NDArray:
39084030 # Validate arguments are dimension 2
39094031 if x .ndim > 2 :
39104032 raise ValueError ("Transposing arrays with dimension greater than 2 is not supported yet." )
4033+ return permute_dims (x , ** kwargs )
39114034
3912- n , m = x .shape
3913- p , q = x .chunks
3914- result = blosc2 .zeros ((m , n ), dtype = np .result_type (x ), ** kwargs )
39154035
3916- for row in range (0 , n , p ):
3917- row_end = (row + p ) if (row + p ) < n else n
3918- for col in range (0 , m , q ):
3919- col_end = (col + q ) if (col + q ) < m else m
3920- aux = x [row :row_end , col :col_end ]
3921- result [col :col_end , row :row_end ] = np .transpose (aux ).copy ()
4036+ def matrix_transpose (arr : NDArray , ** kwargs : Any ) -> NDArray :
4037+ """
4038+ Transposes a matrix (or a stack of matrices).
39224039
3923- return result
4040+ Parameters
4041+ ----------
4042+ arr: :ref:`NDArray`
4043+ The input NDArray having shape ``(..., M, N)`` and whose innermost two dimensions form
4044+ ``MxN`` matrices.
4045+
4046+ Returns
4047+ -------
4048+ out: :ref:`NDArray`
4049+ A new :ref:`NDArray` containing the transpose for each matrix and having shape
4050+ ``(..., N, M)``.
4051+ """
4052+ axes = None
4053+ if not np .isscalar (arr ) and arr .ndim > 2 :
4054+ axes = list (range (arr .ndim ))
4055+ axes [- 2 ], axes [- 1 ] = axes [- 1 ], axes [- 2 ]
4056+ return permute_dims (arr , axes , ** kwargs )
39244057
39254058
39264059# Class for dealing with fields in an NDArray
0 commit comments