search.py 39.8 KB
Newer Older
1
#   Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
2 3 4 5 6 7 8 9 10 11 12 13
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
14 15 16

# TODO: define searching & indexing functions of a tensor

17
import numpy as np
18

Z
zhiboniu 已提交
19
import paddle
20
from paddle import _C_ops
21 22
from paddle.common_ops_import import VarDesc, Variable

23
from ..fluid.data_feeder import check_dtype, check_variable_and_dtype
24 25 26 27 28 29
from ..framework import (
    LayerHelper,
    convert_np_dtype_to_dtype_,
    core,
    in_dygraph_mode,
)
30

31 32
# from ..fluid.layers import has_inf  #DEFINE_ALIAS
# from ..fluid.layers import has_nan  #DEFINE_ALIAS
33

34 35
__all__ = []

36

37 38
def argsort(x, axis=-1, descending=False, name=None):
    """
39
    Sorts the input along the given axis, and returns the corresponding index tensor for the sorted output values. The default sort algorithm is ascending, if you want the sort algorithm to be descending, you must set the :attr:`descending` as True.
40 41 42 43 44 45

    Args:
        x(Tensor): An input N-D Tensor with type float32, float64, int16,
            int32, int64, uint8.
        axis(int, optional): Axis to compute indices along. The effective range
            is [-R, R), where R is Rank(x). when axis<0, it works the same way
C
Chen Long 已提交
46
            as axis+R. Default is -1.
47 48 49
        descending(bool, optional) : Descending is a flag, if set to true,
            algorithm will sort by descending order, else sort by
            ascending order. Default is false.
50
        name (str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
51 52 53 54 55 56

    Returns:
        Tensor: sorted indices(with the same shape as ``x``
        and with data type int64).

    Examples:
李灿 已提交
57

58
        .. code-block:: python
李灿 已提交
59

60
            import paddle
61

62 63 64 65 66
            x = paddle.to_tensor([[[5,8,9,5],
                                   [0,0,1,7],
                                   [6,9,2,4]],
                                  [[5,2,4,2],
                                   [4,7,7,9],
67
                                   [1,7,0,6]]],
68
                                dtype='float32')
C
Chen Long 已提交
69 70 71
            out1 = paddle.argsort(x, axis=-1)
            out2 = paddle.argsort(x, axis=0)
            out3 = paddle.argsort(x, axis=1)
72

N
Noel 已提交
73
            print(out1)
W
wawltor 已提交
74 75 76
            #[[[0 3 1 2]
            #  [0 1 2 3]
            #  [2 3 0 1]]
77
            # [[1 3 2 0]
W
wawltor 已提交
78 79
            #  [0 1 2 3]
            #  [2 0 3 1]]]
80

N
Noel 已提交
81
            print(out2)
W
wawltor 已提交
82 83 84 85 86 87
            #[[[0 1 1 1]
            #  [0 0 0 0]
            #  [1 1 1 0]]
            # [[1 0 0 0]
            #  [1 1 1 1]
            #  [0 0 0 1]]]
88

N
Noel 已提交
89
            print(out3)
W
wawltor 已提交
90 91 92 93 94 95
            #[[[1 1 1 2]
            #  [0 0 2 0]
            #  [2 2 0 1]]
            # [[2 0 2 0]
            #  [1 1 0 2]
            #  [0 2 1 1]]]
96
    """
H
hong 已提交
97
    if in_dygraph_mode():
98
        _, ids = _C_ops.argsort(x, axis, descending)
H
hong 已提交
99
        return ids
100 101 102 103 104 105 106
    else:
        check_variable_and_dtype(
            x,
            'x',
            ['float32', 'float64', 'int16', 'int32', 'int64', 'uint8'],
            'argsort',
        )
H
hong 已提交
107

108 109 110 111 112 113 114 115 116 117 118 119
        helper = LayerHelper("argsort", **locals())
        out = helper.create_variable_for_type_inference(
            dtype=x.dtype, stop_gradient=True
        )
        ids = helper.create_variable_for_type_inference(
            VarDesc.VarType.INT64, stop_gradient=True
        )
        helper.append_op(
            type='argsort',
            inputs={'X': x},
            outputs={'Out': out, 'Indices': ids},
            attrs={'axis': axis, 'descending': descending},
120
        )
121 122 123
        return ids


124
def argmax(x, axis=None, keepdim=False, dtype="int64", name=None):
125
    """
126
    Computes the indices of the max elements of the input tensor's
127 128 129
    element along the provided axis.

    Args:
W
wawltor 已提交
130
        x(Tensor): An input N-D Tensor with type float32, float64, int16,
131 132
            int32, int64, uint8.
        axis(int, optional): Axis to compute indices along. The effective range
W
wawltor 已提交
133 134
            is [-R, R), where R is x.ndim. when axis < 0, it works the same way
            as axis + R. Default is None, the input `x` will be into the flatten tensor, and selecting the min value index.
135
        keepdim(bool, optional): Whether to keep the given axis in output. If it is True, the dimensions will be same as input x and with size one in the axis. Otherwise the output dimentions is one fewer than x since the axis is squeezed. Default is False.
136
        dtype(str|np.dtype, optional): Data type of the output tensor which can
137
                    be int32, int64. The default value is ``int64`` , and it will
138
                    return the int64 indices.
139
        name (str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
140 141

    Returns:
142
        Tensor, return the tensor of int32 if set :attr:`dtype` is int32, otherwise return the tensor of int64.
143 144 145 146

    Examples:
        .. code-block:: python

W
wawltor 已提交
147
            import paddle
148

149 150 151
            x = paddle.to_tensor([[5,8,9,5],
                                 [0,0,1,7],
                                 [6,9,2,4]])
W
wawltor 已提交
152
            out1 = paddle.argmax(x)
N
Noel 已提交
153
            print(out1) # 2
154
            out2 = paddle.argmax(x, axis=0)
155
            print(out2)
156
            # [2, 2, 0, 1]
W
wawltor 已提交
157
            out3 = paddle.argmax(x, axis=-1)
158
            print(out3)
159 160 161 162
            # [2, 3, 1]
            out4 = paddle.argmax(x, axis=0, keepdim=True)
            print(out4)
            # [[2, 2, 0, 1]]
163
    """
