chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/Scalar.h>
|
||||
|
||||
#include "paddle/phi/api/include/tensor.h"
|
||||
#include "paddle/phi/common/data_type.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
/// Extracts a scalar value from a single-element dense tensor.
|
||||
/// Mirrors PyTorch's at::_local_scalar_dense: copies the tensor to CPU if
|
||||
/// needed, then reads the first element according to its dtype.
|
||||
inline at::Scalar _local_scalar_dense(const at::Tensor& self) {
|
||||
PD_CHECK(self.numel() > 0, "_local_scalar_dense: Empty tensor not supported");
|
||||
|
||||
// Move to CPU if necessary (for compatibility with PyTorch behavior)
|
||||
const PaddleTensor& inner = self._PD_GetInner();
|
||||
PaddleTensor cpu_tensor = inner;
|
||||
if (!phi::is_cpu_place(inner.place())) {
|
||||
PaddlePlace place(phi::AllocationType::CPU);
|
||||
cpu_tensor = inner.copy_to(place, /*blocking=*/true);
|
||||
}
|
||||
|
||||
auto dtype = cpu_tensor.dtype();
|
||||
switch (dtype) {
|
||||
case phi::DataType::FLOAT32:
|
||||
return at::Scalar(*(cpu_tensor.data<float>()));
|
||||
case phi::DataType::FLOAT64:
|
||||
return at::Scalar(*(cpu_tensor.data<double>()));
|
||||
case phi::DataType::FLOAT16:
|
||||
return at::Scalar(
|
||||
static_cast<float>(*(cpu_tensor.data<phi::dtype::float16>())));
|
||||
case phi::DataType::BFLOAT16:
|
||||
return at::Scalar(
|
||||
static_cast<float>(*(cpu_tensor.data<phi::dtype::bfloat16>())));
|
||||
case phi::DataType::INT8:
|
||||
return at::Scalar(*(cpu_tensor.data<int8_t>()));
|
||||
case phi::DataType::INT16:
|
||||
return at::Scalar(*(cpu_tensor.data<int16_t>()));
|
||||
case phi::DataType::INT32:
|
||||
return at::Scalar(*(cpu_tensor.data<int32_t>()));
|
||||
case phi::DataType::INT64:
|
||||
return at::Scalar(*(cpu_tensor.data<int64_t>()));
|
||||
case phi::DataType::UINT8:
|
||||
return at::Scalar(*(cpu_tensor.data<uint8_t>()));
|
||||
case phi::DataType::BOOL:
|
||||
return at::Scalar(*(cpu_tensor.data<bool>()));
|
||||
case phi::DataType::COMPLEX64:
|
||||
return at::Scalar(*(cpu_tensor.data<phi::dtype::complex<float>>()));
|
||||
case phi::DataType::COMPLEX128:
|
||||
return at::Scalar(*(cpu_tensor.data<phi::dtype::complex<double>>()));
|
||||
default:
|
||||
PD_THROW("_local_scalar_dense: Unsupported data type");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include "paddle/phi/core/sparse_coo_tensor.h"
|
||||
#include "paddle/phi/core/sparse_csr_tensor.h"
|
||||
|
||||
namespace at {} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline int64_t Tensor::_nnz() const {
|
||||
PD_CHECK(this->is_sparse(),
|
||||
"_nnz expected sparse tensor layout but got ",
|
||||
layout());
|
||||
if (tensor_.layout() == common::DataLayout::SPARSE_COO) {
|
||||
auto sparse_coo_tensor =
|
||||
std::dynamic_pointer_cast<phi::SparseCooTensor>(tensor_.impl());
|
||||
PD_CHECK(sparse_coo_tensor != nullptr,
|
||||
"_nnz: failed to cast tensor impl to SparseCooTensor");
|
||||
return sparse_coo_tensor->nnz();
|
||||
} else {
|
||||
auto sparse_csr_tensor =
|
||||
std::dynamic_pointer_cast<phi::SparseCsrTensor>(tensor_.impl());
|
||||
PD_CHECK(sparse_csr_tensor != nullptr,
|
||||
"_nnz: failed to cast tensor impl to SparseCsrTensor");
|
||||
return sparse_csr_tensor->nnz();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include "paddle/phi/core/sparse_coo_tensor.h"
|
||||
#include "paddle/phi/core/sparse_csr_tensor.h"
|
||||
|
||||
namespace at {} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::_values() const {
|
||||
PD_CHECK(this->is_sparse(),
|
||||
"_values expected sparse tensor layout but got ",
|
||||
layout());
|
||||
if (tensor_.layout() == common::DataLayout::SPARSE_COO) {
|
||||
auto sparse_coo_tensor =
|
||||
std::dynamic_pointer_cast<phi::SparseCooTensor>(tensor_.impl());
|
||||
PD_CHECK(sparse_coo_tensor != nullptr,
|
||||
"_values: failed to cast tensor impl to SparseCooTensor");
|
||||
return paddle::Tensor(
|
||||
std::make_shared<phi::DenseTensor>(sparse_coo_tensor->values()));
|
||||
} else {
|
||||
PD_THROW("_values is not implemented for SparseCsr tensors");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,57 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/core/enforce.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor abs(const at::Tensor& self) {
|
||||
if (!self.is_contiguous()) {
|
||||
phi::enforce::ThrowWarnInternal(
|
||||
"at::abs: input tensor is non-contiguous. PyTorch and Paddle handle "
|
||||
"non-contiguous tensors differently, which may produce logically "
|
||||
"incorrect results even though the code is syntactically valid. "
|
||||
"See https://github.com/PaddlePaddle/Paddle/pull/78099 for details.");
|
||||
}
|
||||
return paddle::experimental::abs(self._PD_GetInner());
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::abs() const { return at::abs(*this); }
|
||||
|
||||
inline at::Tensor& Tensor::abs_() const {
|
||||
if (!is_contiguous()) {
|
||||
phi::enforce::ThrowWarnInternal(
|
||||
"Tensor::abs_: tensor is non-contiguous. PyTorch and Paddle handle "
|
||||
"non-contiguous tensors differently, which may produce logically "
|
||||
"incorrect results even though the code is syntactically valid. "
|
||||
"See https://github.com/PaddlePaddle/Paddle/pull/78099 for details.");
|
||||
}
|
||||
PaddleTensor& inner = const_cast<PaddleTensor&>(tensor_);
|
||||
paddle::experimental::abs_(inner);
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/util/OptionalArrayRef.h>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// all: Check if all elements are true (non-zero)
|
||||
// Version 1: all() - check all elements in the tensor
|
||||
inline at::Tensor all(const at::Tensor& self) {
|
||||
return paddle::experimental::all(self._PD_GetInner(), {}, false);
|
||||
}
|
||||
|
||||
// Version 2: all(dim, keepdim) - check along a specific dimension
|
||||
inline at::Tensor all(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
bool keepdim = false) {
|
||||
return paddle::experimental::all(self._PD_GetInner(), {dim}, keepdim);
|
||||
}
|
||||
|
||||
// Version 3: all(dim, keepdim) - check along optional dimensions
|
||||
inline at::Tensor all(const at::Tensor& self,
|
||||
at::OptionalIntArrayRef dim,
|
||||
bool keepdim = false) {
|
||||
std::vector<int64_t> axis_vec;
|
||||
if (dim.has_value()) {
|
||||
axis_vec.assign(dim.value().begin(), dim.value().end());
|
||||
}
|
||||
return paddle::experimental::all(self._PD_GetInner(), axis_vec, keepdim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
// Tensor member function implementations
|
||||
inline at::Tensor Tensor::all() const { return at::all(*this); }
|
||||
|
||||
inline at::Tensor Tensor::all(int64_t dim, bool keepdim) const {
|
||||
return at::all(*this, dim, keepdim);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::all(at::OptionalIntArrayRef dim, bool keepdim) const {
|
||||
return at::all(*this, dim, keepdim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/data_type.h"
|
||||
#include "paddle/phi/common/scalar.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// allclose: Check if two tensors are close to each other
|
||||
inline bool allclose(const at::Tensor& self,
|
||||
const at::Tensor& other,
|
||||
double rtol = 1e-05,
|
||||
double atol = 1e-08,
|
||||
bool equal_nan = false) {
|
||||
// Paddle's allclose returns a Tensor, but PyTorch's allclose returns bool.
|
||||
// The allclose kernel always sets output dtype to phi::DataType::BOOL via
|
||||
// kernel->OutputAt(0).SetDataType(phi::DataType::BOOL), so we read BOOL
|
||||
// directly.
|
||||
PaddleTensor result = paddle::experimental::allclose(self._PD_GetInner(),
|
||||
other._PD_GetInner(),
|
||||
phi::Scalar(rtol),
|
||||
phi::Scalar(atol),
|
||||
equal_nan);
|
||||
auto* result_tensor =
|
||||
std::dynamic_pointer_cast<phi::DenseTensor>(result.impl()).get();
|
||||
return *result_tensor->data<bool>();
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
// Tensor member function implementation
|
||||
inline bool Tensor::allclose(const at::Tensor& other,
|
||||
double rtol,
|
||||
double atol,
|
||||
bool equal_nan) const {
|
||||
return at::allclose(*this, other, rtol, atol, equal_nan);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/Scalar.h>
|
||||
#include <c10/util/OptionalArrayRef.h>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// any - free functions
|
||||
inline Tensor any(const Tensor& self, int64_t dim, bool keepdim = false) {
|
||||
return paddle::experimental::any(self._PD_GetInner(), {dim}, keepdim);
|
||||
}
|
||||
|
||||
inline Tensor any(const Tensor& self,
|
||||
at::OptionalIntArrayRef dim,
|
||||
bool keepdim = false) {
|
||||
std::vector<int64_t> dims_vec;
|
||||
if (dim.has_value() && dim.value().size() > 0) {
|
||||
dims_vec.assign(dim.value().begin(), dim.value().end());
|
||||
}
|
||||
return paddle::experimental::any(self._PD_GetInner(), dims_vec, keepdim);
|
||||
}
|
||||
|
||||
inline Tensor any(const Tensor& self) {
|
||||
return paddle::experimental::any(self._PD_GetInner());
|
||||
}
|
||||
|
||||
// any - member function implementations
|
||||
inline Tensor Tensor::any(int64_t dim, bool keepdim) const {
|
||||
return paddle::experimental::any(_PD_GetInner(), {dim}, keepdim);
|
||||
}
|
||||
|
||||
inline Tensor Tensor::any(at::OptionalIntArrayRef dim, bool keepdim) const {
|
||||
std::vector<int64_t> dims_vec;
|
||||
if (dim.has_value() && dim.value().size() > 0) {
|
||||
dims_vec.assign(dim.value().begin(), dim.value().end());
|
||||
}
|
||||
return paddle::experimental::any(_PD_GetInner(), dims_vec, keepdim);
|
||||
}
|
||||
|
||||
inline Tensor Tensor::any() const {
|
||||
return paddle::experimental::any(_PD_GetInner());
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,157 @@
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/native/RangeUtils.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline bool _PD_IsIntegralArangeScalar(const at::Scalar& scalar) {
|
||||
switch (scalar.dtype()) {
|
||||
case phi::DataType::BOOL:
|
||||
case phi::DataType::UINT8:
|
||||
case phi::DataType::INT8:
|
||||
case phi::DataType::UINT16:
|
||||
case phi::DataType::INT16:
|
||||
case phi::DataType::UINT32:
|
||||
case phi::DataType::INT32:
|
||||
case phi::DataType::UINT64:
|
||||
case phi::DataType::INT64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline at::ScalarType _PD_ResolveArangeDtype(const at::Scalar& start,
|
||||
const at::Scalar& end,
|
||||
const at::Scalar& step,
|
||||
const at::TensorOptions& options) {
|
||||
if (options.has_dtype()) {
|
||||
return options.dtype().toScalarType();
|
||||
}
|
||||
if (_PD_IsIntegralArangeScalar(start) && _PD_IsIntegralArangeScalar(end) &&
|
||||
_PD_IsIntegralArangeScalar(step)) {
|
||||
return at::kLong;
|
||||
}
|
||||
return c10::get_default_dtype_as_scalartype();
|
||||
}
|
||||
|
||||
inline paddle::Tensor _PD_MakeArangeScalarTensor(const at::Scalar& scalar,
|
||||
phi::DataType dtype) {
|
||||
return paddle::experimental::full({}, scalar, dtype, phi::CPUPlace());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
inline at::Tensor arange(const at::Scalar& start,
|
||||
const at::Scalar& end,
|
||||
const at::Scalar& step,
|
||||
at::TensorOptions options = {}) {
|
||||
// Match PyTorch: step must be non-zero and consistent with (end - start).
|
||||
at::native::arange_check_bounds(start, end, step);
|
||||
auto dtype = detail::_PD_ResolveArangeDtype(start, end, step, options);
|
||||
auto pd_dtype = compat::_PD_AtenScalarTypeToPhiDataType(dtype);
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::arange(
|
||||
detail::_PD_MakeArangeScalarTensor(start, pd_dtype),
|
||||
detail::_PD_MakeArangeScalarTensor(end, pd_dtype),
|
||||
detail::_PD_MakeArangeScalarTensor(step, pd_dtype),
|
||||
pd_dtype,
|
||||
phi::CPUPlace());
|
||||
return dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
return paddle::experimental::arange(
|
||||
detail::_PD_MakeArangeScalarTensor(start, pd_dtype),
|
||||
detail::_PD_MakeArangeScalarTensor(end, pd_dtype),
|
||||
detail::_PD_MakeArangeScalarTensor(step, pd_dtype),
|
||||
pd_dtype,
|
||||
options._PD_GetPlace());
|
||||
}
|
||||
|
||||
inline at::Tensor arange(const at::Scalar& end,
|
||||
at::TensorOptions options = {}) {
|
||||
return arange(/*start=*/0, end, /*step=*/1, options);
|
||||
}
|
||||
|
||||
inline at::Tensor arange(const at::Scalar& end,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype)
|
||||
.layout(layout)
|
||||
.device(device)
|
||||
.pinned_memory(pin_memory);
|
||||
return arange(/*start=*/0, end, /*step=*/1, options);
|
||||
}
|
||||
|
||||
inline at::Tensor arange(const at::Scalar& start,
|
||||
const at::Scalar& end,
|
||||
at::TensorOptions options = {}) {
|
||||
return arange(start, end, /*step=*/1, options);
|
||||
}
|
||||
|
||||
inline at::Tensor arange(const at::Scalar& start,
|
||||
const at::Scalar& end,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype)
|
||||
.layout(layout)
|
||||
.device(device)
|
||||
.pinned_memory(pin_memory);
|
||||
return arange(start, end, /*step=*/1, options);
|
||||
}
|
||||
|
||||
inline at::Tensor arange(const at::Scalar& start,
|
||||
const at::Scalar& end,
|
||||
const at::Scalar& step,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype)
|
||||
.layout(layout)
|
||||
.device(device)
|
||||
.pinned_memory(pin_memory);
|
||||
return arange(start, end, step, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/util/ArrayRef.h>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/ddim.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// as_strided: Create a tensor view with custom size, stride, and storage_offset
|
||||
inline at::Tensor Tensor::as_strided(
|
||||
at::IntArrayRef size,
|
||||
at::IntArrayRef stride,
|
||||
::std::optional<int64_t> storage_offset) const {
|
||||
// Materialize the compat StorageHolderView before creating the view so
|
||||
// aliasing tensors share one StorageImpl and observe later resize_ growth.
|
||||
(void)this->storage();
|
||||
auto src_impl = tensor_.impl();
|
||||
auto* src_tensor =
|
||||
std::dynamic_pointer_cast<phi::DenseTensor>(src_impl).get();
|
||||
if (!src_tensor) {
|
||||
PD_THROW("as_strided: tensor must be a DenseTensor");
|
||||
}
|
||||
// Create new meta with desired shape and strides first
|
||||
std::vector<int64_t> size_vec(size.begin(), size.end());
|
||||
std::vector<int64_t> stride_vec(stride.begin(), stride.end());
|
||||
|
||||
// Create new DenseTensor with correct meta, then share data
|
||||
// We need to create a temporary DenseTensor with the right meta
|
||||
// because ShareDataWith copies the source meta which we don't want
|
||||
auto new_tensor = std::make_shared<phi::DenseTensor>();
|
||||
|
||||
// First, set up the holder by sharing data (this copies src meta, we'll
|
||||
// override)
|
||||
new_tensor->ShareDataWith(*src_tensor);
|
||||
|
||||
// Now create the correct meta with new shape/strides
|
||||
phi::DenseTensorMeta meta(src_tensor->dtype(),
|
||||
common::make_ddim(size_vec),
|
||||
common::make_ddim(stride_vec));
|
||||
// Calculate offset in bytes
|
||||
int64_t offset = storage_offset.has_value() ? storage_offset.value() : 0;
|
||||
meta.offset = src_tensor->meta().offset +
|
||||
static_cast<size_t>(offset) * phi::SizeOf(src_tensor->dtype());
|
||||
new_tensor->set_meta(meta);
|
||||
PaddleTensor result;
|
||||
result.set_impl(new_tensor);
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
// as_strided_: Inplace version
|
||||
inline const at::Tensor& Tensor::as_strided_(
|
||||
at::IntArrayRef size,
|
||||
at::IntArrayRef stride,
|
||||
::std::optional<int64_t> storage_offset) const {
|
||||
// Keep inplace metadata-only view rewrites attached to the same compat
|
||||
// storage as the original tensor.
|
||||
(void)this->storage();
|
||||
auto src_impl = tensor_.impl();
|
||||
auto* src_tensor =
|
||||
std::dynamic_pointer_cast<phi::DenseTensor>(src_impl).get();
|
||||
if (!src_tensor) {
|
||||
PD_THROW("as_strided_: tensor must be a DenseTensor");
|
||||
}
|
||||
std::vector<int64_t> size_vec(size.begin(), size.end());
|
||||
std::vector<int64_t> stride_vec(stride.begin(), stride.end());
|
||||
// Use set_meta instead of Resize + set_strides to avoid contiguous check
|
||||
phi::DenseTensorMeta meta(src_tensor->dtype(),
|
||||
common::make_ddim(size_vec),
|
||||
common::make_ddim(stride_vec));
|
||||
meta.layout = src_tensor->layout();
|
||||
int64_t offset = storage_offset.has_value() ? storage_offset.value() : 0;
|
||||
meta.offset = src_tensor->meta().offset +
|
||||
static_cast<size_t>(offset) * phi::SizeOf(src_tensor->dtype());
|
||||
src_tensor->set_meta(meta);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// as_strided_scatter: Scatter src into a strided view
|
||||
// Returns a new tensor (copy of self) with the strided window filled by src.
|
||||
// The original tensor is NOT modified.
|
||||
inline at::Tensor Tensor::as_strided_scatter(
|
||||
const at::Tensor& src,
|
||||
at::IntArrayRef size,
|
||||
at::IntArrayRef stride,
|
||||
::std::optional<int64_t> storage_offset) const {
|
||||
// Clone self to an independent copy so the original tensor is left unchanged
|
||||
PaddleTensor self_copy = tensor_.copy_to(tensor_.place(), /*blocking=*/true);
|
||||
at::Tensor copy_tensor(self_copy);
|
||||
at::Tensor strided_view =
|
||||
copy_tensor.as_strided(size, stride, storage_offset);
|
||||
strided_view.copy_(src);
|
||||
return copy_tensor;
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <optional>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor cat(const at::ITensorListRef& tensors, int64_t dim = 0) {
|
||||
std::vector<paddle::Tensor> pd_tensors;
|
||||
pd_tensors.reserve(tensors.size());
|
||||
for (const auto& t : tensors) {
|
||||
pd_tensors.push_back(t._PD_GetInner());
|
||||
}
|
||||
return paddle::experimental::concat(pd_tensors, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// chunk - splits tensor into chunks
|
||||
inline std::vector<Tensor> chunk(const Tensor& self,
|
||||
int64_t chunks,
|
||||
int64_t dim = 0) {
|
||||
if (chunks <= 0) {
|
||||
PD_THROW("chunk expects chunks to be greater than 0, got ", chunks);
|
||||
}
|
||||
|
||||
std::vector<Tensor> result;
|
||||
paddle::Tensor pd_tensor = self._PD_GetInner();
|
||||
|
||||
int64_t rank = static_cast<int64_t>(pd_tensor.dims().size());
|
||||
if (rank == 0) {
|
||||
PD_THROW("chunk expects at least a 1-dimensional tensor");
|
||||
}
|
||||
|
||||
int64_t original_dim = dim;
|
||||
if (dim < 0) {
|
||||
dim += rank;
|
||||
}
|
||||
if (dim < 0 || dim >= rank) {
|
||||
PD_THROW("Dimension out of range (expected to be in range of [",
|
||||
-rank,
|
||||
", ",
|
||||
rank - 1,
|
||||
"], but got ",
|
||||
original_dim,
|
||||
")");
|
||||
}
|
||||
|
||||
int64_t dim_size = pd_tensor.dims()[dim];
|
||||
|
||||
if (dim_size == 0) {
|
||||
for (int64_t i = 0; i < chunks; ++i) {
|
||||
auto chunk_tensor =
|
||||
paddle::experimental::slice(pd_tensor, {dim}, {0}, {0}, {1}, {});
|
||||
result.push_back(Tensor(chunk_tensor));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// PyTorch returns at most 'dim_size' non-empty chunks when chunks > dim_size
|
||||
if (chunks > dim_size) {
|
||||
chunks = dim_size;
|
||||
}
|
||||
|
||||
int64_t chunk_size = (dim_size + chunks - 1) / chunks;
|
||||
int64_t remaining = dim_size;
|
||||
|
||||
for (int64_t i = 0; i < chunks && remaining > 0; ++i) {
|
||||
int64_t current_chunk_size = std::min(chunk_size, remaining);
|
||||
auto chunk_tensor =
|
||||
paddle::experimental::slice(pd_tensor,
|
||||
{dim},
|
||||
{i * chunk_size},
|
||||
{i * chunk_size + current_chunk_size},
|
||||
{1},
|
||||
{});
|
||||
result.push_back(Tensor(chunk_tensor));
|
||||
remaining -= current_chunk_size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
// Member function: Tensor::chunk
|
||||
inline std::vector<Tensor> Tensor::chunk(int64_t chunks, int64_t dim) const {
|
||||
return at::chunk(*this, chunks, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/core/TensorBase.h>
|
||||
#include <ATen/ops/full.h>
|
||||
#include <c10/core/Scalar.h>
|
||||
#include <c10/core/ScalarType.h>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include "paddle/phi/api/include/tensor.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// Helper function implementations
|
||||
namespace detail {
|
||||
inline at::Scalar get_default_min_value(c10::ScalarType dtype) {
|
||||
switch (dtype) {
|
||||
case c10::ScalarType::Byte:
|
||||
return at::Scalar(static_cast<uint8_t>(0));
|
||||
case c10::ScalarType::Char:
|
||||
return at::Scalar(std::numeric_limits<int8_t>::lowest());
|
||||
case c10::ScalarType::Short:
|
||||
return at::Scalar(std::numeric_limits<int16_t>::lowest());
|
||||
case c10::ScalarType::Int:
|
||||
return at::Scalar(std::numeric_limits<int32_t>::lowest());
|
||||
case c10::ScalarType::Long:
|
||||
return at::Scalar(std::numeric_limits<int64_t>::lowest());
|
||||
case c10::ScalarType::UInt16:
|
||||
return at::Scalar(static_cast<uint16_t>(0));
|
||||
case c10::ScalarType::UInt32:
|
||||
return at::Scalar(static_cast<uint32_t>(0));
|
||||
case c10::ScalarType::UInt64:
|
||||
return at::Scalar(static_cast<uint64_t>(0));
|
||||
case c10::ScalarType::Half:
|
||||
return at::Scalar(-std::numeric_limits<float>::infinity());
|
||||
case c10::ScalarType::Float:
|
||||
return at::Scalar(-std::numeric_limits<float>::infinity());
|
||||
case c10::ScalarType::Double:
|
||||
return at::Scalar(-std::numeric_limits<double>::infinity());
|
||||
case c10::ScalarType::BFloat16:
|
||||
return at::Scalar(-std::numeric_limits<float>::infinity());
|
||||
case c10::ScalarType::Bool:
|
||||
return at::Scalar(false);
|
||||
default:
|
||||
return at::Scalar(-std::numeric_limits<double>::infinity());
|
||||
}
|
||||
}
|
||||
|
||||
inline at::Scalar get_default_max_value(c10::ScalarType dtype) {
|
||||
switch (dtype) {
|
||||
case c10::ScalarType::Byte:
|
||||
return at::Scalar(std::numeric_limits<uint8_t>::max());
|
||||
case c10::ScalarType::Char:
|
||||
return at::Scalar(std::numeric_limits<int8_t>::max());
|
||||
case c10::ScalarType::Short:
|
||||
return at::Scalar(std::numeric_limits<int16_t>::max());
|
||||
case c10::ScalarType::Int:
|
||||
return at::Scalar(std::numeric_limits<int32_t>::max());
|
||||
case c10::ScalarType::Long:
|
||||
return at::Scalar(std::numeric_limits<int64_t>::max());
|
||||
case c10::ScalarType::UInt16:
|
||||
return at::Scalar(std::numeric_limits<uint16_t>::max());
|
||||
case c10::ScalarType::UInt32:
|
||||
return at::Scalar(std::numeric_limits<uint32_t>::max());
|
||||
case c10::ScalarType::UInt64:
|
||||
return at::Scalar(std::numeric_limits<uint64_t>::max());
|
||||
case c10::ScalarType::Half:
|
||||
return at::Scalar(std::numeric_limits<float>::infinity());
|
||||
case c10::ScalarType::Float:
|
||||
return at::Scalar(std::numeric_limits<float>::infinity());
|
||||
case c10::ScalarType::Double:
|
||||
return at::Scalar(std::numeric_limits<double>::infinity());
|
||||
case c10::ScalarType::BFloat16:
|
||||
return at::Scalar(std::numeric_limits<float>::infinity());
|
||||
case c10::ScalarType::Bool:
|
||||
return at::Scalar(true);
|
||||
default:
|
||||
return at::Scalar(std::numeric_limits<double>::infinity());
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::clamp(const ::std::optional<at::Scalar>& min,
|
||||
const ::std::optional<at::Scalar>& max) const {
|
||||
// Handle cases where min or max is nullopt - don't apply that bound
|
||||
if (min.has_value() && !max.has_value()) {
|
||||
// Only min is specified - use clamp_min
|
||||
return clamp_min(min.value());
|
||||
} else if (!min.has_value() && max.has_value()) {
|
||||
// Only max is specified - use clamp_max
|
||||
return clamp_max(max.value());
|
||||
} else if (!min.has_value() && !max.has_value()) {
|
||||
// Neither specified - return copy of tensor
|
||||
return *this;
|
||||
}
|
||||
// Both specified - apply full clamp
|
||||
return Tensor(paddle::experimental::clip(tensor_, min.value(), max.value()));
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::clamp(const ::std::optional<at::Tensor>& min,
|
||||
const ::std::optional<at::Tensor>& max) const {
|
||||
PaddleTensor result = tensor_;
|
||||
if (min.has_value()) {
|
||||
result = paddle::experimental::maximum(result, min.value()._PD_GetInner());
|
||||
}
|
||||
if (max.has_value()) {
|
||||
result = paddle::experimental::minimum(result, max.value()._PD_GetInner());
|
||||
}
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::clamp_(
|
||||
const ::std::optional<at::Scalar>& min,
|
||||
const ::std::optional<at::Scalar>& max) const {
|
||||
// Handle cases where min or max is nullopt - don't apply that bound
|
||||
if (min.has_value() && !max.has_value()) {
|
||||
// Only min is specified - use clamp_min_
|
||||
return clamp_min_(min.value());
|
||||
} else if (!min.has_value() && max.has_value()) {
|
||||
// Only max is specified - use clamp_max_
|
||||
return clamp_max_(max.value());
|
||||
} else if (!min.has_value() && !max.has_value()) {
|
||||
// Neither specified - nothing to do
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
// Both specified - apply full clamp
|
||||
paddle::experimental::clip_(
|
||||
const_cast<PaddleTensor&>(tensor_), min.value(), max.value());
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::clamp_(
|
||||
const ::std::optional<at::Tensor>& min,
|
||||
const ::std::optional<at::Tensor>& max) const {
|
||||
if (min.has_value()) {
|
||||
PaddleTensor temp =
|
||||
paddle::experimental::maximum(tensor_, min.value()._PD_GetInner());
|
||||
const_cast<PaddleTensor&>(tensor_) = temp;
|
||||
}
|
||||
if (max.has_value()) {
|
||||
PaddleTensor temp =
|
||||
paddle::experimental::minimum(tensor_, max.value()._PD_GetInner());
|
||||
const_cast<PaddleTensor&>(tensor_) = temp;
|
||||
}
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::clamp_max(const at::Scalar& max) const {
|
||||
// Create a tensor with the same shape filled with the max value
|
||||
at::Tensor max_tensor = at::full(tensor_.shape(), max, {});
|
||||
return clamp_max(max_tensor);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::clamp_max(const at::Tensor& max) const {
|
||||
return Tensor(paddle::experimental::minimum(tensor_, max._PD_GetInner()));
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::clamp_max_(const at::Scalar& max) const {
|
||||
// Create a tensor with the same shape filled with the max value
|
||||
at::Tensor max_tensor = at::full(tensor_.shape(), max, {});
|
||||
return clamp_max_(max_tensor);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::clamp_max_(const at::Tensor& max) const {
|
||||
PaddleTensor temp =
|
||||
paddle::experimental::minimum(tensor_, max._PD_GetInner());
|
||||
const_cast<PaddleTensor&>(tensor_) = temp;
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::clamp_min(const at::Scalar& min) const {
|
||||
// Create a tensor with the same shape filled with the min value
|
||||
at::Tensor min_tensor = at::full(tensor_.shape(), min, {});
|
||||
return clamp_min(min_tensor);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::clamp_min(const at::Tensor& min) const {
|
||||
return Tensor(paddle::experimental::maximum(tensor_, min._PD_GetInner()));
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::clamp_min_(const at::Scalar& min) const {
|
||||
// Create a tensor with the same shape filled with the min value
|
||||
at::Tensor min_tensor = at::full(tensor_.shape(), min, {});
|
||||
return clamp_min_(min_tensor);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::clamp_min_(const at::Tensor& min) const {
|
||||
PaddleTensor temp =
|
||||
paddle::experimental::maximum(tensor_, min._PD_GetInner());
|
||||
const_cast<PaddleTensor&>(tensor_) = temp;
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include "paddle/phi/api/include/sparse_api.h"
|
||||
|
||||
namespace at {} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::coalesce() const {
|
||||
PD_CHECK(layout() == kSparse,
|
||||
"coalesce expected sparse coordinate tensor layout but got ",
|
||||
layout());
|
||||
if (is_coalesced()) {
|
||||
return *this;
|
||||
}
|
||||
return paddle::experimental::sparse::coalesce(tensor_);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor detach(const at::Tensor& self) {
|
||||
// Create a new Tensor that shares data but has no autograd history
|
||||
auto inner = self._PD_GetInner();
|
||||
PaddleTensor detached_tensor(inner.impl());
|
||||
detached_tensor.set_name(inner.name());
|
||||
detached_tensor.set_autograd_meta(nullptr);
|
||||
return Tensor(detached_tensor);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::detach() const { return at::detach(*this); }
|
||||
|
||||
inline at::Tensor& Tensor::detach_() const {
|
||||
// In-place version: clear autograd meta of current tensor
|
||||
PaddleTensor& inner = const_cast<PaddleTensor&>(tensor_);
|
||||
inner.set_autograd_meta(nullptr);
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/tensor_split.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> dsplit(const at::Tensor& self,
|
||||
int64_t sections) {
|
||||
return tensor_split(self, sections, 2);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> dsplit(const at::Tensor& self,
|
||||
at::IntArrayRef indices) {
|
||||
return tensor_split(self, indices, 2);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::dsplit(int64_t sections) const {
|
||||
return at::dsplit(*this, sections);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::dsplit(at::IntArrayRef indices) const {
|
||||
return at::dsplit(*this, indices);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,75 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/dense_sparse_conversion.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor empty(
|
||||
at::IntArrayRef size,
|
||||
at::TensorOptions options = {},
|
||||
::std::optional<at::MemoryFormat> memory_format = ::std::nullopt) {
|
||||
PD_CHECK(!(memory_format.has_value() &&
|
||||
memory_format.value() != c10::MemoryFormat::Contiguous),
|
||||
"`MemoryFormat` other than Contiguous is not supported now.");
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
auto dense = paddle::experimental::empty(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
dense = dense.copy_to(phi::GPUPinnedPlace(), /*blocking=*/true);
|
||||
return compat::_PD_ConvertToSparseIfNeeded(dense, options.layout());
|
||||
}
|
||||
auto dense = paddle::experimental::empty(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
return compat::_PD_ConvertToSparseIfNeeded(dense, options.layout());
|
||||
}
|
||||
|
||||
inline at::Tensor empty(at::IntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory,
|
||||
::std::optional<at::MemoryFormat> memory_format) {
|
||||
PD_CHECK(!(memory_format.has_value() &&
|
||||
memory_format.value() != c10::MemoryFormat::Contiguous),
|
||||
"`MemoryFormat` other than Contiguous is not supported now.");
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.layout(layout)
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return empty(size, options, memory_format);
|
||||
}
|
||||
|
||||
#define empty_symint empty // SymIntArrayRef is same as IntArrayRef
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,81 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/dense_sparse_conversion.h>
|
||||
#include <utils/pinned_place.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor empty_like(
|
||||
const at::Tensor& self,
|
||||
at::TensorOptions options = {},
|
||||
::std::optional<at::MemoryFormat> memory_format = ::std::nullopt) {
|
||||
PD_CHECK(!(memory_format.has_value() &&
|
||||
memory_format.value() != c10::MemoryFormat::Contiguous),
|
||||
"`MemoryFormat` other than Contiguous is not supported now.");
|
||||
|
||||
auto dtype = options.dtype_opt().value_or(self.dtype());
|
||||
paddle::Tensor dense;
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
auto dense_cpu = paddle::experimental::empty_like(
|
||||
self._PD_GetInner(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(dtype),
|
||||
phi::CPUPlace());
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
dense = dense_cpu.copy_to(pinned_place, /*blocking=*/true);
|
||||
} else {
|
||||
auto place = options.device_opt().value_or(self.device());
|
||||
dense = paddle::experimental::empty_like(
|
||||
self._PD_GetInner(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(dtype),
|
||||
place._PD_GetInner());
|
||||
}
|
||||
return compat::_PD_ConvertToSparseIfNeeded(dense, options.layout());
|
||||
}
|
||||
|
||||
inline at::Tensor empty_like(const at::Tensor& self,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory,
|
||||
::std::optional<at::MemoryFormat> memory_format) {
|
||||
PD_CHECK(!(memory_format.has_value() &&
|
||||
memory_format.value() != c10::MemoryFormat::Contiguous),
|
||||
"`MemoryFormat` other than Contiguous is not supported now.");
|
||||
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype)
|
||||
.layout(layout)
|
||||
.device(device)
|
||||
.pinned_memory(pin_memory);
|
||||
return empty_like(self, options, memory_format);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,41 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <c10/util/ArrayRef.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor empty_strided(at::IntArrayRef size,
|
||||
at::IntArrayRef stride,
|
||||
at::TensorOptions options = {}) {
|
||||
auto empty_tensor = paddle::experimental::empty(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
|
||||
return paddle::experimental::as_strided(
|
||||
empty_tensor,
|
||||
std::vector<int64_t>(size.begin(), size.end()),
|
||||
std::vector<int64_t>(stride.begin(), stride.end()));
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/item.h>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline bool equal(const at::Tensor& self, const at::Tensor& other) {
|
||||
PD_CHECK(self.defined(),
|
||||
"Expected a proper Tensor but got None (or an undefined Tensor in "
|
||||
"C++)");
|
||||
PD_CHECK(other.defined(),
|
||||
"Expected a proper Tensor but got None (or an undefined Tensor in "
|
||||
"C++)");
|
||||
PD_CHECK(self.device() == other.device(),
|
||||
"Cannot compare two tensors on "
|
||||
"different devices. Got: ",
|
||||
self.device(),
|
||||
" and ",
|
||||
other.device());
|
||||
if (self.sizes() != other.sizes()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lhs = self._PD_GetInner();
|
||||
auto rhs = other._PD_GetInner();
|
||||
if (self.scalar_type() != other.scalar_type()) {
|
||||
rhs = paddle::experimental::cast(
|
||||
rhs, compat::_PD_AtenScalarTypeToPhiDataType(self.scalar_type()));
|
||||
}
|
||||
|
||||
auto result = paddle::experimental::equal_all(lhs, rhs);
|
||||
return at::Tensor(std::move(result)).item<bool>();
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline bool Tensor::equal(const at::Tensor& other) const {
|
||||
return at::equal(*this, other);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// expand - expands tensor to new size
|
||||
// PyTorch's expand works by right-aligning dimensions and broadcasting
|
||||
// dimensions with size 1 to the target size
|
||||
// Unlike Paddle's expand_v2, PyTorch allows non-singleton dimensions to be
|
||||
// preserved when they match the corresponding target dimension
|
||||
inline Tensor expand(const Tensor& self,
|
||||
at::IntArrayRef size,
|
||||
bool implicit = false) {
|
||||
// implicit parameter is used by PyTorch's vmap for internal optimization.
|
||||
// It doesn't affect the actual expand operation, so we can safely ignore it.
|
||||
|
||||
paddle::Tensor pd_tensor = self._PD_GetInner();
|
||||
|
||||
// Target sizes - convert to vector
|
||||
std::vector<int64_t> target_size_vec(size.begin(), size.end());
|
||||
auto target_rank = target_size_vec.size();
|
||||
auto input_dims = pd_tensor.dims();
|
||||
auto input_rank = static_cast<size_t>(input_dims.size());
|
||||
|
||||
// PyTorch's expand uses right-alignment semantics:
|
||||
// - For 1D tensor expand to 2D: {3}.expand({3,4}) treats input as {3,1},
|
||||
// expands to {3,4}
|
||||
// - Non-singleton dimensions are preserved, singleton dimensions (1) can
|
||||
// expand
|
||||
//
|
||||
// For example:
|
||||
// {3}.expand({3, 4}) -> input {3} becomes {3, 1} implicitly
|
||||
// then expand: dim 0: 3 stays 3, dim 1: 1 -> 4 -> result {3, 4}
|
||||
|
||||
if (input_rank < target_rank) {
|
||||
// Add leading 1s to right-align with target shape (PyTorch behavior)
|
||||
// Input {1, 2}, target {2, 3, 2} -> reshape to {1, 1, 2}
|
||||
std::vector<int64_t> reshape_vec(target_rank, 1);
|
||||
for (size_t i = 0; i < input_rank; ++i) {
|
||||
reshape_vec[target_rank - input_rank + i] = input_dims[i];
|
||||
}
|
||||
|
||||
// Check if Paddle's expand can handle this right-aligned shape
|
||||
// Paddle allows: input[i] == 1 (can expand), or input[i] == target[i]
|
||||
// (match)
|
||||
bool can_use_paddle_expand = true;
|
||||
size_t fail_dim = 0;
|
||||
for (size_t i = 0; i < target_rank; ++i) {
|
||||
bool dim_can_expand = (reshape_vec[i] == 1);
|
||||
bool dim_is_matching = (reshape_vec[i] == target_size_vec[i]);
|
||||
if (!dim_can_expand && !dim_is_matching) {
|
||||
can_use_paddle_expand = false;
|
||||
fail_dim = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_use_paddle_expand) {
|
||||
// Reshape to right-aligned shape, then expand
|
||||
paddle::Tensor reshaped =
|
||||
paddle::experimental::reshape(pd_tensor, phi::IntArray(reshape_vec));
|
||||
paddle::Tensor result = paddle::experimental::expand(
|
||||
reshaped, phi::IntArray(target_size_vec));
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
PD_THROW("expand(): the expanded size of the tensor (",
|
||||
target_size_vec[fail_dim],
|
||||
") must match the existing size (",
|
||||
reshape_vec[fail_dim],
|
||||
") at non-singleton dimension ",
|
||||
fail_dim,
|
||||
".");
|
||||
} else if (input_rank == target_rank) {
|
||||
// Same rank - check if we can use expand directly
|
||||
bool can_use_paddle_expand = true;
|
||||
size_t fail_dim = 0;
|
||||
for (size_t i = 0; i < target_rank; ++i) {
|
||||
auto in_size = input_dims[i];
|
||||
auto target_size = target_size_vec[i];
|
||||
if (in_size != 1 && in_size != target_size) {
|
||||
can_use_paddle_expand = false;
|
||||
fail_dim = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_use_paddle_expand) {
|
||||
paddle::Tensor result = paddle::experimental::expand(
|
||||
pd_tensor, phi::IntArray(target_size_vec));
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
PD_THROW("expand(): the expanded size of the tensor (",
|
||||
target_size_vec[fail_dim],
|
||||
") must match the existing size (",
|
||||
input_dims[fail_dim],
|
||||
") at non-singleton dimension ",
|
||||
fail_dim,
|
||||
".");
|
||||
} else {
|
||||
PD_THROW("expand(): the number of sizes provided (",
|
||||
target_rank,
|
||||
") must be greater or equal to the number of dimensions in the "
|
||||
"tensor (",
|
||||
input_rank,
|
||||
").");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
// Member function: Tensor::expand
|
||||
inline Tensor Tensor::expand(at::IntArrayRef size, bool implicit) const {
|
||||
return at::expand(*this, size, implicit);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/expand.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline Tensor Tensor::expand_as(const Tensor& other) const {
|
||||
return at::expand(*this, other.sizes());
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// eye(n) — n×n identity matrix
|
||||
inline at::Tensor eye(int64_t n, at::TensorOptions options = {}) {
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::eye(
|
||||
n,
|
||||
/*num_columns=*/-1,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
return dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
return paddle::experimental::eye(
|
||||
n,
|
||||
/*num_columns=*/-1,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
}
|
||||
|
||||
// eye(n, m) — n×m identity-like matrix
|
||||
inline at::Tensor eye(int64_t n, int64_t m, at::TensorOptions options = {}) {
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::eye(
|
||||
n,
|
||||
m,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
return dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
return paddle::experimental::eye(
|
||||
n,
|
||||
m,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
}
|
||||
|
||||
// eye(n, dtype, layout, device, pin_memory)
|
||||
inline at::Tensor eye(int64_t n,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
PD_CHECK(!layout.has_value(), "`layout` is not supported now.");
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return eye(n, options);
|
||||
}
|
||||
|
||||
// eye(n, m, dtype, layout, device, pin_memory)
|
||||
inline at::Tensor eye(int64_t n,
|
||||
int64_t m,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
PD_CHECK(!layout.has_value(), "`layout` is not supported now.");
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return eye(n, m, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor flatten(const at::Tensor& self,
|
||||
int64_t start_dim = 0,
|
||||
int64_t end_dim = -1) {
|
||||
return Tensor(paddle::experimental::flatten(self._PD_GetInner(),
|
||||
static_cast<int>(start_dim),
|
||||
static_cast<int>(end_dim)));
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::flatten(int64_t start_dim, int64_t end_dim) const {
|
||||
return at::flatten(*this, start_dim, end_dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,219 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
#include "paddle/phi/api/include/tensor_utils.h"
|
||||
namespace at {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline void noopDelete(void* /*unused*/) {}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class TensorMaker {
|
||||
friend TensorMaker for_blob(void* data, IntArrayRef sizes) noexcept;
|
||||
|
||||
public:
|
||||
using ContextDeleter = DeleterFnPtr;
|
||||
|
||||
TensorMaker& strides(OptionalIntArrayRef value) noexcept {
|
||||
strides_ = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TensorMaker& storage_offset(std::optional<int64_t> value) noexcept {
|
||||
storage_offset_ = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TensorMaker& deleter(std::function<void(void*)> value) noexcept {
|
||||
deleter_ = std::move(value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TensorMaker& context(void* value, ContextDeleter deleter = nullptr) noexcept {
|
||||
ctx_ = std::unique_ptr<void, ContextDeleter>{
|
||||
value, deleter != nullptr ? deleter : detail::noopDelete};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TensorMaker& target_device(std::optional<Device> value) noexcept {
|
||||
device_ = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TensorMaker& options(TensorOptions value) noexcept {
|
||||
opts_ = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TensorMaker& resizeable_storage() noexcept {
|
||||
resizeable_ = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tensor make_tensor() {
|
||||
PD_CHECK(!deleter_ || !ctx_,
|
||||
"The deleter and context arguments are mutually exclusive.");
|
||||
|
||||
PD_CHECK(!storage_offset_.has_value() || storage_offset_.value() == 0,
|
||||
"storage_offset` should be zero.");
|
||||
|
||||
if (device_.has_value() && opts_.has_device() &&
|
||||
opts_.device().has_index()) {
|
||||
PD_CHECK(opts_.device() == *device_,
|
||||
"Specified device ",
|
||||
opts_.device(),
|
||||
" does not match device of data ",
|
||||
*device_);
|
||||
}
|
||||
|
||||
phi::Place pd_place;
|
||||
if (device_.has_value()) {
|
||||
pd_place = device_->_PD_GetInner();
|
||||
} else if (opts_.has_device() && opts_.device().has_index()) {
|
||||
pd_place = opts_.device()._PD_GetInner();
|
||||
} else {
|
||||
pd_place = phi::Place(); // UNDEFINED → auto-detect inside from_blob
|
||||
}
|
||||
|
||||
// Build paddle deleter: prefer explicit deleter_, then wrap ctx_ so its
|
||||
// lifetime is tied to the tensor allocation.
|
||||
paddle::Deleter pd_deleter = nullptr;
|
||||
if (deleter_) {
|
||||
pd_deleter = deleter_;
|
||||
} else if (ctx_) {
|
||||
// shared_ptr takes ownership of the context and calls its deleter when
|
||||
// the last copy (held in the lambda) is destroyed.
|
||||
auto shared_ctx =
|
||||
std::shared_ptr<void>(ctx_.release(), ctx_.get_deleter());
|
||||
pd_deleter = [shared_ctx](void* /*data*/) {};
|
||||
}
|
||||
|
||||
if (strides_.has_value()) {
|
||||
return paddle::from_blob(
|
||||
data_,
|
||||
sizes_._PD_ToPaddleIntArray(),
|
||||
strides_.value()._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(opts_.dtype()),
|
||||
phi::DataLayout::NCHW,
|
||||
pd_place,
|
||||
pd_deleter);
|
||||
} else {
|
||||
return paddle::from_blob(
|
||||
data_,
|
||||
sizes_._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(opts_.dtype()),
|
||||
phi::DataLayout::NCHW,
|
||||
pd_place,
|
||||
pd_deleter);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
explicit TensorMaker(void* data, IntArrayRef sizes) noexcept
|
||||
: data_{data}, sizes_{sizes} {}
|
||||
|
||||
std::size_t computeStorageSize() const noexcept;
|
||||
|
||||
DataPtr makeDataPtrFromDeleter() noexcept;
|
||||
|
||||
DataPtr makeDataPtrFromContext() noexcept;
|
||||
|
||||
IntArrayRef makeTempSizes() const noexcept;
|
||||
|
||||
void* data_;
|
||||
IntArrayRef sizes_;
|
||||
OptionalIntArrayRef strides_;
|
||||
std::optional<int64_t> storage_offset_;
|
||||
std::function<void(void*)> deleter_;
|
||||
std::unique_ptr<void, ContextDeleter> ctx_{nullptr, detail::noopDelete};
|
||||
std::optional<Device> device_;
|
||||
TensorOptions opts_;
|
||||
bool resizeable_{};
|
||||
};
|
||||
|
||||
inline TensorMaker for_blob(void* data, IntArrayRef sizes) noexcept {
|
||||
return TensorMaker{data, sizes};
|
||||
}
|
||||
|
||||
inline Tensor from_blob(
|
||||
void* data,
|
||||
IntArrayRef sizes,
|
||||
IntArrayRef strides,
|
||||
const std::function<void(void*)>& deleter,
|
||||
const TensorOptions& options = {},
|
||||
const std::optional<Device> target_device = std::nullopt) {
|
||||
return for_blob(data, sizes)
|
||||
.strides(strides)
|
||||
.deleter(deleter)
|
||||
.options(options)
|
||||
.target_device(target_device)
|
||||
.make_tensor();
|
||||
}
|
||||
|
||||
inline Tensor from_blob(
|
||||
void* data,
|
||||
IntArrayRef sizes,
|
||||
IntArrayRef strides,
|
||||
int64_t storage_offset,
|
||||
const std::function<void(void*)>& deleter,
|
||||
const TensorOptions& options = {},
|
||||
const std::optional<Device> target_device = std::nullopt) {
|
||||
return for_blob(data, sizes)
|
||||
.strides(strides)
|
||||
.storage_offset(storage_offset)
|
||||
.deleter(deleter)
|
||||
.options(options)
|
||||
.target_device(target_device)
|
||||
.make_tensor();
|
||||
}
|
||||
|
||||
inline Tensor from_blob(
|
||||
void* data,
|
||||
IntArrayRef sizes,
|
||||
std::function<void(void*)> deleter,
|
||||
const TensorOptions& options = {},
|
||||
const std::optional<Device> target_device = std::nullopt) {
|
||||
return for_blob(data, sizes)
|
||||
.deleter(std::move(deleter))
|
||||
.options(options)
|
||||
.target_device(target_device)
|
||||
.make_tensor();
|
||||
}
|
||||
|
||||
inline Tensor from_blob(void* data,
|
||||
IntArrayRef sizes,
|
||||
IntArrayRef strides,
|
||||
const TensorOptions& options = {}) {
|
||||
return for_blob(data, sizes).strides(strides).options(options).make_tensor();
|
||||
}
|
||||
|
||||
inline Tensor from_blob(void* data,
|
||||
IntArrayRef sizes,
|
||||
const TensorOptions& options = {}) {
|
||||
return for_blob(data, sizes).options(options).make_tensor();
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,104 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/SymIntArrayRef.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor full(at::IntArrayRef size,
|
||||
const at::Scalar& fill_value,
|
||||
at::TensorOptions options = {}) {
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::full(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
fill_value,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
return dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
return paddle::experimental::full(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
fill_value,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
}
|
||||
|
||||
inline at::Tensor full(at::IntArrayRef size,
|
||||
const at::Scalar& fill_value,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
PD_CHECK(!layout.has_value(), "`layout` is not supported now.");
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return full(size, fill_value, options);
|
||||
}
|
||||
|
||||
inline at::Tensor full_symint(c10::SymIntArrayRef size,
|
||||
const at::Scalar& fill_value,
|
||||
at::TensorOptions options = {}) {
|
||||
if (options.pinned_memory()) {
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::full(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
fill_value,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
return dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
return paddle::experimental::full(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
fill_value,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
}
|
||||
|
||||
inline at::Tensor full_symint(c10::SymIntArrayRef size,
|
||||
const at::Scalar& fill_value,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
PD_CHECK(!layout.has_value(), "`layout` is not supported now.");
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return full_symint(size, fill_value, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/tensor_split.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> hsplit(const at::Tensor& self,
|
||||
int64_t sections) {
|
||||
// For 1D tensors, split along dim 0; otherwise split along dim 1
|
||||
int64_t dim = self._PD_GetInner().dims().size() == 1 ? 0 : 1;
|
||||
return at::tensor_split(self, sections, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> hsplit(const at::Tensor& self,
|
||||
at::IntArrayRef indices) {
|
||||
int64_t dim = self._PD_GetInner().dims().size() == 1 ? 0 : 1;
|
||||
return at::tensor_split(self, indices, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::hsplit(int64_t sections) const {
|
||||
return at::hsplit(*this, sections);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::hsplit(at::IntArrayRef indices) const {
|
||||
return at::hsplit(*this, indices);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,203 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/TensorIndexing.h>
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/List.h>
|
||||
|
||||
namespace at::indexing {
|
||||
|
||||
inline TensorIndex::TensorIndex(const at::Tensor& tensor)
|
||||
: tensor_(std::make_shared<at::Tensor>(tensor)),
|
||||
type_(TensorIndexType::Tensor) {}
|
||||
|
||||
inline const at::Tensor& TensorIndex::tensor() const { return *tensor_; }
|
||||
|
||||
} // namespace at::indexing
|
||||
|
||||
namespace at::detail {
|
||||
|
||||
inline bool _PD_is_full_slice(const at::indexing::Slice& slice) {
|
||||
return static_cast<int64_t>(slice.start()) == 0 &&
|
||||
static_cast<int64_t>(slice.stop()) == at::indexing::INDEX_MAX &&
|
||||
static_cast<int64_t>(slice.step()) == 1;
|
||||
}
|
||||
|
||||
inline at::Tensor _PD_apply_tensor_index(
|
||||
const at::Tensor& self, ArrayRef<at::indexing::TensorIndex> indices) {
|
||||
int64_t output_dim = 0;
|
||||
int tensor_index_count = 0;
|
||||
at::Tensor result = self;
|
||||
|
||||
for (const auto& index : indices) {
|
||||
if (index.is_tensor()) {
|
||||
++tensor_index_count;
|
||||
PD_CHECK(tensor_index_count == 1,
|
||||
"Multiple tensor indices mixed with None/Slice are not "
|
||||
"supported yet.");
|
||||
result = paddle::experimental::index_select(
|
||||
result._PD_GetInner(), index.tensor()._PD_GetInner(), output_dim);
|
||||
++output_dim;
|
||||
} else if (index.is_none()) {
|
||||
result =
|
||||
paddle::experimental::unsqueeze(result._PD_GetInner(), {output_dim});
|
||||
++output_dim;
|
||||
} else if (index.is_slice()) {
|
||||
const auto& slice = index.slice();
|
||||
PD_CHECK(_PD_is_full_slice(slice),
|
||||
"Only full Slice() is supported when mixed with tensor/None "
|
||||
"indices.");
|
||||
++output_dim;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline at::Tensor _PD_index_tensor_indices(
|
||||
const at::Tensor& self, ArrayRef<at::indexing::TensorIndex> indices) {
|
||||
if (indices.size() == 0) {
|
||||
PD_THROW("index() cannot be called with an empty index list");
|
||||
}
|
||||
|
||||
bool has_slice = false;
|
||||
bool has_tensor_like = false;
|
||||
for (const auto& index : indices) {
|
||||
has_slice = has_slice || index.is_slice();
|
||||
has_tensor_like = has_tensor_like || index.is_tensor() || index.is_none();
|
||||
PD_CHECK(!index.is_ellipsis(), "Ellipsis index is not supported yet.");
|
||||
PD_CHECK(!index.is_integer(), "Integer index is not supported yet.");
|
||||
PD_CHECK(!index.is_boolean(), "Boolean index is not supported yet.");
|
||||
}
|
||||
|
||||
if (has_slice && !has_tensor_like) {
|
||||
std::vector<int64_t> axes;
|
||||
std::vector<int64_t> starts;
|
||||
std::vector<int64_t> ends;
|
||||
std::vector<int64_t> strides;
|
||||
axes.reserve(indices.size());
|
||||
starts.reserve(indices.size());
|
||||
ends.reserve(indices.size());
|
||||
strides.reserve(indices.size());
|
||||
|
||||
int64_t dim = 0;
|
||||
for (const auto& index : indices) {
|
||||
const auto& slice = index.slice();
|
||||
axes.push_back(dim++);
|
||||
starts.push_back(static_cast<int64_t>(slice.start()));
|
||||
ends.push_back(static_cast<int64_t>(slice.stop()));
|
||||
strides.push_back(static_cast<int64_t>(slice.step()));
|
||||
}
|
||||
|
||||
return paddle::experimental::slice(
|
||||
self._PD_GetInner(), axes, starts, ends, strides, {});
|
||||
}
|
||||
|
||||
if (has_slice) {
|
||||
return _PD_apply_tensor_index(self, indices);
|
||||
}
|
||||
|
||||
c10::List<::std::optional<at::Tensor>> tensor_indices;
|
||||
for (const auto& index : indices) {
|
||||
if (index.is_none()) {
|
||||
tensor_indices.push_back(::std::nullopt);
|
||||
} else if (index.is_tensor()) {
|
||||
tensor_indices.push_back(index.tensor());
|
||||
}
|
||||
}
|
||||
return self.index(tensor_indices);
|
||||
}
|
||||
|
||||
} // namespace at::detail
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor index(const at::Tensor& self,
|
||||
const c10::List<::std::optional<at::Tensor>>& indices) {
|
||||
if (indices.empty()) {
|
||||
return self;
|
||||
}
|
||||
|
||||
bool all_none = true;
|
||||
for (const auto& idx : indices) {
|
||||
if (idx.has_value()) {
|
||||
all_none = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_none) {
|
||||
return self;
|
||||
}
|
||||
|
||||
std::vector<paddle::Tensor> pd_indices;
|
||||
std::vector<bool> has_index(indices.size(), false);
|
||||
pd_indices.reserve(indices.size());
|
||||
|
||||
for (size_t i = 0; i < indices.size(); ++i) {
|
||||
if (indices[i].has_value()) {
|
||||
pd_indices.push_back(indices[i].value()._PD_GetInner());
|
||||
has_index[i] = true;
|
||||
} else {
|
||||
pd_indices.push_back(paddle::Tensor());
|
||||
}
|
||||
}
|
||||
|
||||
int non_none_count = 0;
|
||||
size_t first_non_none = 0;
|
||||
for (size_t i = 0; i < has_index.size(); ++i) {
|
||||
if (has_index[i]) {
|
||||
non_none_count++;
|
||||
first_non_none = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (non_none_count == 1 && first_non_none == 0) {
|
||||
return paddle::experimental::index_select(
|
||||
self._PD_GetInner(), pd_indices[0], 0);
|
||||
}
|
||||
|
||||
if (non_none_count == static_cast<int>(indices.size())) {
|
||||
auto stacked_indices = paddle::experimental::stack(pd_indices, -1);
|
||||
return paddle::experimental::gather_nd(self._PD_GetInner(),
|
||||
stacked_indices);
|
||||
}
|
||||
|
||||
auto self_dims = self._PD_GetInner().dims();
|
||||
int self_rank = self_dims.size();
|
||||
at::Tensor result = self;
|
||||
|
||||
for (size_t i = 0; i < indices.size() && i < static_cast<size_t>(self_rank);
|
||||
++i) {
|
||||
if (has_index[i]) {
|
||||
paddle::Tensor pd_result = result._PD_GetInner();
|
||||
result = paddle::experimental::index_select(
|
||||
pd_result, pd_indices[i], static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::index(
|
||||
ArrayRef<at::indexing::TensorIndex> indices) const {
|
||||
return at::detail::_PD_index_tensor_indices(*this, indices);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,205 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/index.h>
|
||||
#include <c10/core/List.h>
|
||||
#include <c10/core/Scalar.h>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at::detail {
|
||||
|
||||
inline std::vector<at::Tensor> _PD_convert_indices_list(
|
||||
const c10::List<::std::optional<at::Tensor>>& indices) {
|
||||
std::vector<at::Tensor> result;
|
||||
result.reserve(indices.size());
|
||||
for (const auto& idx : indices) {
|
||||
if (idx.has_value()) {
|
||||
result.push_back(idx.value());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline c10::List<::std::optional<at::Tensor>> _PD_convert_tensor_index_list(
|
||||
ArrayRef<at::indexing::TensorIndex> indices) {
|
||||
c10::List<::std::optional<at::Tensor>> result;
|
||||
for (const auto& index : indices) {
|
||||
PD_CHECK(!index.is_ellipsis(), "Ellipsis index is not supported yet.");
|
||||
PD_CHECK(!index.is_integer(), "Integer index is not supported yet.");
|
||||
PD_CHECK(!index.is_boolean(), "Boolean index is not supported yet.");
|
||||
if (index.is_slice()) {
|
||||
PD_CHECK(_PD_is_full_slice(index.slice()),
|
||||
"Only full Slice() is supported in index_put_ TensorIndex "
|
||||
"paths.");
|
||||
} else if (index.is_tensor()) {
|
||||
result.push_back(index.tensor());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline at::Tensor _PD_squeeze_newaxis_value(
|
||||
const at::Tensor& values, ArrayRef<at::indexing::TensorIndex> indices) {
|
||||
std::vector<int64_t> value_shape(values.sizes().begin(),
|
||||
values.sizes().end());
|
||||
size_t value_dim = 0;
|
||||
bool changed = false;
|
||||
|
||||
for (const auto& index : indices) {
|
||||
if (index.is_none()) {
|
||||
if (!value_shape.empty()) {
|
||||
PD_CHECK(value_dim < value_shape.size(),
|
||||
"index_put_ value rank is too small for None index.");
|
||||
PD_CHECK(value_shape[value_dim] == 1,
|
||||
"index_put_ expected value dimension inserted by None to "
|
||||
"have size 1, but got ",
|
||||
value_shape[value_dim],
|
||||
".");
|
||||
value_shape.erase(value_shape.begin() + value_dim);
|
||||
changed = true;
|
||||
}
|
||||
} else if (index.is_tensor()) {
|
||||
if (!value_shape.empty()) {
|
||||
++value_dim;
|
||||
}
|
||||
} else if (index.is_slice()) {
|
||||
PD_CHECK(_PD_is_full_slice(index.slice()),
|
||||
"Only full Slice() is supported in index_put_ TensorIndex "
|
||||
"paths.");
|
||||
if (!value_shape.empty()) {
|
||||
++value_dim;
|
||||
}
|
||||
} else {
|
||||
PD_CHECK(!index.is_ellipsis(), "Ellipsis index is not supported yet.");
|
||||
PD_CHECK(!index.is_integer(), "Integer index is not supported yet.");
|
||||
PD_CHECK(!index.is_boolean(), "Boolean index is not supported yet.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
return values;
|
||||
}
|
||||
return paddle::experimental::reshape(values._PD_GetInner(),
|
||||
phi::IntArray(value_shape));
|
||||
}
|
||||
|
||||
} // namespace at::detail
|
||||
|
||||
namespace at {
|
||||
|
||||
// index_put_: Set values at specified indices (in-place)
|
||||
inline at::Tensor& index_put_(
|
||||
at::Tensor& self, // NOLINT(runtime/references)
|
||||
const c10::List<::std::optional<at::Tensor>>& indices,
|
||||
const at::Tensor& values,
|
||||
bool accumulate = false) {
|
||||
std::vector<paddle::Tensor> pd_indices;
|
||||
pd_indices.reserve(indices.size());
|
||||
for (const auto& idx : indices) {
|
||||
if (idx.has_value()) {
|
||||
pd_indices.push_back(idx.value()._PD_GetInner());
|
||||
}
|
||||
}
|
||||
|
||||
paddle::experimental::index_put_(
|
||||
self._PD_GetInner(), pd_indices, values._PD_GetInner(), accumulate);
|
||||
return self;
|
||||
}
|
||||
|
||||
// index_put: Non-inplace version
|
||||
inline at::Tensor index_put(
|
||||
const at::Tensor& self,
|
||||
const c10::List<::std::optional<at::Tensor>>& indices,
|
||||
const at::Tensor& values,
|
||||
bool accumulate = false) {
|
||||
std::vector<paddle::Tensor> pd_indices;
|
||||
pd_indices.reserve(indices.size());
|
||||
for (const auto& idx : indices) {
|
||||
if (idx.has_value()) {
|
||||
pd_indices.push_back(idx.value()._PD_GetInner());
|
||||
}
|
||||
}
|
||||
|
||||
return paddle::experimental::index_put(
|
||||
self._PD_GetInner(), pd_indices, values._PD_GetInner(), accumulate);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::index(
|
||||
const c10::List<::std::optional<at::Tensor>>& indices) const {
|
||||
return at::index(*this, indices);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::index_put_(
|
||||
const c10::List<::std::optional<at::Tensor>>& indices,
|
||||
const at::Tensor& values,
|
||||
bool accumulate) const {
|
||||
return at::index_put_(
|
||||
const_cast<at::Tensor&>(*this), indices, values, accumulate);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::index_put_(
|
||||
ArrayRef<at::indexing::TensorIndex> indices, Tensor const& rhs) {
|
||||
auto tensor_indices = detail::_PD_convert_tensor_index_list(indices);
|
||||
at::Tensor values = detail::_PD_squeeze_newaxis_value(rhs, indices);
|
||||
if (tensor_indices.empty()) {
|
||||
return copy_(values);
|
||||
}
|
||||
return index_put_(tensor_indices, values);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::index_put_(
|
||||
ArrayRef<at::indexing::TensorIndex> indices, const Scalar& v) {
|
||||
auto tensor_indices = detail::_PD_convert_tensor_index_list(indices);
|
||||
if (tensor_indices.empty()) {
|
||||
std::vector<int64_t> value_shape(this->sizes().begin(),
|
||||
this->sizes().end());
|
||||
auto scalar_tensor =
|
||||
at::Tensor(paddle::experimental::full(phi::IntArray(value_shape),
|
||||
phi::Scalar(v.to<double>()),
|
||||
this->_PD_GetInner().dtype()));
|
||||
return copy_(scalar_tensor);
|
||||
}
|
||||
auto scalar_tensor = at::Tensor(paddle::experimental::full(
|
||||
{}, phi::Scalar(v.to<double>()), this->_PD_GetInner().dtype()));
|
||||
return index_put_(indices, scalar_tensor);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::index_put_(
|
||||
std::initializer_list<at::indexing::TensorIndex> indices,
|
||||
Tensor const& rhs) {
|
||||
return index_put_(ArrayRef<at::indexing::TensorIndex>(indices), rhs);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::index_put_(
|
||||
std::initializer_list<at::indexing::TensorIndex> indices, const Scalar& v) {
|
||||
return index_put_(ArrayRef<at::indexing::TensorIndex>(indices), v);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::index_put(
|
||||
const c10::List<::std::optional<at::Tensor>>& indices,
|
||||
const at::Tensor& values,
|
||||
bool accumulate) const {
|
||||
return at::index_put(*this, indices, values, accumulate);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include "paddle/phi/core/sparse_coo_tensor.h"
|
||||
|
||||
namespace at {} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline bool Tensor::is_coalesced() const {
|
||||
PD_CHECK(tensor_.layout() == common::DataLayout::SPARSE_COO,
|
||||
"is_coalesced expected sparse coordinate tensor layout but got ",
|
||||
layout());
|
||||
auto sparse_coo_tensor =
|
||||
std::dynamic_pointer_cast<phi::SparseCooTensor>(tensor_.impl());
|
||||
return sparse_coo_tensor->coalesced();
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/_local_scalar_dense.h>
|
||||
|
||||
namespace at {} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Scalar Tensor::item() const {
|
||||
auto numel = this->sym_numel();
|
||||
PD_CHECK(numel == 1,
|
||||
"a Tensor with ",
|
||||
numel,
|
||||
" elements cannot be converted to Scalar");
|
||||
if (this->is_sparse()) {
|
||||
if (this->_nnz() == 0) return Scalar(0);
|
||||
if (this->is_coalesced()) return at::_local_scalar_dense(this->_values());
|
||||
return at::_local_scalar_dense(this->_values().sum());
|
||||
} else {
|
||||
return _local_scalar_dense(*this);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Tensor::item() const {
|
||||
return item().to<T>();
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor masked_select(const at::Tensor& self,
|
||||
const at::Tensor& mask) {
|
||||
return Tensor(paddle::experimental::masked_select(self._PD_GetInner(),
|
||||
mask._PD_GetInner()));
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::masked_select(const at::Tensor& mask) const {
|
||||
return at::masked_select(*this, mask);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor narrow(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
int64_t start,
|
||||
int64_t length) {
|
||||
// Bounds checks matching PyTorch behavior
|
||||
PD_CHECK(self.dim() > 0, "narrow() cannot be applied to a 0-dim tensor.");
|
||||
PD_CHECK(length >= 0, "narrow(): length must be non-negative.");
|
||||
|
||||
// Normalize negative dim
|
||||
int64_t ndim = self.dim();
|
||||
if (dim < 0) dim += ndim;
|
||||
PD_CHECK(dim >= 0 && dim < ndim,
|
||||
"start out of range (expected to be in range of [",
|
||||
-ndim,
|
||||
", ",
|
||||
ndim - 1,
|
||||
"], but got ",
|
||||
dim,
|
||||
")");
|
||||
|
||||
int64_t cur_size = self.sizes()[dim];
|
||||
|
||||
// Wrap negative start (matching PyTorch: only wrap when start != cur_size)
|
||||
if (start < 0) {
|
||||
start = start + cur_size;
|
||||
}
|
||||
PD_CHECK(start <= cur_size - length,
|
||||
"start (",
|
||||
start,
|
||||
") + length (",
|
||||
length,
|
||||
") exceeds dimension size (",
|
||||
cur_size,
|
||||
").");
|
||||
|
||||
// Use slice to implement narrow: narrow(dim, start, length) is equivalent
|
||||
// to slice(dim, start, start + length)
|
||||
return Tensor(paddle::experimental::slice(
|
||||
self._PD_GetInner(), {dim}, {start}, {start + length}, {1}, {}));
|
||||
}
|
||||
|
||||
inline at::Tensor narrow_symint(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
c10::SymInt start,
|
||||
c10::SymInt length) {
|
||||
return narrow(self, dim, start, length);
|
||||
}
|
||||
|
||||
inline at::Tensor narrow(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
const at::Tensor& start,
|
||||
int64_t length) {
|
||||
// Extract scalar value from start tensor
|
||||
PD_CHECK(start.numel() == 1,
|
||||
"start must be a 0-dim tensor or 1-element tensor");
|
||||
int64_t start_val = start.item<int64_t>();
|
||||
return narrow(self, dim, start_val, length);
|
||||
}
|
||||
|
||||
inline at::Tensor narrow_symint(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
const at::Tensor& start,
|
||||
c10::SymInt length) {
|
||||
return narrow(self, dim, start, length);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::narrow(int64_t dim,
|
||||
int64_t start,
|
||||
int64_t length) const {
|
||||
return at::narrow(*this, dim, start, length);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::narrow_symint(int64_t dim,
|
||||
c10::SymInt start,
|
||||
c10::SymInt length) const {
|
||||
return at::narrow_symint(*this, dim, start, length);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::narrow(int64_t dim,
|
||||
const at::Tensor& start,
|
||||
int64_t length) const {
|
||||
return at::narrow(*this, dim, start, length);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::narrow_symint(int64_t dim,
|
||||
const at::Tensor& start,
|
||||
c10::SymInt length) const {
|
||||
return at::narrow_symint(*this, dim, start, length);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/narrow.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor narrow_copy(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
int64_t start,
|
||||
int64_t length) {
|
||||
// narrow_copy returns a copy of the narrowed tensor
|
||||
return narrow(self, dim, start, length).clone();
|
||||
}
|
||||
|
||||
inline at::Tensor narrow_copy_symint(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
c10::SymInt start,
|
||||
c10::SymInt length) {
|
||||
return narrow_copy(self, dim, start, length);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::narrow_copy(int64_t dim,
|
||||
int64_t start,
|
||||
int64_t length) const {
|
||||
return at::narrow_copy(*this, dim, start, length);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::narrow_copy_symint(int64_t dim,
|
||||
c10::SymInt start,
|
||||
c10::SymInt length) const {
|
||||
return at::narrow_copy_symint(*this, dim, start, length);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// Member function: Tensor::new_empty
|
||||
inline Tensor Tensor::new_empty(at::IntArrayRef size,
|
||||
at::TensorOptions options) const {
|
||||
caffe2::TypeMeta actual_dtype = options.dtype_opt().value_or(dtype());
|
||||
auto actual_device = options.device_opt().value_or(device());
|
||||
auto actual_pin_memory = options.pinned_memory();
|
||||
|
||||
auto pd_dtype = compat::_PD_AtenScalarTypeToPhiDataType(actual_dtype);
|
||||
auto pd_place = actual_device._PD_GetInner();
|
||||
|
||||
paddle::Tensor result;
|
||||
if (actual_pin_memory) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !actual_device.is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(pd_place);
|
||||
auto dense_cpu = paddle::experimental::empty(
|
||||
size._PD_ToPaddleIntArray(), pd_dtype, phi::CPUPlace());
|
||||
result = dense_cpu.copy_to(pinned_place, /*blocking=*/true);
|
||||
} else {
|
||||
result = paddle::experimental::empty(
|
||||
size._PD_ToPaddleIntArray(), pd_dtype, pd_place);
|
||||
}
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
inline Tensor Tensor::new_empty(at::IntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout>,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) const {
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype.value_or(this->scalar_type()))
|
||||
.device(device.value_or(this->device()))
|
||||
.pinned_memory(pin_memory);
|
||||
return new_empty(size, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// Member function: Tensor::new_full
|
||||
inline Tensor Tensor::new_full(at::IntArrayRef size,
|
||||
const at::Scalar& fill_value,
|
||||
at::TensorOptions options) const {
|
||||
caffe2::TypeMeta actual_dtype = options.dtype_opt().value_or(dtype());
|
||||
auto actual_device = options.device_opt().value_or(device());
|
||||
auto actual_pin_memory = options.pinned_memory();
|
||||
|
||||
auto pd_dtype = compat::_PD_AtenScalarTypeToPhiDataType(actual_dtype);
|
||||
auto pd_place = actual_device._PD_GetInner();
|
||||
|
||||
paddle::Tensor result;
|
||||
if (actual_pin_memory) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !actual_device.is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(pd_place);
|
||||
auto dense_cpu = paddle::experimental::full(
|
||||
size._PD_ToPaddleIntArray(), fill_value, pd_dtype, phi::CPUPlace());
|
||||
result = dense_cpu.copy_to(pinned_place, /*blocking=*/true);
|
||||
} else {
|
||||
result = paddle::experimental::full(
|
||||
size._PD_ToPaddleIntArray(), fill_value, pd_dtype, pd_place);
|
||||
}
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
inline Tensor Tensor::new_full(at::IntArrayRef size,
|
||||
const at::Scalar& fill_value,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout>,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) const {
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype.value_or(this->scalar_type()))
|
||||
.device(device.value_or(this->device()))
|
||||
.pinned_memory(pin_memory);
|
||||
return new_full(size, fill_value, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// Member function: Tensor::new_ones
|
||||
inline Tensor Tensor::new_ones(at::IntArrayRef size,
|
||||
at::TensorOptions options) const {
|
||||
caffe2::TypeMeta actual_dtype = options.dtype_opt().value_or(dtype());
|
||||
auto actual_device = options.device_opt().value_or(device());
|
||||
auto actual_pin_memory = options.pinned_memory();
|
||||
|
||||
auto pd_dtype = compat::_PD_AtenScalarTypeToPhiDataType(actual_dtype);
|
||||
auto pd_place = actual_device._PD_GetInner();
|
||||
|
||||
paddle::Tensor result;
|
||||
if (actual_pin_memory) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !actual_device.is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(pd_place);
|
||||
auto dense_cpu = paddle::experimental::ones(
|
||||
size._PD_ToPaddleIntArray(), pd_dtype, phi::CPUPlace());
|
||||
result = dense_cpu.copy_to(pinned_place, /*blocking=*/true);
|
||||
} else {
|
||||
result = paddle::experimental::ones(
|
||||
size._PD_ToPaddleIntArray(), pd_dtype, pd_place);
|
||||
}
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
inline Tensor Tensor::new_ones(at::IntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout>,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) const {
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype.value_or(this->scalar_type()))
|
||||
.device(device.value_or(this->device()))
|
||||
.pinned_memory(pin_memory);
|
||||
return new_ones(size, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/SymIntArrayRef.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// Member function: Tensor::new_zeros
|
||||
inline Tensor Tensor::new_zeros(at::IntArrayRef size,
|
||||
at::TensorOptions options) const {
|
||||
caffe2::TypeMeta actual_dtype = options.dtype_opt().value_or(dtype());
|
||||
auto actual_device = options.device_opt().value_or(device());
|
||||
auto actual_pin_memory = options.pinned_memory();
|
||||
|
||||
auto pd_dtype = compat::_PD_AtenScalarTypeToPhiDataType(actual_dtype);
|
||||
auto pd_place = actual_device._PD_GetInner();
|
||||
|
||||
paddle::Tensor result;
|
||||
if (actual_pin_memory) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !actual_device.is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(pd_place);
|
||||
auto dense_cpu = paddle::experimental::zeros(
|
||||
size._PD_ToPaddleIntArray(), pd_dtype, phi::CPUPlace());
|
||||
result = dense_cpu.copy_to(pinned_place, /*blocking=*/true);
|
||||
} else {
|
||||
result = paddle::experimental::zeros(
|
||||
size._PD_ToPaddleIntArray(), pd_dtype, pd_place);
|
||||
}
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
inline Tensor Tensor::new_zeros(at::IntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout>,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) const {
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype.value_or(this->scalar_type()))
|
||||
.device(device.value_or(this->device()))
|
||||
.pinned_memory(pin_memory);
|
||||
return new_zeros(size, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,99 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor ones(at::IntArrayRef size, at::TensorOptions options = {}) {
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::ones(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
return dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
return paddle::experimental::ones(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
}
|
||||
|
||||
inline at::Tensor ones(at::IntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
PD_CHECK(!layout.has_value(), "`layout` is not supported now.");
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return ones(size, options);
|
||||
}
|
||||
|
||||
inline at::Tensor ones_symint(c10::SymIntArrayRef size,
|
||||
at::TensorOptions options = {}) {
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::ones(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
return dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
return paddle::experimental::ones(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
}
|
||||
|
||||
inline at::Tensor ones_symint(c10::SymIntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
PD_CHECK(!layout.has_value(), "`layout` is not supported now.");
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return ones_symint(size, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor permute(const at::Tensor& self, at::IntArrayRef dims) {
|
||||
std::vector<int> perm(dims.size());
|
||||
for (size_t i = 0; i < dims.size(); i++) {
|
||||
perm[i] = static_cast<int>(dims[i]);
|
||||
}
|
||||
return paddle::experimental::transpose(self._PD_GetInner(), perm);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::permute(at::IntArrayRef dims) const {
|
||||
return at::permute(*this, dims);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor reciprocal(const at::Tensor& self) {
|
||||
return Tensor(paddle::experimental::reciprocal(self._PD_GetInner()));
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::reciprocal() const { return at::reciprocal(*this); }
|
||||
|
||||
inline at::Tensor& Tensor::reciprocal_() const {
|
||||
PaddleTensor& inner = const_cast<PaddleTensor&>(tensor_);
|
||||
paddle::experimental::reciprocal_(inner);
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/Device.h>
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
#include <c10/cuda/CUDAStream.h>
|
||||
#endif
|
||||
|
||||
namespace at {
|
||||
inline void Tensor::record_stream(at::Stream s) const {
|
||||
auto dense_tensor =
|
||||
std::dynamic_pointer_cast<phi::DenseTensor>(tensor_.impl());
|
||||
PD_CHECK(dense_tensor != nullptr,
|
||||
"record_stream only supports DenseTensor, but got a non-dense "
|
||||
"tensor implementation.");
|
||||
PD_CHECK(dense_tensor->place().GetType() != phi::AllocationType::CPU,
|
||||
"record_stream is not supported for CPU tensors.");
|
||||
#if (defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)) && \
|
||||
!defined(PADDLE_WITH_CUSTOM_DEVICE)
|
||||
paddle::memory::RecordStream(
|
||||
dense_tensor->Holder(), reinterpret_cast<gpuStream_t>(s.native_handle()));
|
||||
#elif defined(PADDLE_WITH_XPU)
|
||||
paddle::memory::RecordStream(dense_tensor->Holder(),
|
||||
reinterpret_cast<XPUStream>(s.native_handle()));
|
||||
#elif defined(PADDLE_WITH_CUSTOM_DEVICE)
|
||||
paddle::memory::RecordStream(
|
||||
dense_tensor->Holder(),
|
||||
reinterpret_cast<phi::stream::stream_t>(s.native_handle()));
|
||||
#else
|
||||
(void)s;
|
||||
(void)dense_tensor;
|
||||
PD_THROW(
|
||||
"record_stream is not supported: no GPU/XPU/Custom device enabled "
|
||||
"in this build.");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
// Member function: Tensor::rename
|
||||
inline Tensor Tensor::rename(::std::optional<at::DimnameList>) const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor reshape(const at::Tensor& self, at::IntArrayRef shape) {
|
||||
return paddle::experimental::reshape(self._PD_GetInner(),
|
||||
shape._PD_ToPaddleIntArray());
|
||||
}
|
||||
|
||||
inline at::Tensor reshape_symint(const at::Tensor& self,
|
||||
c10::SymIntArrayRef shape) {
|
||||
return paddle::experimental::reshape(self._PD_GetInner(),
|
||||
shape._PD_ToPaddleIntArray());
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::reshape(at::IntArrayRef shape) const {
|
||||
return at::reshape(*this, shape);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,119 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/ddim.h"
|
||||
#include "paddle/phi/core/memory/malloc.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline int64_t ResizeCheckedNumel(at::IntArrayRef size) {
|
||||
int64_t numel = 1;
|
||||
for (const auto dim : size) {
|
||||
TORCH_CHECK(dim >= 0,
|
||||
"Trying to create tensor with negative dimension ",
|
||||
dim,
|
||||
": ",
|
||||
size);
|
||||
if (dim == 0) {
|
||||
numel = 0;
|
||||
continue;
|
||||
}
|
||||
TORCH_CHECK(numel <= std::numeric_limits<int64_t>::max() / dim,
|
||||
"resize_ size is too large, possible overflow for size ",
|
||||
size);
|
||||
numel *= dim;
|
||||
}
|
||||
return numel;
|
||||
}
|
||||
|
||||
inline size_t ResizeCheckedStorageBytes(int64_t numel,
|
||||
size_t itemsize,
|
||||
size_t storage_offset_bytes) {
|
||||
const auto numel_size = static_cast<size_t>(numel);
|
||||
TORCH_CHECK(
|
||||
itemsize == 0 || numel_size <= (std::numeric_limits<size_t>::max() -
|
||||
storage_offset_bytes) /
|
||||
itemsize,
|
||||
"resize_ size is too large in bytes");
|
||||
return storage_offset_bytes + numel_size * itemsize;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// resize_ - operate on the underlying DenseTensor directly so we preserve
|
||||
// storage semantics across shrink/grow round-trips. When growth exceeds the
|
||||
// current capacity, expand the shared storage itself so aliasing views keep
|
||||
// their storage offset and existing storage contents stay intact.
|
||||
inline const at::Tensor& Tensor::resize_(
|
||||
at::IntArrayRef size,
|
||||
::std::optional<at::MemoryFormat> memory_format) const {
|
||||
// Keep old compat behavior for memory_format in this split PR.
|
||||
// TODO(youge325): add real ChannelsLast/ChannelsLast3d restride support
|
||||
// later.
|
||||
(void)memory_format;
|
||||
|
||||
std::vector<int64_t> dims(size.begin(), size.end());
|
||||
int64_t new_numel = detail::ResizeCheckedNumel(size);
|
||||
auto dense_tensor =
|
||||
std::dynamic_pointer_cast<phi::DenseTensor>(tensor_.impl());
|
||||
TORCH_CHECK(dense_tensor != nullptr,
|
||||
"resize_ only supports DenseTensor, but got a non-dense tensor");
|
||||
TORCH_CHECK(tensor_.defined(),
|
||||
"resize_ is not allowed on an undefined tensor");
|
||||
|
||||
const size_t itemsize = phi::SizeOf(dense_tensor->dtype());
|
||||
const size_t new_storage_bytes = detail::ResizeCheckedStorageBytes(
|
||||
new_numel, itemsize, dense_tensor->meta().offset);
|
||||
const size_t current_storage_bytes =
|
||||
dense_tensor->Holder() == nullptr ? 0 : dense_tensor->Holder()->size();
|
||||
|
||||
if (new_storage_bytes <= current_storage_bytes || new_numel == 0) {
|
||||
dense_tensor->Resize(dims);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Sync through the compat Storage path first so the DenseTensor holder is a
|
||||
// live StorageHolderView backed by shared StorageImpl.
|
||||
auto storage = this->storage();
|
||||
const auto old_holder = dense_tensor->Holder();
|
||||
TORCH_CHECK(old_holder != nullptr,
|
||||
"resize_ cannot grow a tensor without allocated storage");
|
||||
const phi::Place place = old_holder->place();
|
||||
auto new_holder = paddle::memory::AllocShared(place, new_storage_bytes);
|
||||
TORCH_CHECK(new_holder != nullptr, "resize_ failed to allocate storage");
|
||||
const size_t copy_bytes = std::min(old_holder->size(), new_storage_bytes);
|
||||
if (copy_bytes > 0 && old_holder->ptr() != nullptr &&
|
||||
old_holder->ptr() != new_holder->ptr()) {
|
||||
phi::memory_utils::Copy(
|
||||
place, new_holder->ptr(), place, old_holder->ptr(), copy_bytes);
|
||||
}
|
||||
storage.set_data_ptr_noswap(std::move(new_holder));
|
||||
dense_tensor->Resize(phi::make_ddim(dims));
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor select(const at::Tensor& self, int64_t dim, int64_t index) {
|
||||
// Normalize dim to positive value for error messages
|
||||
int64_t orig_dim = dim;
|
||||
if (dim < 0) {
|
||||
dim += self.dim();
|
||||
}
|
||||
// Check dim is valid
|
||||
if (dim < 0 || dim >= self.dim()) {
|
||||
PD_CHECK(false,
|
||||
"select(): index ",
|
||||
orig_dim,
|
||||
" out of range for tensor of size ",
|
||||
self.sizes(),
|
||||
" at dimension ",
|
||||
orig_dim);
|
||||
}
|
||||
// Handle negative index
|
||||
int64_t orig_index = index;
|
||||
if (index < 0) {
|
||||
index = self.size(dim) + index;
|
||||
}
|
||||
// Check index is valid
|
||||
if (index < 0 || index >= self.size(dim)) {
|
||||
PD_CHECK(false,
|
||||
"select(): index ",
|
||||
orig_index,
|
||||
" out of range for tensor of size ",
|
||||
self.sizes(),
|
||||
" at dimension ",
|
||||
orig_dim < 0 ? orig_dim + self.dim() : orig_dim);
|
||||
}
|
||||
|
||||
return Tensor(
|
||||
paddle::experimental::slice(self._PD_GetInner(),
|
||||
/*axes=*/{static_cast<int>(dim)},
|
||||
/*starts=*/{index},
|
||||
/*ends=*/{index + 1},
|
||||
/*infer_flags=*/{1},
|
||||
/*decrease_axis=*/{static_cast<int>(dim)}));
|
||||
}
|
||||
|
||||
inline at::Tensor select_symint(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
c10::SymInt index) {
|
||||
return select(self, dim, static_cast<int64_t>(index));
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::select(int64_t dim, int64_t index) const {
|
||||
return at::select(*this, dim, index);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::select_symint(int64_t dim, c10::SymInt index) const {
|
||||
return at::select_symint(*this, dim, index);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor slice(const at::Tensor& self,
|
||||
int64_t dim = 0,
|
||||
::std::optional<int64_t> start = ::std::nullopt,
|
||||
::std::optional<int64_t> end = ::std::nullopt,
|
||||
int64_t step = 1) {
|
||||
// Materialize the compat StorageHolderView before creating the slice so the
|
||||
// base tensor and its views observe the same shared storage during resize_.
|
||||
(void)self.storage();
|
||||
return paddle::experimental::slice(
|
||||
self._PD_GetInner(),
|
||||
{dim},
|
||||
start.has_value() ? IntArrayRef(start.value())._PD_ToPaddleIntArray()
|
||||
: IntArrayRef()._PD_ToPaddleIntArray(),
|
||||
end.has_value() ? IntArrayRef(end.value())._PD_ToPaddleIntArray()
|
||||
: IntArrayRef()._PD_ToPaddleIntArray(),
|
||||
{1},
|
||||
{});
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::slice(int64_t dim,
|
||||
::std::optional<int64_t> start,
|
||||
::std::optional<int64_t> end,
|
||||
int64_t step) const {
|
||||
return at::slice(*this, dim, start, end, step);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,119 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/api/include/sparse_api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/sparse_coo_tensor.h"
|
||||
|
||||
namespace at::detail {
|
||||
|
||||
inline std::vector<int64_t> _PD_infer_sparse_coo_size(
|
||||
const at::Tensor& indices) {
|
||||
auto host_indices = indices.cpu().to(at::kLong);
|
||||
int64_t sparse_dim = host_indices.dim() > 0 ? host_indices.size(0) : 0;
|
||||
int64_t nnz = host_indices.dim() > 1 ? host_indices.size(1) : 0;
|
||||
|
||||
std::vector<int64_t> inferred_size(static_cast<size_t>(sparse_dim), 0);
|
||||
const int64_t* data = host_indices.const_data_ptr<int64_t>();
|
||||
for (int64_t dim = 0; dim < sparse_dim; ++dim) {
|
||||
for (int64_t i = 0; i < nnz; ++i) {
|
||||
inferred_size[static_cast<size_t>(dim)] = std::max(
|
||||
inferred_size[static_cast<size_t>(dim)], data[dim * nnz + i] + 1);
|
||||
}
|
||||
}
|
||||
return inferred_size;
|
||||
}
|
||||
|
||||
inline void _PD_set_sparse_coo_coalesced(at::Tensor* tensor,
|
||||
::std::optional<bool> is_coalesced) {
|
||||
if (!is_coalesced.has_value()) {
|
||||
return;
|
||||
}
|
||||
auto sparse_tensor = std::dynamic_pointer_cast<phi::SparseCooTensor>(
|
||||
tensor->_PD_GetInner().impl());
|
||||
PD_CHECK(sparse_tensor,
|
||||
"Expected SparseCooTensor result from sparse_coo_tensor.");
|
||||
sparse_tensor->SetCoalesced(is_coalesced.value());
|
||||
}
|
||||
|
||||
} // namespace at::detail
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor sparse_coo_tensor(
|
||||
const at::Tensor& indices,
|
||||
const at::Tensor& values,
|
||||
at::IntArrayRef size,
|
||||
at::TensorOptions options = {},
|
||||
::std::optional<bool> is_coalesced = ::std::nullopt) {
|
||||
paddle::Tensor idx = indices._PD_GetInner();
|
||||
paddle::Tensor vals = values._PD_GetInner();
|
||||
|
||||
// PyTorch ignores dtype mismatch between values and TensorOptions in
|
||||
// sparse_coo_tensor; the resulting sparse tensor uses values' original dtype.
|
||||
// Do not cast or throw here.
|
||||
|
||||
if (options.pinned_memory()) {
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
idx = idx.copy_to(pinned_place, /*blocking=*/true);
|
||||
vals = vals.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
|
||||
// PyTorch: sparse_coo_tensor(indices, values, size)
|
||||
// Paddle: sparse_coo_tensor(values, indices, shape)
|
||||
at::Tensor result = paddle::experimental::sparse::sparse_coo_tensor(
|
||||
vals, idx, std::vector<int64_t>(size.begin(), size.end()));
|
||||
detail::_PD_set_sparse_coo_coalesced(&result, is_coalesced);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline at::Tensor sparse_coo_tensor(const at::Tensor& indices,
|
||||
const at::Tensor& values,
|
||||
at::IntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory,
|
||||
::std::optional<bool> is_coalesced) {
|
||||
PD_CHECK(!layout.has_value() || layout.value() == c10::kSparse,
|
||||
"`layout` must be Sparse for sparse_coo_tensor.");
|
||||
auto options =
|
||||
at::TensorOptions().dtype(dtype).device(device).pinned_memory(pin_memory);
|
||||
return sparse_coo_tensor(indices, values, size, options, is_coalesced);
|
||||
}
|
||||
|
||||
inline at::Tensor sparse_coo_tensor(
|
||||
const at::Tensor& indices,
|
||||
const at::Tensor& values,
|
||||
at::TensorOptions options = {},
|
||||
::std::optional<bool> is_coalesced = ::std::nullopt) {
|
||||
return sparse_coo_tensor(indices,
|
||||
values,
|
||||
detail::_PD_infer_sparse_coo_size(indices),
|
||||
options,
|
||||
is_coalesced);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/pinned_place.h>
|
||||
#include <optional>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/api/include/tensor.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/sparse_csr_tensor.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor sparse_csr_tensor(const at::Tensor& crow_indices,
|
||||
const at::Tensor& col_indices,
|
||||
const at::Tensor& values,
|
||||
at::IntArrayRef size,
|
||||
at::TensorOptions options) {
|
||||
paddle::Tensor crows = crow_indices._PD_GetInner();
|
||||
paddle::Tensor cols = col_indices._PD_GetInner();
|
||||
paddle::Tensor vals = values._PD_GetInner();
|
||||
|
||||
// PyTorch ignores dtype mismatch between values and TensorOptions in
|
||||
// sparse_csr_tensor; the resulting sparse tensor uses values' original dtype.
|
||||
// Do not cast or throw here.
|
||||
|
||||
if (options.pinned_memory()) {
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
crows = crows.copy_to(pinned_place, /*blocking=*/true);
|
||||
cols = cols.copy_to(pinned_place, /*blocking=*/true);
|
||||
vals = vals.copy_to(pinned_place, /*blocking=*/true);
|
||||
}
|
||||
|
||||
// Get the underlying DenseTensors
|
||||
auto* dense_crows = dynamic_cast<phi::DenseTensor*>(crows.impl().get());
|
||||
auto* dense_cols = dynamic_cast<phi::DenseTensor*>(cols.impl().get());
|
||||
auto* dense_values = dynamic_cast<phi::DenseTensor*>(vals.impl().get());
|
||||
|
||||
PD_CHECK(dense_crows != nullptr,
|
||||
"crow_indices must be a dense tensor for sparse_csr_tensor.");
|
||||
PD_CHECK(dense_cols != nullptr,
|
||||
"col_indices must be a dense tensor for sparse_csr_tensor.");
|
||||
PD_CHECK(dense_values != nullptr,
|
||||
"values must be a dense tensor for sparse_csr_tensor.");
|
||||
|
||||
// Create the SparseCsrTensor
|
||||
std::shared_ptr<phi::SparseCsrTensor> csr_tensor =
|
||||
std::make_shared<phi::SparseCsrTensor>(
|
||||
*dense_crows,
|
||||
*dense_cols,
|
||||
*dense_values,
|
||||
common::make_ddim(std::vector<int64_t>(size.begin(), size.end())));
|
||||
|
||||
// Wrap in a Paddle Tensor
|
||||
paddle::Tensor result;
|
||||
result.set_impl(csr_tensor);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline at::Tensor sparse_csr_tensor(const at::Tensor& crow_indices,
|
||||
const at::Tensor& col_indices,
|
||||
const at::Tensor& values,
|
||||
at::IntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
PD_CHECK(!layout.has_value() || layout.value() == c10::kSparseCsr,
|
||||
"`layout` must be SparseCsr for sparse_csr_tensor.");
|
||||
auto options =
|
||||
at::TensorOptions().dtype(dtype).device(device).pinned_memory(pin_memory);
|
||||
return sparse_csr_tensor(crow_indices, col_indices, values, size, options);
|
||||
}
|
||||
|
||||
inline at::Tensor sparse_csr_tensor(const at::Tensor& crow_indices,
|
||||
const at::Tensor& col_indices,
|
||||
const at::Tensor& values,
|
||||
at::TensorOptions options) {
|
||||
// Infer size from crow_indices and col_indices:
|
||||
// nrows = crow_indices.size(0) - 1
|
||||
// ncols = max(col_indices) + 1
|
||||
int64_t nrows = crow_indices.size(0) - 1;
|
||||
int64_t ncols = 0;
|
||||
|
||||
if (col_indices.numel() > 0) {
|
||||
auto* dense_cols = dynamic_cast<phi::DenseTensor*>(
|
||||
col_indices._PD_GetInner().impl().get());
|
||||
PD_CHECK(dense_cols != nullptr,
|
||||
"col_indices must be a dense tensor for sparse_csr_tensor.");
|
||||
PD_CHECK(
|
||||
dense_cols->place().GetType() == phi::AllocationType::CPU,
|
||||
"sparse_csr_tensor without explicit size only supports CPU "
|
||||
"col_indices for automatic size inference. Please provide the size "
|
||||
"parameter explicitly for non-CPU tensors.");
|
||||
|
||||
int64_t n = dense_cols->numel();
|
||||
if (dense_cols->dtype() == phi::DataType::INT64) {
|
||||
const int64_t* data = dense_cols->data<int64_t>();
|
||||
for (int64_t i = 0; i < n; ++i) {
|
||||
if (data[i] + 1 > ncols) ncols = data[i] + 1;
|
||||
}
|
||||
} else if (dense_cols->dtype() == phi::DataType::INT32) {
|
||||
const int32_t* data = dense_cols->data<int32_t>();
|
||||
for (int64_t i = 0; i < n; ++i) {
|
||||
int64_t val = static_cast<int64_t>(data[i]) + 1;
|
||||
if (val > ncols) ncols = val;
|
||||
}
|
||||
} else {
|
||||
PD_CHECK(false,
|
||||
"col_indices must have dtype int32 or int64 for automatic "
|
||||
"size inference in sparse_csr_tensor.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int64_t> size_vec = {nrows, ncols};
|
||||
return sparse_csr_tensor(
|
||||
crow_indices, col_indices, values, at::IntArrayRef(size_vec), options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> split(const at::Tensor& self,
|
||||
int64_t split_size,
|
||||
int64_t dim = 0) {
|
||||
// Calculate number of splits based on split_size
|
||||
int64_t dim_size = self._PD_GetInner().dims()[dim];
|
||||
std::vector<int64_t> split_sizes;
|
||||
for (int64_t i = 0; i < dim_size; i += split_size) {
|
||||
split_sizes.push_back(std::min(split_size, dim_size - i));
|
||||
}
|
||||
auto outputs =
|
||||
paddle::experimental::split(self._PD_GetInner(), split_sizes, dim);
|
||||
std::vector<at::Tensor> at_tensors;
|
||||
at_tensors.reserve(outputs.size());
|
||||
for (const auto& paddle_tensor : outputs) {
|
||||
at_tensors.emplace_back(paddle_tensor);
|
||||
}
|
||||
return at_tensors;
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> split_symint(const at::Tensor& self,
|
||||
c10::SymInt split_size,
|
||||
int64_t dim = 0) {
|
||||
return split(self, static_cast<int64_t>(split_size), dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> split(const at::Tensor& self,
|
||||
at::IntArrayRef split_sizes,
|
||||
int64_t dim = 0) {
|
||||
auto outputs = paddle::experimental::split(
|
||||
self._PD_GetInner(), split_sizes._PD_ToPaddleIntArray(), dim);
|
||||
std::vector<at::Tensor> at_tensors;
|
||||
at_tensors.reserve(outputs.size());
|
||||
for (const auto& paddle_tensor : outputs) {
|
||||
at_tensors.emplace_back(paddle_tensor);
|
||||
}
|
||||
return at_tensors;
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> split_symint(const at::Tensor& self,
|
||||
c10::SymIntArrayRef split_sizes,
|
||||
int64_t dim = 0) {
|
||||
return split(
|
||||
self,
|
||||
at::IntArrayRef(reinterpret_cast<const int64_t*>(split_sizes.data()),
|
||||
split_sizes.size()),
|
||||
dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::split(int64_t split_size,
|
||||
int64_t dim = 0) const {
|
||||
return at::split(*this, split_size, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::split_symint(c10::SymInt split_size,
|
||||
int64_t dim = 0) const {
|
||||
return at::split_symint(*this, split_size, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::split(at::IntArrayRef split_sizes,
|
||||
int64_t dim = 0) const {
|
||||
return at::split(*this, split_sizes, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::split_symint(
|
||||
c10::SymIntArrayRef split_sizes, int64_t dim = 0) const {
|
||||
return at::split_symint(*this, split_sizes, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/split.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> split_with_sizes(const at::Tensor& self,
|
||||
at::IntArrayRef split_sizes,
|
||||
int64_t dim = 0) {
|
||||
return at::split(self, split_sizes, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> split_with_sizes_symint(
|
||||
const at::Tensor& self, c10::SymIntArrayRef split_sizes, int64_t dim = 0) {
|
||||
return at::split_symint(self, split_sizes, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::split_with_sizes(
|
||||
at::IntArrayRef split_sizes, int64_t dim) const {
|
||||
return at::split_with_sizes(*this, split_sizes, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::split_with_sizes_symint(
|
||||
c10::SymIntArrayRef split_sizes, int64_t dim) const {
|
||||
return at::split_with_sizes_symint(*this, split_sizes, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor squeeze(const at::Tensor& self) {
|
||||
return paddle::experimental::squeeze(self._PD_GetInner(), {});
|
||||
}
|
||||
|
||||
inline at::Tensor squeeze(const at::Tensor& self, int64_t dim) {
|
||||
return paddle::experimental::squeeze(self._PD_GetInner(), {dim});
|
||||
}
|
||||
|
||||
inline at::Tensor squeeze(const at::Tensor& self, at::IntArrayRef dim) {
|
||||
return paddle::experimental::squeeze(self._PD_GetInner(),
|
||||
dim._PD_ToPaddleIntArray());
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::squeeze() const { return at::squeeze(*this); }
|
||||
|
||||
inline at::Tensor Tensor::squeeze(int64_t dim) const {
|
||||
return at::squeeze(*this, dim);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::squeeze(at::IntArrayRef dim) const {
|
||||
return at::squeeze(*this, dim);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::squeeze_() const {
|
||||
PaddleTensor& inner = const_cast<PaddleTensor&>(tensor_);
|
||||
paddle::experimental::squeeze_(inner, {});
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::squeeze_(int64_t dim) const {
|
||||
PaddleTensor& inner = const_cast<PaddleTensor&>(tensor_);
|
||||
paddle::experimental::squeeze_(inner, {dim});
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::squeeze_(at::IntArrayRef dim) const {
|
||||
PaddleTensor& inner = const_cast<PaddleTensor&>(tensor_);
|
||||
paddle::experimental::squeeze_(inner, dim._PD_ToPaddleIntArray());
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,146 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/Scalar.h>
|
||||
#include <c10/util/ArrayRef.h>
|
||||
#include <c10/util/OptionalArrayRef.h>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/int_array.h"
|
||||
#include "paddle/phi/common/scalar.h"
|
||||
|
||||
namespace at::detail {
|
||||
|
||||
// Internal implementation for std (standard deviation = sqrt(variance))
|
||||
inline Tensor _PD_std_impl(const Tensor& self,
|
||||
const std::vector<int64_t>& dims_vec,
|
||||
double correction_value,
|
||||
bool keepdim) {
|
||||
// Validate dimensions before processing
|
||||
int64_t ndim = self.dim();
|
||||
for (int64_t d : dims_vec) {
|
||||
int64_t dim_idx = d < 0 ? d + ndim : d;
|
||||
if (dim_idx < 0 || dim_idx >= ndim) {
|
||||
PD_CHECK(false,
|
||||
"Dimension out of range (expected to be in range of [",
|
||||
-ndim,
|
||||
", ",
|
||||
ndim - 1,
|
||||
"], but got ",
|
||||
d,
|
||||
")");
|
||||
}
|
||||
}
|
||||
phi::IntArray dims_int_array(dims_vec);
|
||||
paddle::Tensor tensor = self._PD_GetInner();
|
||||
|
||||
paddle::Tensor mean_tensor;
|
||||
if (dims_vec.empty()) {
|
||||
mean_tensor = paddle::experimental::mean(
|
||||
tensor, phi::IntArray(std::vector<int64_t>{}), true);
|
||||
} else {
|
||||
mean_tensor = paddle::experimental::mean(tensor, dims_int_array, true);
|
||||
}
|
||||
|
||||
paddle::Tensor diff = paddle::experimental::subtract(tensor, mean_tensor);
|
||||
paddle::Tensor diff_squared = paddle::experimental::multiply(diff, diff);
|
||||
|
||||
paddle::Tensor sum_squared_diff;
|
||||
if (dims_vec.empty()) {
|
||||
sum_squared_diff =
|
||||
paddle::experimental::sum(diff_squared,
|
||||
phi::IntArray(std::vector<int64_t>{}),
|
||||
diff_squared.dtype(),
|
||||
keepdim);
|
||||
} else {
|
||||
sum_squared_diff = paddle::experimental::sum(
|
||||
diff_squared, dims_int_array, diff_squared.dtype(), keepdim);
|
||||
}
|
||||
|
||||
int64_t n = tensor.numel();
|
||||
if (!dims_vec.empty()) {
|
||||
n = 1;
|
||||
for (int64_t d : dims_vec) {
|
||||
int64_t dim_idx = d < 0 ? d + tensor.dims().size() : d;
|
||||
if (dim_idx >= 0 &&
|
||||
dim_idx < static_cast<int64_t>(tensor.dims().size())) {
|
||||
n *= tensor.dims()[dim_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double corrected_n = static_cast<double>(n) - correction_value;
|
||||
if (corrected_n <= 0.0) {
|
||||
corrected_n = static_cast<double>(n);
|
||||
}
|
||||
|
||||
std::vector<int64_t> result_shape_vec;
|
||||
for (int64_t i = 0; i < sum_squared_diff.dims().size(); ++i) {
|
||||
result_shape_vec.push_back(sum_squared_diff.dims()[i]);
|
||||
}
|
||||
paddle::Tensor correction_scalar =
|
||||
paddle::experimental::full(phi::IntArray(result_shape_vec),
|
||||
phi::Scalar(corrected_n),
|
||||
sum_squared_diff.dtype(),
|
||||
sum_squared_diff.place());
|
||||
paddle::Tensor variance =
|
||||
paddle::experimental::divide(sum_squared_diff, correction_scalar);
|
||||
|
||||
paddle::Tensor result = paddle::experimental::sqrt(variance);
|
||||
|
||||
return Tensor(result);
|
||||
}
|
||||
|
||||
} // namespace at::detail
|
||||
|
||||
namespace at {
|
||||
|
||||
inline Tensor Tensor::std(bool unbiased) const {
|
||||
std::vector<int64_t> empty_dims;
|
||||
double correction = unbiased ? 1.0 : 0.0;
|
||||
return detail::_PD_std_impl(*this, empty_dims, correction, false);
|
||||
}
|
||||
|
||||
inline Tensor Tensor::std(at::OptionalIntArrayRef dim,
|
||||
bool unbiased,
|
||||
bool keepdim) const {
|
||||
double correction = unbiased ? 1.0 : 0.0;
|
||||
std::vector<int64_t> dims_vec;
|
||||
if (dim.has_value() && dim.value().size() > 0) {
|
||||
dims_vec.assign(dim.value().begin(), dim.value().end());
|
||||
}
|
||||
return detail::_PD_std_impl(*this, dims_vec, correction, keepdim);
|
||||
}
|
||||
|
||||
inline Tensor Tensor::std(at::OptionalIntArrayRef dim,
|
||||
const ::std::optional<at::Scalar>& correction,
|
||||
bool keepdim) const {
|
||||
double correction_value = 1.0;
|
||||
if (correction.has_value()) {
|
||||
const at::Scalar& scalar = correction.value();
|
||||
correction_value = scalar.to<double>();
|
||||
}
|
||||
std::vector<int64_t> dims_vec;
|
||||
if (dim.has_value() && dim.value().size() > 0) {
|
||||
dims_vec.assign(dim.value().begin(), dim.value().end());
|
||||
}
|
||||
return detail::_PD_std_impl(*this, dims_vec, correction_value, keepdim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,110 @@
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <c10/util/OptionalArrayRef.h>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor sum(const at::Tensor& self,
|
||||
::std::optional<at::ScalarType> dtype = ::std::nullopt) {
|
||||
// Match PyTorch promotion: integer inputs -> int64; others -> keep input
|
||||
// dtype.
|
||||
at::ScalarType resolved_dtype;
|
||||
if (dtype.has_value()) {
|
||||
resolved_dtype = dtype.value();
|
||||
} else {
|
||||
at::ScalarType input_dtype = self.scalar_type();
|
||||
resolved_dtype = at::isIntegralType(input_dtype, /*includeBool=*/true)
|
||||
? at::kLong
|
||||
: input_dtype;
|
||||
}
|
||||
return paddle::experimental::sum(
|
||||
self._PD_GetInner(),
|
||||
{},
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(resolved_dtype),
|
||||
/*keepdim=*/false);
|
||||
}
|
||||
|
||||
inline at::Tensor sum(const at::Tensor& self,
|
||||
at::OptionalIntArrayRef dim,
|
||||
bool keepdim = false,
|
||||
::std::optional<at::ScalarType> dtype = ::std::nullopt) {
|
||||
// Match PyTorch promotion: integer inputs -> int64; others -> keep input
|
||||
// dtype.
|
||||
at::ScalarType resolved_dtype;
|
||||
if (dtype.has_value()) {
|
||||
resolved_dtype = dtype.value();
|
||||
} else {
|
||||
at::ScalarType input_dtype = self.scalar_type();
|
||||
resolved_dtype = at::isIntegralType(input_dtype, /*includeBool=*/true)
|
||||
? at::kLong
|
||||
: input_dtype;
|
||||
}
|
||||
return paddle::experimental::sum(
|
||||
self._PD_GetInner(),
|
||||
dim.has_value() ? dim.value()._PD_ToPaddleIntArray()
|
||||
: paddle::experimental::IntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(resolved_dtype),
|
||||
keepdim);
|
||||
}
|
||||
|
||||
inline at::Tensor& sum_out(
|
||||
at::Tensor&
|
||||
out, // NOLINT: intentional non-const reference for output parameter
|
||||
const at::Tensor& self,
|
||||
at::OptionalIntArrayRef dim,
|
||||
bool keepdim = false,
|
||||
::std::optional<at::ScalarType> dtype = ::std::nullopt) {
|
||||
auto res = sum(self, dim, keepdim, dtype);
|
||||
paddle::experimental::assign_out_(res._PD_GetInner(), out._PD_GetInner());
|
||||
return out;
|
||||
}
|
||||
|
||||
inline at::Tensor& sum_out(
|
||||
at::Tensor&
|
||||
out, // NOLINT: intentional non-const reference for output parameter
|
||||
const at::Tensor& self,
|
||||
::std::optional<at::ScalarType> dtype = ::std::nullopt) {
|
||||
auto res = sum(self, dtype);
|
||||
paddle::experimental::assign_out_(res._PD_GetInner(), out._PD_GetInner());
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::sum(::std::optional<at::ScalarType> dtype) const {
|
||||
return at::sum(*this, dtype);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::sum(at::OptionalIntArrayRef dim,
|
||||
bool keepdim,
|
||||
::std::optional<at::ScalarType> dtype) const {
|
||||
return at::sum(*this, dim, keepdim, dtype);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor t(const Tensor& self) {
|
||||
return self.transpose(0, self.dim() < 2 ? 0 : 1);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::t() const { return at::t(*this); }
|
||||
|
||||
inline at::Tensor& Tensor::t_() const {
|
||||
return transpose_(0, dim() < 2 ? 0 : 1);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/ScalarType.h>
|
||||
|
||||
#include "paddle/common/macros.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
#define TENSOR(T, S) \
|
||||
PADDLE_API Tensor tensor(ArrayRef<T> values, const TensorOptions& options); \
|
||||
inline Tensor tensor(std::initializer_list<T> values, \
|
||||
const TensorOptions& options) { \
|
||||
return at::tensor(ArrayRef<T>(values), options); \
|
||||
} \
|
||||
inline Tensor tensor(T value, const TensorOptions& options) { \
|
||||
return at::tensor(ArrayRef<T>(value), options); \
|
||||
} \
|
||||
inline Tensor tensor(ArrayRef<T> values) { \
|
||||
return at::tensor(std::move(values), at::dtype(k##S)); \
|
||||
} \
|
||||
inline Tensor tensor(std::initializer_list<T> values) { \
|
||||
return at::tensor(ArrayRef<T>(values)); \
|
||||
} \
|
||||
inline Tensor tensor(T value) { return at::tensor(ArrayRef<T>(value)); }
|
||||
AT_FORALL_SCALAR_TYPES_AND3(Bool, Half, BFloat16, TENSOR)
|
||||
AT_FORALL_COMPLEX_TYPES(TENSOR)
|
||||
#undef TENSOR
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> tensor_split(const at::Tensor& self,
|
||||
int64_t sections,
|
||||
int64_t dim = 0) {
|
||||
// Follow PyTorch's tensor_split_sections_symint implementation
|
||||
PD_CHECK(self._PD_GetInner().dims().size() > 0,
|
||||
"tensor_split expected at least a 1-dimensional tensor, but got a "
|
||||
"tensor with ",
|
||||
self._PD_GetInner().dims().size(),
|
||||
" dims");
|
||||
|
||||
PD_CHECK(
|
||||
sections > 0, "number of sections must be larger than 0, got ", sections);
|
||||
|
||||
int64_t dim_size = self._PD_GetInner().dims()[dim];
|
||||
|
||||
// Calculate split sizes: first (dim_size % sections) chunks get size
|
||||
// (dim_size / sections + 1), remaining chunks get size (dim_size / sections)
|
||||
auto min_split_size = dim_size / sections;
|
||||
auto num_splits_one_extra = dim_size % sections;
|
||||
|
||||
std::vector<int64_t> split_sizes;
|
||||
split_sizes.reserve(sections);
|
||||
|
||||
for (int64_t split_idx = 0; split_idx < sections; ++split_idx) {
|
||||
auto split_size = (split_idx < num_splits_one_extra) ? (min_split_size + 1)
|
||||
: min_split_size;
|
||||
split_sizes.push_back(split_size);
|
||||
}
|
||||
|
||||
// Use split with calculated sizes
|
||||
auto outputs =
|
||||
paddle::experimental::split(self._PD_GetInner(), split_sizes, dim);
|
||||
|
||||
std::vector<at::Tensor> at_tensors;
|
||||
at_tensors.reserve(outputs.size());
|
||||
for (const auto& paddle_tensor : outputs) {
|
||||
at_tensors.emplace_back(paddle_tensor);
|
||||
}
|
||||
return at_tensors;
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> tensor_split_symint(const at::Tensor& self,
|
||||
c10::SymInt sections,
|
||||
int64_t dim = 0) {
|
||||
return tensor_split(self, static_cast<int64_t>(sections), dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> tensor_split(const at::Tensor& self,
|
||||
at::IntArrayRef indices,
|
||||
int64_t dim = 0) {
|
||||
// Follow PyTorch's _tensor_split_indices implementation
|
||||
// indices are split positions, not sizes
|
||||
PD_CHECK(self._PD_GetInner().dims().size() > 0,
|
||||
"tensor_split expected at least a 1-dimensional tensor, but got a "
|
||||
"tensor with ",
|
||||
self._PD_GetInner().dims().size(),
|
||||
" dims");
|
||||
|
||||
int64_t num_indices = indices.size();
|
||||
int64_t dim_size = self._PD_GetInner().dims()[dim];
|
||||
|
||||
// Convert indices (positions) to sizes
|
||||
std::vector<int64_t> split_sizes;
|
||||
split_sizes.reserve(num_indices + 1);
|
||||
|
||||
int64_t start_idx = 0;
|
||||
for (int64_t i = 0; i < num_indices; ++i) {
|
||||
int64_t end_idx = indices[i];
|
||||
// Handle negative indices
|
||||
if (end_idx < 0) {
|
||||
end_idx += dim_size;
|
||||
}
|
||||
// Clamp to valid range
|
||||
end_idx = std::max(start_idx, std::min(end_idx, dim_size));
|
||||
split_sizes.push_back(end_idx - start_idx);
|
||||
start_idx = end_idx;
|
||||
}
|
||||
// Add the last segment
|
||||
split_sizes.push_back(dim_size - start_idx);
|
||||
|
||||
// Use split with calculated sizes
|
||||
auto outputs =
|
||||
paddle::experimental::split(self._PD_GetInner(), split_sizes, dim);
|
||||
|
||||
std::vector<at::Tensor> at_tensors;
|
||||
at_tensors.reserve(outputs.size());
|
||||
for (const auto& paddle_tensor : outputs) {
|
||||
at_tensors.emplace_back(paddle_tensor);
|
||||
}
|
||||
return at_tensors;
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> tensor_split_symint(const at::Tensor& self,
|
||||
c10::SymIntArrayRef indices,
|
||||
int64_t dim = 0) {
|
||||
return tensor_split(
|
||||
self,
|
||||
at::IntArrayRef(reinterpret_cast<const int64_t*>(indices.data()),
|
||||
indices.size()),
|
||||
dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> tensor_split(
|
||||
const at::Tensor& self,
|
||||
const at::Tensor& tensor_indices_or_sections,
|
||||
int64_t dim = 0) {
|
||||
// Follow PyTorch's validation and implementation
|
||||
PD_CHECK(self._PD_GetInner().dims().size() > 0,
|
||||
"tensor_split expected at least a 1-dimensional tensor, but got a "
|
||||
"tensor with ",
|
||||
self._PD_GetInner().dims().size(),
|
||||
" dims");
|
||||
|
||||
auto split_device = tensor_indices_or_sections.device();
|
||||
PD_CHECK(split_device.is_cpu(),
|
||||
"tensor_split expected tensor_indices_or_sections to be on cpu, but "
|
||||
"it's on ",
|
||||
split_device);
|
||||
|
||||
auto split_dtype = tensor_indices_or_sections.scalar_type();
|
||||
PD_CHECK(split_dtype == at::kLong,
|
||||
"tensor_split expected tensor_indices_or_sections to have dtype of "
|
||||
"long, but got ",
|
||||
split_dtype);
|
||||
|
||||
auto split_dim = tensor_indices_or_sections.dim();
|
||||
PD_CHECK(split_dim == 1 || split_dim == 0,
|
||||
"tensor_split expected tensor_indices_or_sections to be a "
|
||||
"zero-dimensional or one-dimensional tensor, but got a tensor with ",
|
||||
split_dim,
|
||||
" dims");
|
||||
|
||||
if (split_dim == 0) {
|
||||
// 0-dimensional tensor: treat as sections
|
||||
int64_t sections = tensor_indices_or_sections.item<int64_t>();
|
||||
return tensor_split(self, sections, dim);
|
||||
} else {
|
||||
// 1-dimensional tensor: treat as indices
|
||||
// Need to handle non-contiguous tensors properly
|
||||
const PaddleTensor& paddle_tensor =
|
||||
tensor_indices_or_sections._PD_GetInner();
|
||||
const int64_t* indices_data = paddle_tensor.data<int64_t>();
|
||||
auto stride = tensor_indices_or_sections.stride(0);
|
||||
auto numel = tensor_indices_or_sections.numel();
|
||||
std::vector<int64_t> indices(numel);
|
||||
for (int64_t offset = 0; offset < numel; ++offset) {
|
||||
// indices tensor could be non-contiguous
|
||||
indices[offset] = *(indices_data + offset * stride);
|
||||
}
|
||||
return tensor_split(self, at::IntArrayRef(indices), dim);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::tensor_split(int64_t sections,
|
||||
int64_t dim = 0) const {
|
||||
return at::tensor_split(*this, sections, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::tensor_split_symint(
|
||||
c10::SymInt sections, int64_t dim = 0) const {
|
||||
return at::tensor_split_symint(*this, sections, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::tensor_split(at::IntArrayRef indices,
|
||||
int64_t dim = 0) const {
|
||||
return at::tensor_split(*this, indices, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::tensor_split_symint(
|
||||
c10::SymIntArrayRef indices, int64_t dim = 0) const {
|
||||
return at::tensor_split_symint(*this, indices, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::tensor_split(
|
||||
const at::Tensor& tensor_indices_or_sections, int64_t dim = 0) const {
|
||||
return at::tensor_split(*this, tensor_indices_or_sections, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/core/ScalarType.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/scalar_type_conversion.h>
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
// Overload 1: to(TensorOptions, non_blocking, copy, memory_format)
|
||||
inline at::Tensor Tensor::to(
|
||||
at::TensorOptions options,
|
||||
bool non_blocking,
|
||||
bool copy,
|
||||
::std::optional<at::MemoryFormat> memory_format) const {
|
||||
// Handle device transfer
|
||||
PaddleTensor result = tensor_;
|
||||
bool materialized_copy = false;
|
||||
|
||||
if (options.has_device()) {
|
||||
const c10::Device& dev = options.device();
|
||||
phi::Place place;
|
||||
switch (dev.type()) {
|
||||
case c10::DeviceType::CPU:
|
||||
case c10::DeviceType::CUDA:
|
||||
case c10::DeviceType::XPU:
|
||||
case c10::DeviceType::IPU:
|
||||
case c10::DeviceType::CUSTOM:
|
||||
place = dev._PD_GetInner();
|
||||
break;
|
||||
default:
|
||||
PD_THROW("Unsupported device type: ", dev.type());
|
||||
break;
|
||||
}
|
||||
if (place != tensor_.place()) {
|
||||
result = result.copy_to(place, /*blocking=*/!non_blocking);
|
||||
materialized_copy = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle dtype cast
|
||||
if (options.has_dtype()) {
|
||||
auto target_dtype =
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype());
|
||||
if (target_dtype != result.dtype()) {
|
||||
result = paddle::experimental::cast(result, target_dtype);
|
||||
materialized_copy = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (copy && !materialized_copy) {
|
||||
result = paddle::experimental::assign(result);
|
||||
}
|
||||
|
||||
return at::Tensor(result);
|
||||
}
|
||||
|
||||
// Overload 2: to(optional<ScalarType>, optional<Layout>, optional<Device>,
|
||||
// optional<bool> pin_memory, non_blocking, copy, memory_format)
|
||||
inline at::Tensor Tensor::to(
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory,
|
||||
bool non_blocking,
|
||||
bool copy,
|
||||
::std::optional<at::MemoryFormat> memory_format) const {
|
||||
at::TensorOptions options;
|
||||
if (dtype.has_value()) {
|
||||
options = options.dtype(dtype.value());
|
||||
}
|
||||
if (device.has_value()) {
|
||||
options = options.device(device.value());
|
||||
}
|
||||
if (pin_memory.has_value() && pin_memory.value()) {
|
||||
options = options.pinned_memory(true);
|
||||
}
|
||||
return to(options, non_blocking, copy, memory_format);
|
||||
}
|
||||
|
||||
// Overload 3: to(Device, ScalarType, non_blocking, copy, memory_format)
|
||||
inline at::Tensor Tensor::to(
|
||||
at::Device device,
|
||||
at::ScalarType dtype,
|
||||
bool non_blocking,
|
||||
bool copy,
|
||||
::std::optional<at::MemoryFormat> memory_format) const {
|
||||
at::TensorOptions options = at::TensorOptions().device(device).dtype(dtype);
|
||||
return to(options, non_blocking, copy, memory_format);
|
||||
}
|
||||
|
||||
// Overload 4: to(ScalarType, non_blocking, copy, memory_format)
|
||||
inline at::Tensor Tensor::to(
|
||||
at::ScalarType dtype,
|
||||
bool non_blocking,
|
||||
bool copy,
|
||||
::std::optional<at::MemoryFormat> memory_format) const {
|
||||
auto target_dtype = compat::_PD_AtenScalarTypeToPhiDataType(dtype);
|
||||
if (!copy && target_dtype == tensor_.dtype()) {
|
||||
return *this;
|
||||
}
|
||||
return at::Tensor(paddle::experimental::cast(tensor_, target_dtype));
|
||||
}
|
||||
|
||||
// Overload 5: to(const Tensor& other, non_blocking, copy, memory_format)
|
||||
inline at::Tensor Tensor::to(
|
||||
const at::Tensor& other,
|
||||
bool non_blocking,
|
||||
bool copy,
|
||||
::std::optional<at::MemoryFormat> memory_format) const {
|
||||
at::TensorOptions options =
|
||||
at::TensorOptions().device(other.device()).dtype(other.scalar_type());
|
||||
return to(options, non_blocking, copy, memory_format);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
|
||||
namespace at::detail {
|
||||
|
||||
inline int _PD_normalize_transpose_dim(int64_t dim,
|
||||
int64_t ndim,
|
||||
const char* name) {
|
||||
int64_t normalized = dim;
|
||||
if (normalized < 0) {
|
||||
normalized += ndim;
|
||||
}
|
||||
|
||||
PD_CHECK(normalized >= 0 && normalized < ndim, name, " out of range");
|
||||
PD_CHECK(normalized <= static_cast<int64_t>(std::numeric_limits<int>::max()),
|
||||
name,
|
||||
" out of int range");
|
||||
return static_cast<int>(normalized);
|
||||
}
|
||||
|
||||
inline std::vector<int> _PD_make_transpose_perm(int64_t ndim, int d0, int d1) {
|
||||
PD_CHECK(ndim <= static_cast<int64_t>(std::numeric_limits<int>::max()),
|
||||
"tensor rank out of int range");
|
||||
|
||||
std::vector<int> perm(static_cast<size_t>(ndim));
|
||||
for (int64_t i = 0; i < ndim; ++i) {
|
||||
perm[static_cast<size_t>(i)] = static_cast<int>(i);
|
||||
}
|
||||
std::swap(perm[d0], perm[d1]);
|
||||
return perm;
|
||||
}
|
||||
|
||||
} // namespace at::detail
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor transpose(const at::Tensor& self,
|
||||
int64_t dim0,
|
||||
int64_t dim1) {
|
||||
int64_t ndim = self.dim();
|
||||
int d0 = at::detail::_PD_normalize_transpose_dim(dim0, ndim, "dim0");
|
||||
int d1 = at::detail::_PD_normalize_transpose_dim(dim1, ndim, "dim1");
|
||||
auto perm = at::detail::_PD_make_transpose_perm(ndim, d0, d1);
|
||||
|
||||
return paddle::experimental::transpose(self._PD_GetInner(), perm);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::transpose(int64_t dim0, int64_t dim1) const {
|
||||
return at::transpose(*this, dim0, dim1);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::transpose_(int64_t dim0, int64_t dim1) const {
|
||||
int64_t ndim = this->dim();
|
||||
int d0 = at::detail::_PD_normalize_transpose_dim(dim0, ndim, "dim0");
|
||||
int d1 = at::detail::_PD_normalize_transpose_dim(dim1, ndim, "dim1");
|
||||
auto perm = at::detail::_PD_make_transpose_perm(ndim, d0, d1);
|
||||
PaddleTensor& inner = const_cast<PaddleTensor&>(tensor_);
|
||||
paddle::experimental::transpose_(inner, perm);
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor unflatten(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
at::IntArrayRef sizes) {
|
||||
// Compute the new shape by replacing the dimension at 'dim' with 'sizes'
|
||||
int64_t ndim = self._PD_GetInner().dims().size();
|
||||
int64_t actual_dim = dim < 0 ? dim + ndim : dim;
|
||||
std::vector<int64_t> new_shape;
|
||||
for (int64_t i = 0; i < ndim; ++i) {
|
||||
if (i == actual_dim) {
|
||||
for (auto s : sizes) {
|
||||
new_shape.push_back(s);
|
||||
}
|
||||
} else {
|
||||
new_shape.push_back(self._PD_GetInner().dims()[i]);
|
||||
}
|
||||
}
|
||||
return Tensor(paddle::experimental::reshape(self._PD_GetInner(), new_shape));
|
||||
}
|
||||
|
||||
inline at::Tensor unflatten_symint(const at::Tensor& self,
|
||||
int64_t dim,
|
||||
c10::SymIntArrayRef sizes) {
|
||||
return unflatten(
|
||||
self,
|
||||
dim,
|
||||
at::IntArrayRef(reinterpret_cast<const int64_t*>(sizes.data()),
|
||||
sizes.size()));
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::unflatten(int64_t dim, at::IntArrayRef sizes) const {
|
||||
return at::unflatten(*this, dim, sizes);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::unflatten_symint(int64_t dim,
|
||||
c10::SymIntArrayRef sizes) const {
|
||||
return at::unflatten_symint(*this, dim, sizes);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/split.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> unsafe_split(const at::Tensor& self,
|
||||
int64_t split_size,
|
||||
int64_t dim = 0) {
|
||||
return at::split(self, split_size, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> unsafe_split_symint(const at::Tensor& self,
|
||||
c10::SymInt split_size,
|
||||
int64_t dim = 0) {
|
||||
return at::split(self, static_cast<int64_t>(split_size), dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::unsafe_split(int64_t split_size,
|
||||
int64_t dim) const {
|
||||
return at::unsafe_split(*this, split_size, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::unsafe_split_symint(
|
||||
c10::SymInt split_size, int64_t dim) const {
|
||||
return at::unsafe_split_symint(*this, split_size, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/split.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> unsafe_split_with_sizes(
|
||||
const at::Tensor& self, at::IntArrayRef split_sizes, int64_t dim = 0) {
|
||||
return at::split(self, split_sizes, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> unsafe_split_with_sizes_symint(
|
||||
const at::Tensor& self, c10::SymIntArrayRef split_sizes, int64_t dim = 0) {
|
||||
return at::split_symint(self, split_sizes, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::unsafe_split_with_sizes(
|
||||
at::IntArrayRef split_sizes, int64_t dim) const {
|
||||
return at::unsafe_split_with_sizes(*this, split_sizes, dim);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::unsafe_split_with_sizes_symint(
|
||||
c10::SymIntArrayRef split_sizes, int64_t dim) const {
|
||||
return at::unsafe_split_with_sizes_symint(*this, split_sizes, dim);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor unsqueeze(const at::Tensor& self, int64_t dim) {
|
||||
return paddle::experimental::unsqueeze(self._PD_GetInner(), {dim});
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::unsqueeze(int64_t dim) const {
|
||||
return at::unsqueeze(*this, dim);
|
||||
}
|
||||
|
||||
inline at::Tensor& Tensor::unsqueeze_(int64_t dim) const {
|
||||
PaddleTensor& inner = const_cast<PaddleTensor&>(tensor_);
|
||||
paddle::experimental::unsqueeze_(inner, {dim});
|
||||
return const_cast<at::Tensor&>(*this);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor view(const at::Tensor& self, at::IntArrayRef size) {
|
||||
return paddle::experimental::view_shape(self._PD_GetInner(), size.vec());
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::view(at::IntArrayRef size) const {
|
||||
return at::view(*this, size);
|
||||
}
|
||||
|
||||
inline at::Tensor Tensor::view(at::ScalarType dtype) const {
|
||||
return paddle::experimental::view_dtype(
|
||||
this->_PD_GetInner(), compat::_PD_AtenScalarTypeToPhiDataType(dtype));
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
|
||||
namespace at {}
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor Tensor::view_as(const at::Tensor& other) const {
|
||||
return view(other.sizes());
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <ATen/ops/tensor_split.h>
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> vsplit(const at::Tensor& self,
|
||||
int64_t sections) {
|
||||
return at::tensor_split(self, sections, 0);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> vsplit(const at::Tensor& self,
|
||||
at::IntArrayRef indices) {
|
||||
return at::tensor_split(self, indices, 0);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
|
||||
namespace at {
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::vsplit(int64_t sections) const {
|
||||
return at::vsplit(*this, sections);
|
||||
}
|
||||
|
||||
inline std::vector<at::Tensor> Tensor::vsplit(at::IntArrayRef indices) const {
|
||||
return at::vsplit(*this, indices);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,106 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/SymIntArrayRef.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/dense_sparse_conversion.h>
|
||||
#include <utils/pinned_place.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor zeros(at::IntArrayRef size, at::TensorOptions options = {}) {
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::zeros(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
dense = dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
return compat::_PD_ConvertToSparseIfNeeded(dense, options.layout());
|
||||
}
|
||||
auto dense = paddle::experimental::zeros(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
return compat::_PD_ConvertToSparseIfNeeded(dense, options.layout());
|
||||
}
|
||||
|
||||
inline at::Tensor zeros(at::IntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.layout(layout)
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return zeros(size, options);
|
||||
}
|
||||
|
||||
inline at::Tensor zeros_symint(c10::SymIntArrayRef size,
|
||||
at::TensorOptions options = {}) {
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
auto dense = paddle::experimental::zeros(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
phi::CPUPlace());
|
||||
dense = dense.copy_to(pinned_place, /*blocking=*/true);
|
||||
return compat::_PD_ConvertToSparseIfNeeded(dense, options.layout());
|
||||
}
|
||||
auto dense = paddle::experimental::zeros(
|
||||
size._PD_ToPaddleIntArray(),
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(options.dtype()),
|
||||
options._PD_GetPlace());
|
||||
return compat::_PD_ConvertToSparseIfNeeded(dense, options.layout());
|
||||
}
|
||||
|
||||
inline at::Tensor zeros_symint(c10::SymIntArrayRef size,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory) {
|
||||
auto options =
|
||||
at::TensorOptions()
|
||||
.dtype(dtype.value_or(c10::get_default_dtype_as_scalartype()))
|
||||
.layout(layout)
|
||||
.device(device.value_or(at::kCPU))
|
||||
.pinned_memory(pin_memory);
|
||||
return zeros_symint(size, options);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
@@ -0,0 +1,93 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ATen/core/Tensor.h>
|
||||
#include <c10/core/TensorOptions.h>
|
||||
#include <utils/dense_sparse_conversion.h>
|
||||
#include <utils/pinned_place.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "paddle/phi/api/include/api.h"
|
||||
#include "paddle/phi/api/include/sparse_api.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace at {
|
||||
|
||||
inline at::Tensor zeros_like(
|
||||
const at::Tensor& self,
|
||||
at::TensorOptions options = {},
|
||||
::std::optional<at::MemoryFormat> memory_format = ::std::nullopt) {
|
||||
PD_CHECK(!(memory_format.has_value() &&
|
||||
memory_format.value() != c10::MemoryFormat::Contiguous),
|
||||
"`MemoryFormat` other than Contiguous is not supported now.");
|
||||
|
||||
auto layout = options.layout();
|
||||
if (layout == c10::kStrided && (self.is_sparse() || self.is_sparse_csr())) {
|
||||
layout = self.layout();
|
||||
}
|
||||
|
||||
auto dtype = options.dtype();
|
||||
if (dtype == c10::ScalarType::Undefined) {
|
||||
dtype = self.scalar_type();
|
||||
}
|
||||
|
||||
paddle::Tensor base = self._PD_GetInner();
|
||||
if (self.is_sparse() || self.is_sparse_csr()) {
|
||||
base = paddle::experimental::sparse::to_dense(base);
|
||||
}
|
||||
|
||||
paddle::Tensor dense;
|
||||
if (options.pinned_memory()) {
|
||||
// Pinning memory is only supported for CPU tensors
|
||||
if (options.has_device() && !options.device().is_cpu()) {
|
||||
PD_THROW(
|
||||
"pin_memory=true requires device to be CPU, but got non-CPU device");
|
||||
}
|
||||
auto dense_cpu = paddle::experimental::zeros_like(
|
||||
base, compat::_PD_AtenScalarTypeToPhiDataType(dtype), phi::CPUPlace());
|
||||
phi::Place base_place = options._PD_GetPlace();
|
||||
phi::Place pinned_place = compat::_PD_GetCreatePinnedPlace(base_place);
|
||||
dense = dense_cpu.copy_to(pinned_place, /*blocking=*/true);
|
||||
} else {
|
||||
dense = paddle::experimental::zeros_like(
|
||||
base,
|
||||
compat::_PD_AtenScalarTypeToPhiDataType(dtype),
|
||||
options._PD_GetPlace());
|
||||
}
|
||||
return compat::_PD_ConvertToSparseIfNeeded(dense, layout);
|
||||
}
|
||||
|
||||
inline at::Tensor zeros_like(const at::Tensor& self,
|
||||
::std::optional<at::ScalarType> dtype,
|
||||
::std::optional<at::Layout> layout,
|
||||
::std::optional<at::Device> device,
|
||||
::std::optional<bool> pin_memory,
|
||||
::std::optional<at::MemoryFormat> memory_format) {
|
||||
PD_CHECK(!(memory_format.has_value() &&
|
||||
memory_format.value() != c10::MemoryFormat::Contiguous),
|
||||
"`MemoryFormat` other than Contiguous is not supported now.");
|
||||
|
||||
auto options = at::TensorOptions()
|
||||
.dtype(dtype)
|
||||
.layout(layout)
|
||||
.device(device)
|
||||
.pinned_memory(pin_memory);
|
||||
return zeros_like(self, options, memory_format);
|
||||
}
|
||||
|
||||
} // namespace at
|
||||
Reference in New Issue
Block a user