// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. // // 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. // custom arg mapper function. // The function here will be called by the functions in // paddle/fluid/pybind/static_op_function.cc and // paddle/fluid/pybind/eager_op_function.cc. Mainly used to customize the args // parser from PyObject *args and PyObject *kwargs #include "paddle/fluid/pybind/args_mapper.h" #include "paddle/fluid/eager/utils.h" #include "paddle/fluid/pir/dialect/operator/ir/pd_api.h" #include "paddle/fluid/pybind/eager_utils.h" #include "paddle/fluid/pybind/op_function_common.h" #include "paddle/phi/common/data_type.h" #include "paddle/phi/core/enforce.h" namespace paddle { namespace pybind { void ArgMaxMinMapper(PyObject* args, PyObject* kwargs, Tensor** x_ptr_ptr, paddle::experimental::Scalar* axis, bool* keepdims, bool* flatten, DataType* dtype) { // The python params are (x, axis,keepdim,dtype) which haven't flatten // The _C_ops params are (x, axis,keepdim,flatten,dtype) which have flatten int nargs = args ? static_cast(PyTuple_Size(args)) : 0; int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; const int max_args = 4; CheckParamsCount(nargs, remaining_kwargs, max_args); VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); // Get EagerTensors from args auto& x = GetTensorFromArgsOrKWArgs("argmax", "x", args, 0, kwargs, {"x", "input"}, nargs, &remaining_kwargs, false); *x_ptr_ptr = &x; // Parse Attributes if needed PyObject* axis_obj = GetItemFromArgsOrKWArgs( args, 1, kwargs, {"axis", "dim"}, nargs, &remaining_kwargs); /** flatten = False if axis is None: flatten = True axis = 0 */ *flatten = false; if (axis_obj == Py_None || axis_obj == nullptr) { *flatten = true; *axis = 0; } else { *axis = CastPyArg2Scalar(axis_obj, "argmax", 1); } PyObject* keepdims_obj = GetItemFromArgsOrKWArgs( args, 2, kwargs, {"keepdim", "keepdims"}, nargs, &remaining_kwargs); *keepdims = CastPyArg2Boolean(keepdims_obj, "argmax", 2, false); PyObject* dtype_obj = GetItemFromArgsOrKWArgs( args, 3, kwargs, {"dtype"}, nargs, &remaining_kwargs); /** if dtype is None: raise ValueError( "the value of 'dtype' in argmax could not be None, but received None") */ PADDLE_ENFORCE_NE(dtype_obj, Py_None, common::errors::InvalidArgument( "the value of 'dtype' in argmax and argmin " "could not be None, but received None")); *dtype = CastPyArg2DataType(dtype_obj, "argmax", 3, DataType::INT64); // Check Remaining Params validity if needed CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); return; } void ArgMaxMinMapper(PyObject* args, PyObject* kwargs, pir::Value* x, pir::Value* axis, bool* keepdims, bool* flatten, DataType* dtype) { // Get Total Params count and check validity if needed int nargs = args ? static_cast(PyTuple_Size(args)) : 0; int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; const int max_args = 4; CheckParamsCount(nargs, remaining_kwargs, max_args); // Get Value from args PyObject* x_obj = GetItemFromArgsOrKWArgs( args, 0, kwargs, {"x", "input"}, nargs, &remaining_kwargs); *x = CastPyArg2Value(x_obj, "argmax", 0, false); // Parse Attributes PyObject* axis_obj = GetItemFromArgsOrKWArgs( args, 1, kwargs, {"axis", "dim"}, nargs, &remaining_kwargs); PyObject* keepdims_obj = GetItemFromArgsOrKWArgs( args, 2, kwargs, {"keepdim", "keepdims"}, nargs, &remaining_kwargs); PyObject* dtype_obj = GetItemFromArgsOrKWArgs( args, 3, kwargs, {"dtype"}, nargs, &remaining_kwargs); /** flatten = False if axis is None: flatten = True axis = 0 */ *flatten = false; if (axis_obj == Py_None || axis_obj == nullptr) { *flatten = true; *axis = paddle::dialect::full( std::vector{1}, 0, DataType::INT64, CPUPlace()); } else if (PyObject_CheckIRValue(axis_obj)) { *axis = CastPyArg2Value(axis_obj, "argmax", 1); } else { int64_t axis_tmp = CastPyArg2Long(axis_obj, "argmax", 1); *axis = paddle::dialect::full( std::vector{1}, axis_tmp, DataType::INT64, CPUPlace()); } *keepdims = CastPyArg2Boolean(keepdims_obj, "argmax", 2, false); PADDLE_ENFORCE_NE(dtype_obj, Py_None, common::errors::InvalidArgument( "the value of 'dtype' in argmax and argmin " "could not be None, but received None")); *dtype = CastPyArg2DataType(dtype_obj, "argmax", 3, DataType::INT64); // Check Remaining Params validity if needed CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); return; } bool CheckBool(PyObject* obj) { if (obj == Py_False || obj == Py_True) { return true; } return false; } void ArgSumMapper(PyObject* args, PyObject* kwargs, Tensor** x_ptr_ptr, paddle::experimental::IntArray* axis, DataType* dtype, bool* keepdim) { // Get Total Params count and check validity if needed int nargs = args ? static_cast(PyTuple_Size(args)) : 0; int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; const int max_args = 4; CheckParamsCount(nargs, remaining_kwargs, max_args); // Get EagerTensors from args auto& x = GetTensorFromArgsOrKWArgs("sum", "x", args, 0, kwargs, {"input", "x"}, nargs, &remaining_kwargs, false); *x_ptr_ptr = &x; // Parse Attributes if needed PyObject* axis_obj = GetItemFromArgsOrKWArgs( args, 1, kwargs, {"dim", "axis"}, nargs, &remaining_kwargs); *axis = CastPyArg2IntArray(axis_obj, "sum", 1, {}); PyObject* py_obj_1 = GetItemFromArgsOrKWArgs( args, 2, kwargs, {"dtype", "keepdim"}, nargs, &remaining_kwargs); PyObject* py_obj_2 = nullptr; if (py_obj_1 == nullptr) { *dtype = DataType::UNDEFINED; *keepdim = false; } else { bool is_keepdim1 = CheckBool(py_obj_1); if (is_keepdim1) { *keepdim = CastPyArg2Boolean(py_obj_1, "sum", 2, false); py_obj_2 = GetItemFromArgsOrKWArgs( args, 3, kwargs, {"dtype"}, nargs, &remaining_kwargs); *dtype = CastPyArg2DataType(py_obj_2, "sum", 3, DataType::UNDEFINED); } else { *dtype = CastPyArg2DataType(py_obj_1, "sum", 2, DataType::UNDEFINED); py_obj_2 = GetItemFromArgsOrKWArgs( args, 3, kwargs, {"keepdim"}, nargs, &remaining_kwargs); *keepdim = CastPyArg2Boolean(py_obj_2, "sum", 3, false); } } // Check Remaining Params validity if needed CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); } void ArgSumMapper(PyObject* args, PyObject* kwargs, pir::Value* x, pir::Value* axis, DataType* dtype, bool* keepdim) { // Get Total Params count and check validity if needed int nargs = args ? static_cast(PyTuple_Size(args)) : 0; int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; const int max_args = 4; CheckParamsCount(nargs, remaining_kwargs, max_args); // Get Value from args PyObject* x_obj = GetItemFromArgsOrKWArgs( args, 0, kwargs, {"input", "x"}, nargs, &remaining_kwargs); *x = CastPyArg2Value(x_obj, "sum", 0, false); // Parse Attributes PyObject* axis_obj = GetItemFromArgsOrKWArgs( args, 1, kwargs, {"axis", "dim"}, nargs, &remaining_kwargs); // Check for mutable attrs if (PyObject_CheckIRValue(axis_obj)) { *axis = CastPyArg2Value(axis_obj, "sum", 1); } else if (PyObject_CheckIRVectorOfValue(axis_obj)) { std::vector axis_tmp = CastPyArg2VectorOfValue(axis_obj, "sum", 1); *axis = paddle::dialect::stack(axis_tmp, /*axis*/ 0); } else if (PyObject_CheckIRVectorOfValueOrLong(axis_obj)) { std::vector axis_tmp = CastPyArg2VectorOfValueOrLong(axis_obj, "sum", 1); *axis = paddle::dialect::stack(axis_tmp, /*axis*/ 0); } else { std::vector axis_tmp = CastPyArg2Longs(axis_obj, "sum", 1, {}); *axis = paddle::dialect::full_int_array(axis_tmp, DataType::INT64, CPUPlace()); } PyObject* py_obj_1 = GetItemFromArgsOrKWArgs( args, 2, kwargs, {"dtype", "keepdim"}, nargs, &remaining_kwargs); PyObject* py_obj_2 = nullptr; if (py_obj_1 == nullptr) { *dtype = DataType::UNDEFINED; *keepdim = false; } else { bool is_keepdim1 = CheckBool(py_obj_1); if (is_keepdim1) { *keepdim = CastPyArg2Boolean(py_obj_1, "sum", 2, false); py_obj_2 = GetItemFromArgsOrKWArgs( args, 3, kwargs, {"dtype"}, nargs, &remaining_kwargs); *dtype = CastPyArg2DataType(py_obj_2, "sum", 3, DataType::UNDEFINED); } else { *dtype = CastPyArg2DataType(py_obj_1, "sum", 2, DataType::UNDEFINED); py_obj_2 = GetItemFromArgsOrKWArgs( args, 3, kwargs, {"keepdim"}, nargs, &remaining_kwargs); *keepdim = CastPyArg2Boolean(py_obj_2, "sum", 3, false); } } // Check Remaining Params validity if needed CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); } void GeluMapper(PyObject* args, PyObject* kwargs, Tensor** x_ptr_ptr, bool* approximate) { // Get Total Params count and check validity if needed int nargs = args ? static_cast(PyTuple_Size(args)) : 0; int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; const int max_args = 2; CheckParamsCount(nargs, remaining_kwargs, max_args); // Get EagerTensors from args auto& x = GetTensorFromArgsOrKWArgs("gelu", "x", args, 0, kwargs, {"input", "x"}, nargs, &remaining_kwargs, false); *x_ptr_ptr = &x; PyObject* approximate_obj = GetItemFromArgsOrKWArgs( args, 1, kwargs, {"approximate"}, nargs, &remaining_kwargs); if (approximate_obj != nullptr && PyUnicode_Check(approximate_obj)) { std::string approximate_str = std::string(PyUnicode_AsUTF8(approximate_obj)); if (approximate_str == "tanh") { *approximate = true; } else if (approximate_str == "none") { *approximate = false; } else { approximate = nullptr; PADDLE_ENFORCE_NE(approximate, nullptr, common::errors::InvalidArgument( "the value of approximate in gelu should be 'tanh' " "or 'none', but received %s", approximate_str.c_str())); } } else { *approximate = CastPyArg2Boolean(approximate_obj, "gelu", 1, false); } // Check Remaining Params validity if needed CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); } void GeluMapper(PyObject* args, PyObject* kwargs, pir::Value* x, bool* approximate) { // Get Total Params count and check validity if needed int nargs = args ? static_cast(PyTuple_Size(args)) : 0; int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; const int max_args = 2; CheckParamsCount(nargs, remaining_kwargs, max_args); // Get Value from args PyObject* x_obj = GetItemFromArgsOrKWArgs( args, 0, kwargs, {"input", "x"}, nargs, &remaining_kwargs); *x = CastPyArg2Value(x_obj, "gelu", 0, false); // Parse Attributes PyObject* approximate_obj = GetItemFromArgsOrKWArgs( args, 1, kwargs, {"approximate"}, nargs, &remaining_kwargs); // give `approximate` a value based on the type of `approximate_obj` if (approximate_obj != nullptr && PyUnicode_Check(approximate_obj)) { std::string approximate_str = std::string(PyUnicode_AsUTF8(approximate_obj)); if (approximate_str == "tanh") { *approximate = true; } else if (approximate_str == "none") { *approximate = false; } else { approximate = nullptr; PADDLE_ENFORCE_NE(approximate, nullptr, common::errors::InvalidArgument( "the value of approximate in gelu should be 'tanh' " "or 'none', but received %s", approximate_str.c_str())); } } else { *approximate = CastPyArg2Boolean(approximate_obj, "gelu", 1, false); } // Check Remaining Params validity if needed CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); } void KthvalueMapper(PyObject* args, PyObject* kwargs, Tensor** x_ptr_ptr, int64_t* k, int* axis, bool* keepdim) { // Python params: (x, k, axis, keepdim) // C++ _C_ops params: (x, k, axis, keepdim) // When axis is None, set axis = -1 int nargs = args ? static_cast(PyTuple_Size(args)) : 0; int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; const int max_args = 4; // x, k, axis, keepdim CheckParamsCount(nargs, remaining_kwargs, max_args); // Get Tensor x (support aliases: x, input) auto& x = GetTensorFromArgsOrKWArgs("kthvalue", "x", args, 0, kwargs, {"x", "input"}, nargs, &remaining_kwargs, false); *x_ptr_ptr = &x; // Parse k parameter PyObject* k_obj = GetItemFromArgsOrKWArgs(args, 1, kwargs, {"k"}, nargs, &remaining_kwargs); *k = CastPyArg2Long(k_obj, "kthvalue", 1); // Parse axis parameter (support aliases: axis, dim) // When axis is None, set axis = -1 PyObject* axis_obj = GetItemFromArgsOrKWArgs( args, 2, kwargs, {"axis", "dim"}, nargs, &remaining_kwargs); if (axis_obj == Py_None || axis_obj == nullptr) { *axis = -1; } else { *axis = CastPyArg2Int(axis_obj, "kthvalue", 2); } // Parse keepdim parameter (support aliases: keepdim, keepdims) PyObject* keepdim_obj = GetItemFromArgsOrKWArgs( args, 3, kwargs, {"keepdim", "keepdims"}, nargs, &remaining_kwargs); *keepdim = CastPyArg2Boolean(keepdim_obj, "kthvalue", 3, false); // Check Remaining Params validity CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); } void KthvalueMapper(PyObject* args, PyObject* kwargs, pir::Value* x, int64_t* k, int* axis, bool* keepdim) { // Static graph version int nargs = args ? static_cast(PyTuple_Size(args)) : 0; int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; const int max_args = 4; CheckParamsCount(nargs, remaining_kwargs, max_args); // Get Value x (support aliases: x, input) PyObject* x_obj = GetItemFromArgsOrKWArgs( args, 0, kwargs, {"x", "input"}, nargs, &remaining_kwargs); *x = CastPyArg2Value(x_obj, "kthvalue", 0, false); // Parse k parameter PyObject* k_obj = GetItemFromArgsOrKWArgs(args, 1, kwargs, {"k"}, nargs, &remaining_kwargs); *k = CastPyArg2Long(k_obj, "kthvalue", 1); // Parse axis parameter (support aliases: axis, dim) PyObject* axis_obj = GetItemFromArgsOrKWArgs( args, 2, kwargs, {"axis", "dim"}, nargs, &remaining_kwargs); if (axis_obj == Py_None || axis_obj == nullptr) { *axis = -1; } else { *axis = CastPyArg2Int(axis_obj, "kthvalue", 2); } // Parse keepdim parameter PyObject* keepdim_obj = GetItemFromArgsOrKWArgs( args, 3, kwargs, {"keepdim", "keepdims"}, nargs, &remaining_kwargs); *keepdim = CastPyArg2Boolean(keepdim_obj, "kthvalue", 3, false); CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); } } // namespace pybind } // namespace paddle