164
    if axis is not None and not isinstance(axis, (int, Variable)):
165
        raise TypeError(
166
            "The type of 'axis'  must be int or Tensor or None in argmax, but received %s."
167 168
            % (type(axis))
        )
169

170 171 172 173
    if dtype is None:
        raise ValueError(
            "the value of 'dtype' in argmax could not be None, but received None"
        )
174

175
    var_dtype = convert_np_dtype_to_dtype_(dtype)
W
wawltor 已提交
176 177 178 179 180
    flatten = False
    if axis is None:
        flatten = True
        axis = 0

H
hong 已提交
181
    if in_dygraph_mode():
182
        return _C_ops.argmax(x, axis, keepdim, flatten, var_dtype)
183 184 185
    else:
        helper = LayerHelper("argmax", **locals())
        check_variable_and_dtype(
186
            x,
187 188 189
            'x',
            ['float32', 'float64', 'int16', 'int32', 'int64', 'uint8'],
            'paddle.argmax',
190
        )
191 192 193 194 195 196 197 198 199 200 201
        check_dtype(var_dtype, 'dtype', ['int32', 'int64'], 'argmin')
        attrs = {}
        out = helper.create_variable_for_type_inference(var_dtype)
        attrs['keepdims'] = keepdim
        attrs['axis'] = axis
        attrs['flatten'] = flatten
        attrs['dtype'] = var_dtype
        helper.append_op(
            type='arg_max', inputs={'X': x}, outputs={'Out': [out]}, attrs=attrs
        )
        out.stop_gradient = True
W
wawltor 已提交
202 203 204
        return out


205
def argmin(x, axis=None, keepdim=False, dtype="int64", name=None):
W
wawltor 已提交
206
    """
207
    Computes the indices of the min elements of the input tensor's
W
wawltor 已提交
208 209 210 211 212 213 214 215
    element along the provided axis.

    Args:
        x(Tensor): An input N-D Tensor with type float32, float64, int16,
            int32, int64, uint8.
        axis(int, optional): Axis to compute indices along. The effective range
            is [-R, R), where R is x.ndim. when axis < 0, it works the same way
            as axis + R. Default is None, the input `x` will be into the flatten tensor, and selecting the min value index.
216
        keepdim(bool, optional): Whether to keep the given axis in output. If it is True, the dimensions will be same as input x and with size one in the axis. Otherwise the output dimentions is one fewer than x since the axis is squeezed. Default is False.
217
        dtype(str, optional): Data type of the output tensor which can
218
                    be int32, int64. The default value is 'int64', and it will
W
wawltor 已提交
219
                    return the int64 indices.
220
        name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
221

W
wawltor 已提交
222
    Returns:
223
        Tensor, return the tensor of `int32` if set :attr:`dtype` is `int32`, otherwise return the tensor of `int64`.
W
wawltor 已提交
224 225 226

    Examples:
        .. code-block:: python
227

W
wawltor 已提交
228 229
            import paddle

230 231 232
            x =  paddle.to_tensor([[5,8,9,5],
                                     [0,0,1,7],
                                     [6,9,2,4]])
W
wawltor 已提交
233
            out1 = paddle.argmin(x)
N
Noel 已提交
234
            print(out1) # 4
235
            out2 = paddle.argmin(x, axis=0)
236
            print(out2)
237
            # [1, 1, 1, 2]
W
wawltor 已提交
238
            out3 = paddle.argmin(x, axis=-1)
239
            print(out3)
240 241 242 243
            # [0, 0, 2]
            out4 = paddle.argmin(x, axis=0, keepdim=True)
            print(out4)
            # [[1, 1, 1, 2]]
W
wawltor 已提交
244
    """
245
    if axis is not None and not isinstance(axis, (int, Variable)):
246
        raise TypeError(
247
            "The type of 'axis'  must be int or Tensor or None in argmin, but received %s."
248 249
            % (type(axis))
        )
250

251 252 253 254
    if dtype is None:
        raise ValueError(
            "the value of 'dtype' in argmin could not be None, but received None"
        )
255

256
    var_dtype = convert_np_dtype_to_dtype_(dtype)
W
wawltor 已提交
257
    flatten = False
258
    if axis is None:
W
wawltor 已提交
259 260 261
        flatten = True
        axis = 0

H
hong 已提交
262
    if in_dygraph_mode():
263
        return _C_ops.argmin(x, axis, keepdim, flatten, var_dtype)
264 265 266
    else:
        helper = LayerHelper("argmin", **locals())
        check_variable_and_dtype(
267
            x,
268 269 270
            'x',
            ['float32', 'float64', 'int16', 'int32', 'int64', 'uint8'],
            'paddle.argmin',
271
        )
272 273 274 275 276 277 278 279 280 281 282
        check_dtype(var_dtype, 'dtype', ['int32', 'int64'], 'argmin')
        out = helper.create_variable_for_type_inference(var_dtype)
        attrs = {}
        attrs['keepdims'] = keepdim
        attrs['axis'] = axis
        attrs['flatten'] = flatten
        attrs['dtype'] = var_dtype
        helper.append_op(
            type='arg_min', inputs={'X': x}, outputs={'Out': [out]}, attrs=attrs
        )
        out.stop_gradient = True
