// Copyright (c) 2022 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. #include "paddle/phi/kernels/eig_kernel.h" #include "paddle/phi/kernels/cpu/eig.h" #include "paddle/phi/core/kernel_registry.h" namespace phi { template void EigKernel(const Context& dev_ctx, const DenseTensor& x, DenseTensor* out_w, DenseTensor* out_v) { dev_ctx.template Alloc>(out_w); dev_ctx.template Alloc>(out_v); if (x.numel() == 0) { return; } if (!IsComplexType(x.dtype())) { int batch_count = BatchCount(x); int order = static_cast(x.dims(-1)); PADDLE_ENFORCE_LT(0, order, errors::InvalidArgument( "The order of Input(X) should be greater than 0.")); DenseTensor out_w_real; DenseTensor out_v_real; // double the size of out_w_real, the first half stores the real part, // the next half stores the imag part std::vector real_w_dims = vectorize(out_w->dims()); real_w_dims.back() *= 2; out_w_real.Resize(real_w_dims); dev_ctx.template Alloc>(&out_w_real); out_v_real.Resize(x.dims()); dev_ctx.template Alloc>(&out_v_real); ApplyEigKernel, Context>( x, &out_w_real, &out_v_real, dev_ctx); // 1. extract real part & imag part from out_w_real DenseTensor out_w_real_part = funcs::Slice(dev_ctx, out_w_real, {-1}, {0}, {order}); DenseTensor out_w_imag_part = funcs::Slice(dev_ctx, out_w_real, {-1}, {order}, {order * 2}); // 2. construct complex values auto* out_w_real_part_ptr = out_w_real_part.data>(); auto* out_w_imag_part_ptr = out_w_imag_part.data>(); int out_w_numel = static_cast(out_w->numel()); funcs::ForRange for_range(dev_ctx, out_w_numel); funcs::RealImagToComplexFunctor> functor( out_w_real_part_ptr, out_w_imag_part_ptr, dev_ctx.template Alloc>(out_w), out_w_numel); for_range(functor); // 3. construct complex vectors DenseTensor out_v_real_trans = TransposeLast2Dim(dev_ctx, out_v_real); DenseTensor out_v_trans; out_v_trans.Resize(x.dims()); dev_ctx.template Alloc>(&out_v_trans); ConstructComplexVectors, dtype::Complex, Context>( &out_v_trans, *out_w, out_v_real_trans, dev_ctx, batch_count, order); TransposeTwoAxis, Context>( out_v_trans, out_v, x.dims().size() - 1, x.dims().size() - 2, dev_ctx); } else { ApplyEigKernel(x, out_w, out_v, dev_ctx); } } } // namespace phi PD_REGISTER_KERNEL(eig, CPU, ALL_LAYOUT, phi::EigKernel, float, double, phi::complex64, phi::complex128) { if (kernel_key.dtype() == phi::DataType::FLOAT32 || kernel_key.dtype() == phi::DataType::FLOAT64) { kernel->OutputAt(0).SetDataType(phi::dtype::ToComplex(kernel_key.dtype())); kernel->OutputAt(1).SetDataType(phi::dtype::ToComplex(kernel_key.dtype())); } }