11
11
import builtins
12
12
import inspect
13
13
import math
14
+ import warnings
14
15
from collections import OrderedDict , namedtuple
15
16
from functools import reduce
16
17
from itertools import product
@@ -1412,6 +1413,13 @@ def blocksize(self) -> int:
1412
1413
"""
1413
1414
return self ._schunk .blocksize
1414
1415
1416
+ @property
1417
+ def T (self ):
1418
+ """Return the transpose of a 2-dimensional array."""
1419
+ if self .ndim != 2 :
1420
+ raise ValueError ("This property only works for 2-dimensional arrays." )
1421
+ return permute_dims (self )
1422
+
1415
1423
def __getitem__ ( # noqa: C901
1416
1424
self ,
1417
1425
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:
3878
3886
return result .squeeze ()
3879
3887
3880
3888
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
+
3881
3997
def transpose (x , ** kwargs : Any ) -> NDArray :
3882
3998
"""
3883
3999
Returns a Blosc2 NDArray with axes transposed.
@@ -3900,6 +4016,12 @@ def transpose(x, **kwargs: Any) -> NDArray:
3900
4016
----------
3901
4017
`numpy.transpose <https://numpy.org/doc/2.2/reference/generated/numpy.transpose.html>`_
3902
4018
"""
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
+ )
3903
4025
3904
4026
# If arguments are dimension < 2 they are returned
3905
4027
if np .isscalar (x ) or x .ndim < 2 :
@@ -3908,19 +4030,30 @@ def transpose(x, **kwargs: Any) -> NDArray:
3908
4030
# Validate arguments are dimension 2
3909
4031
if x .ndim > 2 :
3910
4032
raise ValueError ("Transposing arrays with dimension greater than 2 is not supported yet." )
4033
+ return permute_dims (x , ** kwargs )
3911
4034
3912
- n , m = x .shape
3913
- p , q = x .chunks
3914
- result = blosc2 .zeros ((m , n ), dtype = np .result_type (x ), ** kwargs )
3915
4035
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).
3922
4039
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 )
3924
4057
3925
4058
3926
4059
# Class for dealing with fields in an NDArray
0 commit comments