W
wawltor 已提交
283 284
        return out

285

286
def index_select(x, index, axis=0, name=None):
287
    """
S
swtkiwi 已提交
288

289 290 291 292
    Returns a new tensor which indexes the ``input`` tensor along dimension ``axis`` using
    the entries in ``index`` which is a Tensor. The returned tensor has the same number
    of dimensions as the original ``x`` tensor. The dim-th dimension has the same
    size as the length of ``index``; other dimensions have the same size as in the ``x`` tensor.
C
Chengmo 已提交
293

294
    Args:
295 296 297
        x (Tensor): The input Tensor to be operated. The data of ``x`` can be one of float32, float64, int32, int64.
        index (Tensor): The 1-D Tensor containing the indices to index. The data type of ``index`` must be int32 or int64.
        axis (int, optional): The dimension in which we index. Default: if None, the ``axis`` is 0.
298
        name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
299 300

    Returns:
301
        Tensor: A Tensor with same data type as ``x``.
302

303 304
    Examples:
        .. code-block:: python
305

306 307
            import paddle

308 309 310 311
            x = paddle.to_tensor([[1.0, 2.0, 3.0, 4.0],
                                  [5.0, 6.0, 7.0, 8.0],
                                  [9.0, 10.0, 11.0, 12.0]])
            index = paddle.to_tensor([0, 1, 1], dtype='int32')
312 313 314 315 316 317 318 319
            out_z1 = paddle.index_select(x=x, index=index)
            #[[1. 2. 3. 4.]
            # [5. 6. 7. 8.]
            # [5. 6. 7. 8.]]
            out_z2 = paddle.index_select(x=x, index=index, axis=1)
            #[[ 1.  2.  2.]
            # [ 5.  6.  6.]
            # [ 9. 10. 10.]]
320
    """
321

F
From00 已提交
322
    if in_dygraph_mode():
323
        return _C_ops.index_select(x, index, axis)
324 325 326 327 328 329 330 331 332 333 334 335 336 337
    else:
        helper = LayerHelper("index_select", **locals())
        check_variable_and_dtype(
            x,
            'x',
            ['float32', 'float64', 'int32', 'int64'],
            'paddle.tensor.search.index_select',
        )
        check_variable_and_dtype(
            index,
            'index',
            ['int32', 'int64'],
            'paddle.tensor.search.index_select',
        )
F
From00 已提交
338

339
        out = helper.create_variable_for_type_inference(x.dtype)
340

341 342 343 344 345 346 347
        helper.append_op(
            type='index_select',
            inputs={'X': x, 'Index': index},
            outputs={'Out': out},
            attrs={'dim': axis},
        )
        return out
348 349


350
def nonzero(x, as_tuple=False):
351
    """
352 353 354 355 356 357
    Return a tensor containing the indices of all non-zero elements of the `input`
    tensor. If as_tuple is True, return a tuple of 1-D tensors, one for each dimension
    in `input`, each containing the indices (in that dimension) of all non-zero elements
    of `input`. Given a n-Dimensional `input` tensor with shape [x_1, x_2, ..., x_n], If
    as_tuple is False, we can get a output tensor with shape [z, n], where `z` is the
    number of all non-zero elements in the `input` tensor. If as_tuple is True, we can get
358
    a 1-D tensor tuple of length `n`, and the shape of each 1-D tensor is [z, 1].
C
Chengmo 已提交
359

360
    Args:
361
        x (Tensor): The input tensor variable.
362
        as_tuple (bool, optional): Return type, Tensor or tuple of Tensor.
363 364

    Returns:
365
        Tensor. The data type is int64.
366 367

    Examples:
368

N
Noel 已提交
369
        .. code-block:: python
李灿 已提交
370

371
            import paddle
372 373

            x1 = paddle.to_tensor([[1.0, 0.0, 0.0],
N
Noel 已提交
374 375
                                   [0.0, 2.0, 0.0],
                                   [0.0, 0.0, 3.0]])
376 377
            x2 = paddle.to_tensor([0.0, 1.0, 0.0, 3.0])
            out_z1 = paddle.nonzero(x1)
N
Noel 已提交
378
            print(out_z1)
379 380 381 382 383
            #[[0 0]
            # [1 1]
            # [2 2]]
            out_z1_tuple = paddle.nonzero(x1, as_tuple=True)
            for out in out_z1_tuple:
N
Noel 已提交
384
                print(out)
385 386 387 388 389 390 391
            #[[0]
            # [1]
            # [2]]
            #[[0]
            # [1]
            # [2]]
            out_z2 = paddle.nonzero(x2)
N
Noel 已提交
392
            print(out_z2)
393 394 395 396
            #[[1]
            # [3]]
            out_z2_tuple = paddle.nonzero(x2, as_tuple=True)
            for out in out_z2_tuple:
N
Noel 已提交
397
                print(out)
398 399
            #[[1]
            # [3]]
N
Noel 已提交
400

401 402
    """
    list_out = []
403
    shape = x.shape
404 405
    rank = len(shape)

406
    if in_dygraph_mode():
407
        outs = _C_ops.nonzero(x)
408
    else:
409 410 411
        helper = LayerHelper("where_index", **locals())

        outs = helper.create_variable_for_type_inference(
412 413
            dtype=core.VarDesc.VarType.INT64
        )
414

415 416 417
        helper.append_op(
            type='where_index', inputs={'Condition': x}, outputs={'Out': [outs]}
        )
418 419 420 421 422 423 424 425

    if not as_tuple:
        return outs
    elif rank == 1:
        return tuple([outs])
    else:
        for i in range(rank):
            list_out.append(
426 427
                paddle.slice(outs, axes=[1], starts=[i], ends=[i + 1])
            )
428 429 430
        return tuple(list_out)


