@@ -1767,6 +1767,95 @@ def make_func_for_chunk_size(chunk_size):
17671767
17681768# {{{ shape manipulation
17691769
1770+ def concatenate (arrays , axis = 0 , allocator = None ):
1771+ """
1772+ Join a sequence of arrays along an existing axis.
1773+ :arg arrays: A sequnce of :class:`GPUArray`.
1774+ :arg axis: Index of the dimension of the new axis in the result array.
1775+ Can be -1, for the new axis to be last dimension.
1776+ :returns: :class:`GPUArray`
1777+ """
1778+ # implementation is borrowed from pyopencl.array.concatenate()
1779+ # {{{ find properties of result array
1780+
1781+ shape = None
1782+
1783+ def shape_except_axis (ary : GPUArray ):
1784+ return ary .shape [:axis ] + ary .shape [axis + 1 :]
1785+
1786+ for i_ary , ary in enumerate (arrays ):
1787+ allocator = allocator or ary .allocator
1788+
1789+ if shape is None :
1790+ # first array
1791+ shape = list (ary .shape )
1792+
1793+ else :
1794+ if len (ary .shape ) != len (shape ):
1795+ raise ValueError ("%d'th array has different number of axes "
1796+ "(should have %d, has %d)"
1797+ % (i_ary , len (ary .shape ), len (shape )))
1798+
1799+ if (ary .ndim != arrays [0 ].ndim
1800+ or shape_except_axis (ary ) != shape_except_axis (arrays [0 ])):
1801+ raise ValueError ("%d'th array has residual not matching "
1802+ "other arrays" % i_ary )
1803+
1804+ shape [axis ] += ary .shape [axis ]
1805+
1806+ # }}}
1807+
1808+ shape = tuple (shape )
1809+ dtype = np .find_common_type ([ary .dtype for ary in arrays ], [])
1810+ result = empty (shape , dtype , allocator = allocator )
1811+
1812+ full_slice = (slice (None ),) * len (shape )
1813+
1814+ base_idx = 0
1815+ for ary in arrays :
1816+ my_len = ary .shape [axis ]
1817+ result [full_slice [:axis ] + (slice (base_idx , base_idx + my_len ),) + full_slice [axis + 1 :]] = ary
1818+ base_idx += my_len
1819+
1820+ return result
1821+
1822+
1823+ def stack (arrays , axis = 0 , allocator = None ):
1824+ """
1825+ Join a sequence of arrays along a new axis.
1826+ :arg arrays: A sequnce of :class:`GPUArray`.
1827+ :arg axis: Index of the dimension of the new axis in the result array.
1828+ Can be -1, for the new axis to be last dimension.
1829+ :returns: :class:`GPUArray`
1830+ """
1831+ # implementation is borrowed from pyopencl.array.stack()
1832+ allocator = allocator or arrays [0 ].allocator
1833+
1834+ if not arrays :
1835+ raise ValueError ("need at least one array to stack" )
1836+
1837+ input_shape = arrays [0 ].shape
1838+ input_ndim = arrays [0 ].ndim
1839+ axis = input_ndim if axis == - 1 else axis
1840+
1841+ if not all (ary .shape == input_shape for ary in arrays [1 :]):
1842+ raise ValueError ("arrays must have the same shape" )
1843+
1844+ if not (0 <= axis <= input_ndim ):
1845+ raise ValueError ("invalid axis" )
1846+
1847+ result_shape = input_shape [:axis ] + (len (arrays ),) + input_shape [axis :]
1848+ result = empty (shape = result_shape ,
1849+ dtype = np .result_type (* (ary .dtype for ary in arrays )),
1850+ allocator = allocator , order = "C" if axis == 0 else "F" )
1851+
1852+ for i , ary in enumerate (arrays ):
1853+
1854+ idx = (slice (None ),)* axis + (i ,) + (slice (None ),)* (input_ndim - axis )
1855+ result [idx ] = ary
1856+
1857+ return result
1858+
17701859
17711860def transpose (a , axes = None ):
17721861 """Permute the dimensions of an array.
0 commit comments