Files
2026-07-13 12:47:05 +08:00

145 lines
5.5 KiB
Plaintext

/*
* ******************************************************************************
* *
* *
* * This program and the accompanying materials are made available under the
* * terms of the Apache License, Version 2.0 which is available at
* * https://www.apache.org/licenses/LICENSE-2.0.
* *
* * See the NOTICE file distributed with this work for additional
* * information regarding copyright ownership.
* * 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.
* *
* * SPDX-License-Identifier: Apache-2.0
* *****************************************************************************
*/
//
// @author GS <sgazeos@gmail.com>
//
#include <array/NDArray.h>
#include <array/NDArrayFactory.h>
#include <execution/Threads.h>
#include <helpers/ConstantTadHelper.h>
#include <helpers/MmulHelper.h>
#include <system/op_boilerplate.h>
#include "../lup.h"
#include "../solve.h"
#include "../triangular_solve.h"
#include "execution/cuda/LaunchDims.h"
#include "helpers/DebugHelper.h"
namespace sd {
namespace ops {
namespace helpers {
template <typename T>
static Status solveFunctor_(LaunchContext* context, NDArray* leftInput, NDArray* rightInput, bool adjoint,
NDArray* output) {
// TODO: note: this is the cpu implementation.
// it's not preferred but cuda has enough edge cases
// that I would prefer to have a working solution for now.
NDArray::preparePrimaryUse({output}, {leftInput, rightInput});
// stage 1: LU decomposition batched
auto leftOutput = leftInput->ulike();
auto permuShape = rightInput->getShapeAsVector();
permuShape.pop_back();
auto permutations = NDArrayFactory::create<LongType>('c', permuShape, context);
lu(context, leftInput, leftOutput, &permutations);
auto leftLower = leftOutput->dup();
auto rightOutput = rightInput->ulike();
const std::vector<LongType> dims1 = {-2, -1};
auto P = leftInput->ulike();
P->nullify();
auto PPart = P->allTensorsAlongDimension({-2, -1});
auto permutationsPart = permutations.allTensorsAlongDimension({-1});
for (auto batch = 0; batch < permutationsPart.size(); batch++) {
for (LongType row = 0; row < PPart[batch]->rows(); row++) {
std::vector<LongType> vec = {row, permutationsPart[batch]->t<LongType>(row)};
PPart[batch]->r<T>(row, permutationsPart[batch]->t<LongType>(row)) = T(1.f);
}
}
P->tickWriteHost();
auto rightPart = rightInput->ulike();
MmulHelper::matmul(P, rightInput, rightPart,false,false, 0.0, 0.0,rightPart);
ResultSet leftLowerPart = leftLower.allTensorsAlongDimension({-2, -1});
for (auto i = 0; i < leftLowerPart.size(); i++) {
for (LongType r = 0; r < leftLowerPart[i]->rows(); r++) leftLowerPart[i]->r<T>(r, r) = (T)1.f;
}
triangularSolveFunctor(context, &leftLower, rightPart, true, false, rightOutput);
triangularSolveFunctor(context, leftOutput, rightOutput, false, false, output);
NDArray::registerPrimaryUse({output}, {leftInput, rightInput});
return Status::OK;
}
Status solveFunctor(LaunchContext* context, NDArray* leftInput, NDArray* rightInput, bool adjoint,
NDArray* output) {
BUILD_SINGLE_SELECTOR(leftInput->dataType(), return solveFunctor_, (context, leftInput, rightInput, adjoint, output),
SD_FLOAT_TYPES);
}
template <typename T>
static SD_KERNEL void adjointKernel(T* output, LongType batchSize, LongType rows, LongType columns,
LongType const* outputTads, LongType const* outputOffsets) {
for (auto b = blockIdx.x; b < batchSize; b += gridDim.x) {
auto outputPart = output + outputOffsets[b];
for (auto r = threadIdx.x; r < rows; r += blockDim.x) {
for (auto c = threadIdx.y; c < r; c += blockDim.y) {
LongType zPos[] = {r, c};
LongType xPos[] = {c, r};
LongType zIndex, xIndex;
COORDS2INDEX(shape::rank(outputTads), shape::stride(outputTads), zPos, zIndex);
COORDS2INDEX(shape::rank(outputTads), shape::stride(outputTads), xPos, xIndex);
math::sd_swap(outputPart[zIndex], outputPart[xIndex]);
}
}
}
}
template <typename T>
static void adjointMatrix_(LaunchContext* context, NDArray * input, NDArray* output) {
NDArray::prepareSpecialUse({output}, {input});
const std::vector<LongType> dims1 = {-2, -1};
auto outputTads = ConstantTadHelper::getInstance().tadForDimensions(
output->shapeInfo(), const_cast<LongType*>(dims1.data()), dims1.size());
auto stream = context->getCudaStream();
auto outputBuf = reinterpret_cast<T*>(output->specialBuffer());
auto rows = input->sizeAt(-2);
auto columns = input->sizeAt(-1);
output->assign(input);
dim3 solveDims = getLaunchDims("solve");
adjointKernel<T><<<solveDims.x,solveDims.y, solveDims.z, *stream>>>(outputBuf, outputTads->numberOfTads(), rows, columns,
outputTads->specialShapeInfo(), outputTads->specialOffsets());
sd::DebugHelper::checkErrorCode(const_cast<cudaStream_t *>(stream), "adjointKernel failed");
NDArray::registerSpecialUse({output}, {input});
}
void adjointMatrix(LaunchContext* context, NDArray * input, NDArray* output) {
BUILD_SINGLE_SELECTOR(input->dataType(), adjointMatrix_, (context, input, output), SD_FLOAT_TYPES);
}
} // namespace helpers
} // namespace ops
} // namespace sd