431
def sort(x, axis=-1, descending=False, name=None):
432
    """
S
swtkiwi 已提交
433

434
    Sorts the input along the given axis, and returns the sorted output tensor. The default sort algorithm is ascending, if you want the sort algorithm to be descending, you must set the :attr:`descending` as True.
C
Chengmo 已提交
435

436
    Args:
437
        x(Tensor): An input N-D Tensor with type float32, float64, int16,
438 439 440
            int32, int64, uint8.
        axis(int, optional): Axis to compute indices along. The effective range
            is [-R, R), where R is Rank(x). when axis<0, it works the same way
441
            as axis+R. Default is -1.
442 443 444
        descending(bool, optional) : Descending is a flag, if set to true,
            algorithm will sort by descending order, else sort by
            ascending order. Default is false.
445
        name (str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
446

447
    Returns:
W
wawltor 已提交
448
        Tensor: sorted tensor(with the same shape and data type as ``x``).
449
    Examples:
N
Noel 已提交
450

451
        .. code-block:: python
N
Noel 已提交
452

453
            import paddle
N
Noel 已提交
454

455 456 457 458 459
            x = paddle.to_tensor([[[5,8,9,5],
                                   [0,0,1,7],
                                   [6,9,2,4]],
                                  [[5,2,4,2],
                                   [4,7,7,9],
460
                                   [1,7,0,6]]],
461
                                 dtype='float32')
462 463 464
            out1 = paddle.sort(x=x, axis=-1)
            out2 = paddle.sort(x=x, axis=0)
            out3 = paddle.sort(x=x, axis=1)
N
Noel 已提交
465
            print(out1)
W
wawltor 已提交
466 467 468 469 470 471
            #[[[5. 5. 8. 9.]
            #  [0. 0. 1. 7.]
            #  [2. 4. 6. 9.]]
            # [[2. 2. 4. 5.]
            #  [4. 7. 7. 9.]
            #  [0. 1. 6. 7.]]]
N
Noel 已提交
472
            print(out2)
473
            #[[[5. 2. 4. 2.]
W
wawltor 已提交
474 475 476 477 478
            #  [0. 0. 1. 7.]
            #  [1. 7. 0. 4.]]
            # [[5. 8. 9. 5.]
            #  [4. 7. 7. 9.]
            #  [6. 9. 2. 6.]]]
N
Noel 已提交
479
            print(out3)
480
            #[[[0. 0. 1. 4.]
W
wawltor 已提交
481 482 483 484 485
            #  [5. 8. 2. 5.]
            #  [6. 9. 9. 7.]]
            # [[1. 2. 0. 2.]
            #  [4. 7. 4. 6.]
            #  [5. 7. 7. 9.]]]
486
    """
487
    if in_dygraph_mode():
488
        outs, _ = _C_ops.argsort(x, axis, descending)
489
        return outs
490 491 492 493
    else:
        helper = LayerHelper("sort", **locals())
        out = helper.create_variable_for_type_inference(
            dtype=x.dtype, stop_gradient=False
494
        )
495 496 497 498 499 500 501 502 503 504
        ids = helper.create_variable_for_type_inference(
            VarDesc.VarType.INT64, stop_gradient=True
        )
        helper.append_op(
            type='argsort',
            inputs={'X': x},
            outputs={'Out': out, 'Indices': ids},
            attrs={'axis': axis, 'descending': descending},
        )
        return out
C
Chengmo 已提交
505 506


507 508
def mode(x, axis=-1, keepdim=False, name=None):
    """
509
    Used to find values and indices of the modes at the optional axis.
510 511 512 513 514 515 516

    Args:
        x(Tensor): Tensor, an input N-D Tensor with type float32, float64, int32, int64.
        axis(int, optional): Axis to compute indices along. The effective range
            is [-R, R), where R is x.ndim. when axis < 0, it works the same way
            as axis + R. Default is -1.
        keepdim(bool, optional): Whether to keep the given axis in output. If it is True, the dimensions will be same as input x and with size one in the axis. Otherwise the output dimentions is one fewer than x since the axis is squeezed. Default is False.
517
        name (str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
518 519 520 521 522 523 524 525 526

    Returns:
        tuple(Tensor), return the values and indices. The value data type is the same as the input `x`. The indices data type is int64.

    Examples:

        .. code-block:: python

           import paddle
527

528 529 530 531 532 533 534 535
           tensor = paddle.to_tensor([[[1,2,2],[2,3,3]],[[0,5,5],[9,9,0]]], dtype=paddle.float32)
           res = paddle.mode(tensor, 2)
           print(res)
           # (Tensor(shape=[2, 2], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
           #   [[2., 3.],
           #    [5., 9.]]), Tensor(shape=[2, 2], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
           #   [[1, 1],
           #    [1, 0]]))
536

537
    """
538
    if in_dygraph_mode():
539
        return _C_ops.mode(x, axis, keepdim)
540 541 542 543 544 545
    else:
        helper = LayerHelper("mode", **locals())
        inputs = {"X": [x]}
        attrs = {}
        attrs['axis'] = axis
        attrs['keepdim'] = keepdim
546

547 548
        values = helper.create_variable_for_type_inference(dtype=x.dtype)
        indices = helper.create_variable_for_type_inference(dtype="int64")
549

550 551 552 553 554 555 556 557
        helper.append_op(
            type="mode",
            inputs=inputs,
            outputs={"Out": [values], "Indices": [indices]},
            attrs=attrs,
        )
        indices.stop_gradient = True
        return values, indices
558 559


