diff --git a/paddle/fluid/pybind/arg_pre_process.cc b/paddle/fluid/pybind/arg_pre_process.cc index 4e2c338e904475..85da0b3fe86639 100644 --- a/paddle/fluid/pybind/arg_pre_process.cc +++ b/paddle/fluid/pybind/arg_pre_process.cc @@ -237,6 +237,17 @@ void AllClosePreProcess(Value* x, Value* y, Value* rtol, Value* atol) { "allclose", "atol", pir::GetValueDtype(*atol), {phi::DataType::FLOAT64}); } +void NextAfterPreProcess(Value* x, Value* y) { + CheckDataType("nextafter", + "x", + pir::GetValueDtype(*x), + {phi::DataType::FLOAT32, phi::DataType::FLOAT64}); + CheckDataType("nextafter", + "y", + pir::GetValueDtype(*y), + {phi::DataType::FLOAT32, phi::DataType::FLOAT64}); +} + void GridSamplePreProcess(Tensor* x, Tensor* grid, std::string* mode, diff --git a/paddle/fluid/pybind/arg_pre_process.h b/paddle/fluid/pybind/arg_pre_process.h index d5387319e26c71..6f12cdf31e8e8a 100644 --- a/paddle/fluid/pybind/arg_pre_process.h +++ b/paddle/fluid/pybind/arg_pre_process.h @@ -46,6 +46,8 @@ void SumPreProcess(Value* x, Value* axis); void IsClosePreProcess(Value* x, Value* y, Value* rtol, Value* atol); void AllClosePreProcess(Value* x, Value* y, Value* rtol, Value* atol); +void NextAfterPreProcess(Value* x, Value* y); + void GridSamplePreProcess(Tensor* x, Tensor* grid, std::string* mode, diff --git a/paddle/phi/ops/yaml/python_api_info.yaml b/paddle/phi/ops/yaml/python_api_info.yaml index efad844a204d41..6f599a8da90e5b 100644 --- a/paddle/phi/ops/yaml/python_api_info.yaml +++ b/paddle/phi/ops/yaml/python_api_info.yaml @@ -319,3 +319,11 @@ args_alias: x : [batch1] y : [batch2] + +- op : nextafter + name : [paddle.nextafter, paddle.Tensor.nextafter] + args_alias : + x: [input] + y: [other] + pre_process: + static_func: NextAfterPreProcess(x, y) diff --git a/python/paddle/_paddle_docs.py b/python/paddle/_paddle_docs.py index 0d7462be8ce979..18b48393b1ae6a 100644 --- a/python/paddle/_paddle_docs.py +++ b/python/paddle/_paddle_docs.py @@ -1153,6 +1153,38 @@ def isclose( """, ) +add_doc_and_signature( + "nextafter", + r""" + Return the next floating-point value after input towards other, elementwise. + The shapes of input and other must be broadcastable. + + Args: + x (Tensor): An N-D Tensor, the data type is float32, float64. + y (Tensor): An N-D Tensor, the data type is float32, float64. + name(str, optional):Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. + + Returns: + out (Tensor): An N-D Tensor, the shape and data type is the same with input. + + Examples: + .. code-block:: python + + >>> import paddle + >>> out = paddle.nextafter(paddle.to_tensor([1.0,2.0]),paddle.to_tensor([2.0,1.0])) + >>> out + Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True, + [1.00000012, 1.99999988]) +""", + """ +def nextafter( + x : Tensor, + y : Tensor, + name: str | None = None, + *, + out: Tensor | None = None, +) -> Tensor""", +) # zhengsheng add_doc_and_signature( diff --git a/python/paddle/compat/__init__.py b/python/paddle/compat/__init__.py index e797399da2a14e..e17d398d0c5c73 100644 --- a/python/paddle/compat/__init__.py +++ b/python/paddle/compat/__init__.py @@ -116,6 +116,46 @@ def allclose( ).item() +@ForbidKeywordsDecorator( + illegal_keys={"x", "y"}, + func_name="paddle.compat.nextafter", + correct_name="paddle.nextafter", +) +def nextafter( + input: Tensor, + other: Tensor, + *, + out: Tensor | None = None, +) -> Tensor: + """ + Return the next floating-point value after input towards other, elementwise. + The shapes of input and other must be broadcastable. + + Args: + x (Tensor): An N-D Tensor, the data type is float32, float64. + y (Tensor): An N-D Tensor, the data type is float32, float64. + name(str, optional):Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. + + Returns: + out (Tensor): An N-D Tensor, the shape and data type is the same with input. + + Examples: + .. code-block:: python + + >>> import paddle + >>> out = paddle.nextafter(paddle.to_tensor([1.0,2.0]),paddle.to_tensor([2.0,1.0])) + >>> out + Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True, + [1.00000012, 1.99999988]) + """ + _check_out_status(out, False) + result = paddle.nextafter(input, other) + if out is not None: + paddle.assign(result, out) + return out + return result + + @ForbidKeywordsDecorator( illegal_keys={"x", "y"}, func_name="paddle.compat.equal", diff --git a/python/paddle/tensor/math.py b/python/paddle/tensor/math.py index 185c6cfb44b898..ce2da65554185f 100644 --- a/python/paddle/tensor/math.py +++ b/python/paddle/tensor/math.py @@ -40,6 +40,7 @@ maximum, minimum, multiply, + nextafter, sign, sin, sum, @@ -6488,42 +6489,6 @@ def vander( return res -def nextafter(x: Tensor, y: Tensor, name: str | None = None) -> Tensor: - r""" - Return the next floating-point value after input towards other, elementwise. - The shapes of input and other must be broadcastable. - - Args: - x (Tensor): An N-D Tensor, the data type is float32, float64. - y (Tensor): An N-D Tensor, the data type is float32, float64. - name(str, optional):Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. - - Returns: - out (Tensor): An N-D Tensor, the shape and data type is the same with input. - - Examples: - .. code-block:: python - - >>> import paddle - >>> out = paddle.nextafter(paddle.to_tensor([1.0,2.0]),paddle.to_tensor([2.0,1.0])) - >>> out - Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True, - [1.00000012, 1.99999988]) - """ - if in_dynamic_or_pir_mode(): - return _C_ops.nextafter(x, y) - else: - check_variable_and_dtype(x, 'x', ['float32', 'float64'], 'nextafter') - check_variable_and_dtype(y, 'y', ['float32', 'float64'], 'nextafter') - op_type = "nextafter" - helper = LayerHelper(op_type, **locals()) - inputs = {"x": x, "y": y} - out = helper.create_variable_for_type_inference(dtype=paddle.float32) - outputs = {"out": out} - helper.append_op(type=op_type, inputs=inputs, outputs=outputs) - return out - - def i0(x: Tensor, name: str | None = None) -> Tensor: r""" The function used to calculate modified bessel function of order 0. diff --git a/test/legacy_test/test_nextafter_op.py b/test/legacy_test/test_nextafter_op.py index 15288c0c6f65bb..bab5291e6bd357 100644 --- a/test/legacy_test/test_nextafter_op.py +++ b/test/legacy_test/test_nextafter_op.py @@ -171,5 +171,76 @@ def setUp(self): self.outputs = {'out': out} +class TestNextafterCompatibility(unittest.TestCase): + def setUp(self): + self.x = np.random.rand(2, 3, 4, 5).astype('float32') + self.y = np.random.rand(2, 3, 4, 5).astype('float32') + self.out = np.nextafter(self.x, self.y) + self.place = get_device_place() + + def test_dygraph_Compatibility(self): + paddle.disable_static() + x = paddle.to_tensor(self.x) + y = paddle.to_tensor(self.y) + paddle_dygraph_out = [] + # Position args (args) + out1 = paddle.nextafter(x, y) + paddle_dygraph_out.append(out1) + # Key words args (kwargs) for paddle + out2 = paddle.nextafter(x=x, y=y) + paddle_dygraph_out.append(out2) + # Key words args (kwargs) for torch + out3 = paddle.nextafter(input=x, other=y) + paddle_dygraph_out.append(out3) + + # Tensor method args + out4 = paddle.empty([]) + out5 = x.nextafter(y, out=out4) + paddle_dygraph_out.append(out4) + paddle_dygraph_out.append(out5) + # Tensor method kwargs + out6 = x.nextafter(y, out=out4) + paddle_dygraph_out.append(out6) + # Test out + out7 = paddle.empty([]) + paddle.nextafter(x, y, out=out7) + paddle_dygraph_out.append(out7) + # Numpy reference out + ref_out = np.nextafter(self.x, self.y) + # Check + for out in paddle_dygraph_out: + np.testing.assert_allclose(ref_out, out.numpy()) + paddle.enable_static() + + def test_static_Compatibility(self): + main = paddle.static.Program() + startup = paddle.static.Program() + with paddle.static.program_guard(main, startup): + x = paddle.static.data( + name='x', shape=self.x.shape, dtype='float32' + ) + y = paddle.static.data( + name='y', shape=self.y.shape, dtype='float32' + ) + # Position args (args) + out1 = paddle.nextafter(x, y) + # Key words args (kwargs) for paddle + out2 = paddle.nextafter(x=x, y=y) + # Key words args (kwargs) for torch + out3 = paddle.nextafter(input=x, other=y) + # Tensor method args + out4 = x.nextafter(y) + + exe = paddle.static.Executor(self.place) + fetches = exe.run( + main, + feed={"x": self.x, "y": self.y}, + fetch_list=[out1, out2, out3, out4], + ) + ref_out = np.nextafter(self.x, self.y) + for out in fetches: + np.testing.assert_allclose(out, ref_out) + + if __name__ == "__main__": unittest.main()