R
ronnywang 已提交
560
def where(condition, x=None, y=None, name=None):
561
    r"""
562
    Return a Tensor of elements selected from either :attr:`x` or :attr:`y` according to corresponding elements of :attr:`condition`. Concretely,
R
ronnywang 已提交
563

564
    .. math::
C
Chengmo 已提交
565

566 567 568 569 570
        out_i =
        \begin{cases}
        x_i, & \text{if}  \ condition_i \  \text{is} \ True \\
        y_i, & \text{if}  \ condition_i \  \text{is} \ False \\
        \end{cases}.
C
Chengmo 已提交
571

572 573
    Notes:
        ``numpy.where(condition)`` is identical to ``paddle.nonzero(condition, as_tuple=True)``, please refer to :ref:`api_tensor_search_nonzero`.
574

575
    Args:
576 577 578 579
        condition (Tensor): The condition to choose x or y. When True (nonzero), yield x, otherwise yield y.
        x (Tensor|scalar, optional): A Tensor or scalar to choose when the condition is True with data type of float32, float64, int32 or int64. Either both or neither of x and y should be given.
        y (Tensor|scalar, optional): A Tensor or scalar to choose when the condition is False with data type of float32, float64, int32 or int64. Either both or neither of x and y should be given.
        name (str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
580

581
    Returns:
582
        Tensor: A Tensor with the same shape as :attr:`condition` and same data type as :attr:`x` and :attr:`y`.
583

584
    Examples:
585

586 587
        .. code-block:: python

588
            import paddle
589

590 591
            x = paddle.to_tensor([0.9383, 0.1983, 3.2, 1.2])
            y = paddle.to_tensor([1.0, 1.0, 1.0, 1.0])
592

593 594 595
            out = paddle.where(x>1, x, y)
            print(out)
            #out: [1.0, 1.0, 3.2, 1.2]
596

597 598 599 600 601
            out = paddle.where(x>1)
            print(out)
            #out: (Tensor(shape=[2, 1], dtype=int64, place=CPUPlace, stop_gradient=True,
            #            [[2],
            #             [3]]),)
602
    """
R
ronnywang 已提交
603
    if np.isscalar(x):
604
        x = paddle.full([1], x, np.array([x]).dtype.name)
R
ronnywang 已提交
605 606

    if np.isscalar(y):
607
        y = paddle.full([1], y, np.array([y]).dtype.name)
R
ronnywang 已提交
608

R
ronnywang 已提交
609 610 611 612 613 614
    if x is None and y is None:
        return nonzero(condition, as_tuple=True)

    if x is None or y is None:
        raise ValueError("either both or neither of x and y should be given")

Z
zhiboniu 已提交
615
    if not paddle.in_dynamic_mode():
616
        check_variable_and_dtype(condition, 'condition', ['bool'], 'where')
617 618 619 620 621 622
        check_variable_and_dtype(
            x, 'x', ['float32', 'float64', 'int32', 'int64'], 'where'
        )
        check_variable_and_dtype(
            y, 'y', ['float32', 'float64', 'int32', 'int64'], 'where'
        )
623

624
    condition_shape = list(condition.shape)
625 626
    x_shape = list(x.shape)
    y_shape = list(y.shape)
627

628
    if x_shape == y_shape and condition_shape == x_shape:
629 630 631 632
        broadcast_condition = condition
        broadcast_x = x
        broadcast_y = y
    else:
Z
zhiboniu 已提交
633 634 635 636 637 638 639 640 641 642 643 644 645
        zeros_like_x = paddle.zeros_like(x)
        zeros_like_y = paddle.zeros_like(y)
        zeros_like_condition = paddle.zeros_like(condition)
        zeros_like_condition = paddle.cast(zeros_like_condition, x.dtype)
        cast_cond = paddle.cast(condition, x.dtype)

        broadcast_zeros = paddle.add(zeros_like_x, zeros_like_y)
        broadcast_zeros = paddle.add(broadcast_zeros, zeros_like_condition)
        broadcast_x = paddle.add(x, broadcast_zeros)
        broadcast_y = paddle.add(y, broadcast_zeros)
        broadcast_condition = paddle.add(cast_cond, broadcast_zeros)
        broadcast_condition = paddle.cast(broadcast_condition, 'bool')

J
Jiabin Yang 已提交
646
    if in_dygraph_mode():
647
        return _C_ops.where(broadcast_condition, broadcast_x, broadcast_y)
648
    else:
649 650
        helper = LayerHelper("where", **locals())
        out = helper.create_variable_for_type_inference(dtype=x.dtype)
651

652 653 654 655 656 657 658 659 660 661 662
        helper.append_op(
            type='where',
            inputs={
                'Condition': broadcast_condition,
                'X': broadcast_x,
                'Y': broadcast_y,
            },
            outputs={'Out': [out]},
        )

        return out
663 664


C
Chengmo 已提交
665 666 667 668
def index_sample(x, index):
    """
    **IndexSample Layer**

669 670
    IndexSample OP returns the element of the specified location of X,
    and the location is specified by Index.
C
Chengmo 已提交
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688

    .. code-block:: text


                Given:

                X = [[1, 2, 3, 4, 5],
                     [6, 7, 8, 9, 10]]

                Index = [[0, 1, 3],
                         [0, 2, 4]]

                Then:

                Out = [[1, 2, 4],
                       [6, 8, 10]]

    Args:
689
        x (Tensor): The source input tensor with 2-D shape. Supported data type is
690
            int32, int64, float16, float32, float64.
691
        index (Tensor): The index input tensor with 2-D shape, first dimension should be same with X.
C
Chengmo 已提交
692 693 694
            Data type is int32 or int64.

    Returns:
C
Chengmo 已提交
695
        output (Tensor): The output is a tensor with the same shape as index.
C
Chengmo 已提交
696 697 698 699 700 701

    Examples:

        .. code-block:: python

            import paddle
702 703 704 705 706 707 708 709 710 711 712

            x = paddle.to_tensor([[1.0, 2.0, 3.0, 4.0],
                                  [5.0, 6.0, 7.0, 8.0],
                                  [9.0, 10.0, 11.0, 12.0]], dtype='float32')
            index = paddle.to_tensor([[0, 1, 2],
                                      [1, 2, 3],
                                      [0, 0, 0]], dtype='int32')
            target = paddle.to_tensor([[100, 200, 300, 400],
                                       [500, 600, 700, 800],
                                       [900, 1000, 1100, 1200]], dtype='int32')
            out_z1 = paddle.index_sample(x, index)
N
Noel 已提交
713
            print(out_z1)
714 715 716 717 718 719 720 721
            #[[1. 2. 3.]
            # [6. 7. 8.]
            # [9. 9. 9.]]

            # Use the index of the maximum value by topk op
            # get the value of the element of the corresponding index in other tensors
            top_value, top_index = paddle.topk(x, k=2)
            out_z2 = paddle.index_sample(target, top_index)
N
Noel 已提交
722
            print(top_value)
723 724 725 726
            #[[ 4.  3.]
            # [ 8.  7.]
            # [12. 11.]]

N
Noel 已提交
727
            print(top_index)
728 729 730 731
            #[[3 2]
            # [3 2]
            # [3 2]]

N
Noel 已提交
732
            print(out_z2)
733 734 735
            #[[ 400  300]
            # [ 800  700]
            # [1200 1100]]
C
Chengmo 已提交
736

C
Chengmo 已提交
737
    """
J
Jiabin Yang 已提交
738
    if in_dygraph_mode():
739
        return _C_ops.index_sample(x, index)
J
Jiabin Yang 已提交
740
    else:
741 742 743 744 745 746 747 748 749 750 751 752 753 754
        helper = LayerHelper("index_sample", **locals())
        check_variable_and_dtype(
            x,
            'x',
            ['float16', 'float32', 'float64', 'int32', 'int64'],
            'paddle.tensor.search.index_sample',
        )
        check_variable_and_dtype(
            index,
            'index',
            ['int32', 'int64'],
            'paddle.tensor.search.index_sample',
        )
        out = helper.create_variable_for_type_inference(dtype=x.dtype)
J
Jiabin Yang 已提交
755

756 757 758 759 760 761
        helper.append_op(
            type='index_sample',
            inputs={'X': x, 'Index': index},
            outputs={'Out': out},
        )
        return out
762 763 764 765


def masked_select(x, mask, name=None):
    """
C
Chen Long 已提交
766
    Returns a new 1-D tensor which indexes the input tensor according to the ``mask``
767 768 769
    which is a tensor with data type of bool.

    Args:
770
        x (Tensor): The input Tensor, the data type can be int32, int64, float32, float64.
771
        mask (Tensor): The Tensor containing the binary mask to index with, it's data type is bool.
772
        name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
773

774
    Returns:
775
        A 1-D Tensor which is the same data type  as ``x``.
776

777 778 779 780 781
    Examples:

        .. code-block:: python

            import paddle
782 783 784 785 786 787 788

            x = paddle.to_tensor([[1.0, 2.0, 3.0, 4.0],
                                  [5.0, 6.0, 7.0, 8.0],
                                  [9.0, 10.0, 11.0, 12.0]])
            mask = paddle.to_tensor([[True, False, False, False],
                                     [True, True, False, False],
                                     [True, False, False, False]])
789 790 791 792
            out = paddle.masked_select(x, mask)
            #[1.0 5.0 6.0 9.0]
    """

H
hong 已提交
793
    if in_dygraph_mode():
794
        return _C_ops.masked_select(x, mask)
H
hong 已提交
795

796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
    else:
        helper = LayerHelper("masked_select", **locals())
        check_variable_and_dtype(
            x,
            'x',
            ['float32', 'float64', 'int32', 'int64'],
            'paddle.tensor.search.mask_select',
        )
        check_variable_and_dtype(
            mask, 'mask', ['bool'], 'paddle.tensor.search.masked_select'
        )
        out = helper.create_variable_for_type_inference(dtype=x.dtype)
        helper.append_op(
            type='masked_select',
            inputs={'X': x, 'Mask': mask},
            outputs={'Y': out},
        )
        return out
W
wawltor 已提交
814 815 816 817


def topk(x, k, axis=None, largest=True, sorted=True, name=None):
    """
818
    Return values and indices of the k largest or smallest at the optional axis.
W
wawltor 已提交
819 820 821 822 823 824 825 826 827 828 829 830
    If the input is a 1-D Tensor, finds the k largest or smallest values and indices.
    If the input is a Tensor with higher rank, this operator computes the top k values and indices along the :attr:`axis`.

    Args:
        x(Tensor): Tensor, an input N-D Tensor with type float32, float64, int32, int64.
        k(int, Tensor): The number of top elements to look for along the axis.
        axis(int, optional): Axis to compute indices along. The effective range
            is [-R, R), where R is x.ndim. when axis < 0, it works the same way
            as axis + R. Default is -1.
        largest(bool, optional) : largest is a flag, if set to true,
            algorithm will sort by descending order, otherwise sort by
            ascending order. Default is True.
831
        sorted(bool, optional): controls whether to return the elements in sorted order, default value is True. In gpu device, it always return the sorted value.
W
wawltor 已提交
832 833 834 835 836 837 838 839
        name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.

    Returns:
        tuple(Tensor), return the values and indices. The value data type is the same as the input `x`. The indices data type is int64.

    Examples:

        .. code-block:: python
840

841
            import paddle
W
wawltor 已提交
842

843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
            data_1 = paddle.to_tensor([1, 4, 5, 7])
            value_1, indices_1 = paddle.topk(data_1, k=1)
            print(value_1) # [7]
            print(indices_1) # [3]

            data_2 = paddle.to_tensor([[1, 4, 5, 7], [2, 6, 2, 5]])
            value_2, indices_2 = paddle.topk(data_2, k=1)
            print(value_2) # [[7], [6]]
            print(indices_2) # [[3], [1]]

            value_3, indices_3 = paddle.topk(data_2, k=1, axis=-1)
            print(value_3) # [[7], [6]]
            print(indices_3) # [[3], [1]]

            value_4, indices_4 = paddle.topk(data_2, k=1, axis=0)
            print(value_4) # [[2, 6, 5, 7]]
            print(indices_4) # [[1, 1, 0, 0]]
W
wawltor 已提交
860 861 862


    """
H
hong 已提交
863

H
hong 已提交
864
    if in_dygraph_mode():
865
        if axis is None:
H
hong 已提交
866
            axis = -1
867
        out, indices = _C_ops.topk(x, k, axis, largest, sorted)
H
hong 已提交
868
        return out, indices
W
wawltor 已提交
869
    else:
870 871 872 873 874 875 876 877 878 879 880
        helper = LayerHelper("top_k_v2", **locals())
        inputs = {"X": [x]}
        attrs = {}
        if isinstance(k, Variable):
            inputs['K'] = [k]
        else:
            attrs = {'k': k}
        attrs['largest'] = largest
        attrs['sorted'] = sorted
        if axis is not None:
            attrs['axis'] = axis
W
wawltor 已提交
881

882 883
        values = helper.create_variable_for_type_inference(dtype=x.dtype)
        indices = helper.create_variable_for_type_inference(dtype="int64")
W
wawltor 已提交
884

885 886 887 888 889 890 891 892
        helper.append_op(
            type="top_k_v2",
            inputs=inputs,
            outputs={"Out": [values], "Indices": [indices]},
            attrs=attrs,
        )
        indices.stop_gradient = True
        return values, indices
Y
Yanxing Shi 已提交
893 894


895 896 897 898 899 900
def bucketize(x, sorted_sequence, out_int32=False, right=False, name=None):
    """
    This API is used to find the index of the corresponding 1D tensor `sorted_sequence` in the innermost dimension based on the given `x`.

    Args:
        x(Tensor): An input N-D tensor value with type int32, int64, float32, float64.
901
        sorted_sequence(Tensor): An input 1-D tensor with type int32, int64, float32, float64. The value of the tensor monotonically increases in the innermost dimension.
902 903
        out_int32(bool, optional): Data type of the output tensor which can be int32, int64. The default value is False, and it indicates that the output data type is int64.
        right(bool, optional): Find the upper or lower bounds of the sorted_sequence range in the innermost dimension based on the given `x`. If the value of the sorted_sequence is nan or inf, return the size of the innermost dimension.
904
                               The default value is False and it shows the lower bounds.
905
        name(str, optional): The default value is None. Normally there is no need for user to set this property. For more information, please refer to :ref:`api_guide_Name`.
906

907
    Returns:
908 909
        Tensor(the same sizes of the `x`), return the tensor of int32 if set :attr:`out_int32` is True, otherwise return the tensor of int64.

910 911 912
    Examples:

        .. code-block:: python
913

914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
            import paddle

            sorted_sequence = paddle.to_tensor([2, 4, 8, 16], dtype='int32')
            x = paddle.to_tensor([[0, 8, 4, 16], [-1, 2, 8, 4]], dtype='int32')
            out1 = paddle.bucketize(x, sorted_sequence)
            print(out1)
            # Tensor(shape=[2, 4], dtype=int64, place=CPUPlace, stop_gradient=True,
            #        [[0, 2, 1, 3],
            #         [0, 0, 2, 1]])
            out2 = paddle.bucketize(x, sorted_sequence, right=True)
            print(out2)
            # Tensor(shape=[2, 4], dtype=int64, place=CPUPlace, stop_gradient=True,
            #        [[0, 3, 2, 4],
            #         [0, 1, 3, 2]])
            out3 = x.bucketize(sorted_sequence)
            print(out3)
            # Tensor(shape=[2, 4], dtype=int64, place=CPUPlace, stop_gradient=True,
            #        [[0, 2, 1, 3],
            #         [0, 0, 2, 1]])
            out4 = x.bucketize(sorted_sequence, right=True)
            print(out4)
            # Tensor(shape=[2, 4], dtype=int64, place=CPUPlace, stop_gradient=True,
            #        [[0, 3, 2, 4],
            #         [0, 1, 3, 2]])
938

939
    """
940 941 942 943 944 945
    check_variable_and_dtype(
        sorted_sequence,
        'SortedSequence',
        ['float32', 'float64', 'int32', 'int64'],
        'paddle.searchsorted',
    )
946 947 948 949 950 951 952
    if sorted_sequence.dim() != 1:
        raise ValueError(
            f"sorted_sequence tensor must be 1 dimension, but got dim {sorted_sequence.dim()}"
        )
    return searchsorted(sorted_sequence, x, out_int32, right, name)


953 954 955
def searchsorted(
    sorted_sequence, values, out_int32=False, right=False, name=None
):
Y
Yanxing Shi 已提交
956
    """
957
    Find the index of the corresponding `sorted_sequence` in the innermost dimension based on the given `values`.
Y
Yanxing Shi 已提交
958 959

    Args:
960
        sorted_sequence(Tensor): An input N-D or 1-D tensor with type int32, int64, float32, float64. The value of the tensor monotonically increases in the innermost dimension.
Y
Yanxing Shi 已提交
961 962 963
        values(Tensor): An input N-D tensor value with type int32, int64, float32, float64.
        out_int32(bool, optional): Data type of the output tensor which can be int32, int64. The default value is False, and it indicates that the output data type is int64.
        right(bool, optional): Find the upper or lower bounds of the sorted_sequence range in the innermost dimension based on the given `values`. If the value of the sorted_sequence is nan or inf, return the size of the innermost dimension.
964
                               The default value is False and it shows the lower bounds.
965
        name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
966

Y
Yanxing Shi 已提交
967
    Returns:
968 969
        Tensor(the same sizes of the `values`), return the tensor of int32 if set :attr:`out_int32` is True, otherwise return the tensor of int64.

Y
Yanxing Shi 已提交
970 971 972
    Examples:

        .. code-block:: python
973

Y
Yanxing Shi 已提交
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
            import paddle

            sorted_sequence = paddle.to_tensor([[1, 3, 5, 7, 9, 11],
                                                [2, 4, 6, 8, 10, 12]], dtype='int32')
            values = paddle.to_tensor([[3, 6, 9, 10], [3, 6, 9, 10]], dtype='int32')
            out1 = paddle.searchsorted(sorted_sequence, values)
            print(out1)
            # Tensor(shape=[2, 4], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
            #        [[1, 3, 4, 5],
            #         [1, 2, 4, 4]])
            out2 = paddle.searchsorted(sorted_sequence, values, right=True)
            print(out2)
            # Tensor(shape=[2, 4], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
            #        [[2, 3, 5, 5],
            #         [1, 3, 4, 5]])
            sorted_sequence_1d = paddle.to_tensor([1, 3, 5, 7, 9, 11, 13])
990
            out3 = paddle.searchsorted(sorted_sequence_1d, values)
Y
Yanxing Shi 已提交
991 992 993 994
            print(out3)
            # Tensor(shape=[2, 4], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
            #        [[1, 3, 4, 5],
            #         [1, 3, 4, 5]])
995

Y
Yanxing Shi 已提交
996
    """
F
From00 已提交
997
    if in_dygraph_mode():
998
        return _C_ops.searchsorted(sorted_sequence, values, out_int32, right)
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
    else:
        check_variable_and_dtype(
            sorted_sequence,
            'SortedSequence',
            ['float32', 'float64', 'int32', 'int64'],
            'paddle.searchsorted',
        )
        check_variable_and_dtype(
            values,
            'Values',
            ['float32', 'float64', 'int32', 'int64'],
            'paddle.searchsorted',
1011
        )
Y
Yanxing Shi 已提交
1012

1013 1014 1015 1016 1017 1018 1019 1020 1021
        helper = LayerHelper('searchsorted', **locals())
        out_type = 'int32' if out_int32 else 'int64'
        out = helper.create_variable_for_type_inference(dtype=out_type)
        helper.append_op(
            type='searchsorted',
            inputs={'SortedSequence': sorted_sequence, "Values": values},
            outputs={'Out': out},
            attrs={"out_int32": out_int32, "right": right},
        )
Y
Yanxing Shi 已提交
1022

1023
        return out
1024 1025 1026 1027


def kthvalue(x, k, axis=None, keepdim=False, name=None):
    """
1028
    Find values and indices of the k-th smallest at the axis.
1029 1030 1031 1032 1033 1034 1035 1036

    Args:
        x(Tensor): A N-D Tensor with type float32, float64, int32, int64.
        k(int): The k for the k-th smallest number to look for along the axis.
        axis(int, optional): Axis to compute indices along. The effective range
            is [-R, R), where R is x.ndim. when axis < 0, it works the same way
            as axis + R. The default is None. And if the axis is None, it will computed as -1 by default.
        keepdim(bool, optional): Whether to keep the given axis in output. If it is True, the dimensions will be same as input x and with size one in the axis. Otherwise the output dimentions is one fewer than x since the axis is squeezed. Default is False.
1037
        name (str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.
1038 1039 1040

    Returns:
        tuple(Tensor), return the values and indices. The value data type is the same as the input `x`. The indices data type is int64.
1041

1042 1043 1044
    Examples:

        .. code-block:: python
1045

1046
            import paddle
1047

1048 1049 1050 1051 1052 1053 1054 1055
            x = paddle.randn((2,3,2))
            # Tensor(shape=[2, 3, 2], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
            #       [[[ 0.22954939, -0.01296274],
            #         [ 1.17135799, -0.34493217],
            #         [-0.19550551, -0.17573971]],
            #
            #        [[ 0.15104349, -0.93965352],
            #         [ 0.14745511,  0.98209465],
1056 1057
            #         [ 0.10732264, -0.55859774]]])
            y = paddle.kthvalue(x, 2, 1)
1058 1059 1060 1061 1062 1063
            # (Tensor(shape=[2, 2], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
            # [[ 0.22954939, -0.17573971],
            #  [ 0.14745511, -0.55859774]]), Tensor(shape=[2, 2], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
            #  [[0, 2],
            #  [1, 2]]))
    """
1064
    if in_dygraph_mode():
1065
        if axis is not None:
1066
            return _C_ops.kthvalue(x, k, axis, keepdim)
1067
        else:
1068
            return _C_ops.kthvalue(x, k, -1, keepdim)
1069 1070 1071 1072 1073 1074 1075 1076 1077

    helper = LayerHelper("kthvalue", **locals())
    inputs = {"X": [x]}
    attrs = {'k': k}
    if axis is not None:
        attrs['axis'] = axis
    values = helper.create_variable_for_type_inference(dtype=x.dtype)
    indices = helper.create_variable_for_type_inference(dtype="int64")

1078 1079 1080 1081 1082 1083
    helper.append_op(
        type="kthvalue",
        inputs=inputs,
        outputs={"Out": [values], "Indices": [indices]},
        attrs=attrs,
    )
1084 1085
    indices.stop_gradient = True
    return values, indices