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

1377 lines
60 KiB
C++

/* ******************************************************************************
*
*
* 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 Yurii Shyrma (iuriish@yahoo.com), created on 14.03.2019
//
#ifndef LIBND4J_LOOPS_H
#define LIBND4J_LOOPS_H
#include <array/DataTypeUtils.h>
#include <execution/Threads.h>
#include <helpers/ConstantTadHelper.h>
#include <helpers/LoopKind.h>
#include <helpers/OmpLaunchHelper.h>
#include <helpers/shape.h>
#include <loops/indexreduce.h>
#include <ops/ops.h>
#include <functional>
namespace sd {
template <typename X, typename Z, typename E>
class ReductionLoops {
protected:
public:
template <typename OpType>
static SD_INLINE void loopReduce(memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims, E* extraParams);
};
template <typename X, typename Z>
class SD_LIB_HIDDEN ReductionFloatLoops : public ReductionLoops<X, Z, Z> {
public:
static void wrapper(int opNum, memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims, Z* extraParams);
template <typename OpType>
static void innerloopReduce(memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims, Z* extraParams);
};
template <typename X, typename Z>
class SD_LIB_HIDDEN ReductionBoolLoops : public ReductionLoops<X, Z, X> {
public:
static void wrapper(int opNum, memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims, X* extraParams);
template <typename OpType>
static void innerloopReduce(memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims, X* extraParams);
};
template <typename X, typename Z>
class SD_LIB_HIDDEN ReductionLongLoops : public ReductionLoops<X, Z, X> {
public:
static void wrapper(int opNum, memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims, X* extraParams);
template <typename OpType>
static void innerloopReduce(memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims, X* extraParams);
};
template <typename X>
class ReductionSameLoops : public ReductionLoops<X, X, X> {
public:
static void wrapper(int opNum, memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, X* z,
const LongType* zShapeInfo, const LongType* dims, X* extraParams);
template <typename OpType>
static void innerloopReduce(memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, X* z,
const LongType* zShapeInfo, const LongType* dims, X* extraParams);
};
template <typename X, typename Z>
class IndexReductionLoops {
public:
static void wrapIndexReduce(int opNum, const void* x, const LongType* xShapeInfo, void* z,
const LongType* zShapeInfo, const LongType* tadShapeInfo,
const LongType* tadOffsets, void* extraParams);
template <typename OpType>
static void loopIndexReduce(X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* tadShapeInfo, const LongType* tadOffsets, void* extraParams);
};
template <typename X, typename Z, typename E>
class SD_LIB_HIDDEN TransformLoops {
public:
template <typename OpType>
static SD_INLINE void loopTransform(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
E* extraParams, LongType threadId, LongType numThreads);
};
template <typename X, typename Z>
class Reduction3Loops {
public:
template <typename OpType>
static SD_INLINE void loopReduce3(const X* x, const LongType* xShapeInfo, const X* y,
const LongType* yShapeInfo, Z* z, const LongType* zShapeInfo,
LongType* dims,
int dimsLen, Z* extraParams, int64_t start, int64_t stop);
template <typename OpType>
static SD_INLINE void loopReduce3All(const X* x, const LongType* xShapeInfo, const X* y,
const LongType* yShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* xTadShapeInfo, const LongType* xTadOffsets,
const LongType* yTadShapeInfo, const LongType* yTadOffsets,
Z* extraParams, int64_t start, int64_t stop);
static void wrapper(int opNum, const X* x, const LongType* xShapeInfo, const X* y, const LongType* yShapeInfo,
Z* z, const LongType* zShapeInfo, LongType* dims, int dimsLen, Z* extraParams, int64_t start,
int64_t stop);
static void wrapperAll(int opNum, const X* x, const LongType* xShapeInfo, const X* y,
const LongType* yShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* xTadShapeInfo, const LongType* xTadOffsets,
const LongType* yTadShapeInfo, const LongType* yTadOffsets, Z* extraParams,
int64_t start, int64_t stop);
template <typename OpType>
static void innerloopReduce3(const X* x, const LongType* xShapeInfo, const X* y, const LongType* yShapeInfo,
Z* z, const LongType* zShapeInfo, LongType* dims, int dimsLen, Z* extraParams,
int64_t start, int64_t stop);
template <typename OpType>
static void innerloopReduce3All(const X* x, const LongType* xShapeInfo, const X* y,
const LongType* yShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* xTadShapeInfo, const LongType* xTadOffsets,
const LongType* yTadShapeInfo, const LongType* yTadOffsets, Z* extraParams,
int64_t start, int64_t stop);
};
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
static void reduceExec21(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, dims[0]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, dims[0]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, static_cast<LongType>(0));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, dims[1]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, dims[1]);
// Convert parameters to Z* for OpType compatibility
Z* compatibleExtraParams = nullptr;
Z convertedParams[8];
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
// Convert parameters to Z type
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR {
for (auto i0 = start; i0 < stop; ++i0) {
auto x0 = x + i0 * xStrd0;
auto z0 = z + i0 * zStrd0;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x0));
if (xStrd1 == 1)
for (LongType i1 = 0; i1 < xAxis1; ++i1) {
s = OpType::update(s, OpType::op(x0[i1], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i1 = 0; i1 < xAxis1; ++i1) {
s = OpType::update(s, OpType::op(x0[i1 * xStrd1], compatibleExtraParams), compatibleExtraParams);
}
*z0 = OpType::postProcess(s, static_cast<LongType>(xAxis1), compatibleExtraParams);
}
};
samediff::Threads::parallel_for(func, 0, xAxis0);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
static void reduceExec31(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, dims[0]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, dims[0]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, static_cast<LongType>(0));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, dims[1]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, dims[1]);
const LongType xAxis2 = shape::sizeAt(xShapeInfo, dims[2]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, dims[2]);
const LongType tadLen = static_cast<LongType>(xAxis1 * xAxis2);
Z* compatibleExtraParams = nullptr;
Z convertedParams[8];
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
// Convert parameters to Z type
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR {
for (auto i0 = start; i0 < stop; ++i0) {
auto x0 = x + i0 * xStrd0;
auto z0 = z + i0 * zStrd0;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x0));
if (xStrd1 == 1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i1 = 0; i1 < xAxis1; ++i1) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2 is %lld,%lld,%lld reduceExec31\n", i0,i1,i2);
#endif
s = OpType::update(s, OpType::op(x0[i1 + i2 * xStrd2], compatibleExtraParams), compatibleExtraParams);
}
else if (xStrd2 == 1)
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i2 = 0; i2 < xAxis2; ++i2) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2 is %lld,%lld,%lld offset is %lld reduceExec31\n", i0,i1,i2,i1 * xStrd1 + i2);
#endif
s = OpType::update(s, OpType::op(x0[i1 * xStrd1 + i2], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i2 = 0; i2 < xAxis2; ++i2) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2 is %lld,%lld,%lld offset is %lld reduceExec31\n", i0,i1,i2,i1 * xStrd1 + i2 * xStrd2);
#endif
s = OpType::update(s, OpType::op(x0[i1 * xStrd1 + i2 * xStrd2], compatibleExtraParams), compatibleExtraParams);
}
*z0 = OpType::postProcess(s, tadLen, compatibleExtraParams);
}
};
samediff::Threads::parallel_for(func, 0, xAxis0);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceExec32(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[1]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[1]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(0) : static_cast<LongType>(1));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[1] : dims[0]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[1] : dims[0]);
const LongType zStrd1 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(1) : static_cast<LongType>(0));
const LongType xAxis2 = shape::sizeAt(xShapeInfo, dims[2]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, dims[2]);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR_2D {
for (auto i0 = start_x; i0 < stop_x; ++i0) {
for (auto i1 = start_y; i1 < stop_y; ++i1) {
auto x1 = x + i0 * xStrd0 + i1 * xStrd1;
auto z1 = z + i0 * zStrd0 + i1 * zStrd1;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x1));
if (xStrd2 == 1)
for (LongType i2 = 0; i2 < xAxis2; ++i2) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2 is %lld,%lld,%lld reduceExec32\n", i0,i1,i2);
#endif
s = OpType::update(s, OpType::op(x1[i2], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i2 = 0; i2 < xAxis2; ++i2) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2 is %lld,%lld,%lld reduceExec32\n", i0,i1,i2);
#endif
s = OpType::update(s, OpType::op(x1[i2 * xStrd2], compatibleExtraParams), compatibleExtraParams);
}
*z1 = OpType::postProcess(s, static_cast<LongType>(xAxis2), compatibleExtraParams);
}
}
};
samediff::Threads::parallel_for(func, 0, xAxis0, 1, 0, xAxis1, 1);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceExec41(const X* x,
const LongType* xShapeInfo,
Z* z, const
LongType* zShapeInfo,
const LongType* dims,
E* extraParams) {
LongType xRank = shape::rank(xShapeInfo);
LongType zRank = shape::rank(zShapeInfo);
const LongType xAxis0 = shape::sizeAt(xShapeInfo, dims[0]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, dims[0]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, static_cast<LongType>(0));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, dims[1]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, dims[1]);
const LongType xAxis2 = shape::sizeAt(xShapeInfo, dims[2]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, dims[2]);
const LongType xAxis3 = shape::sizeAt(xShapeInfo, dims[3]);
const LongType xStrd3 = shape::strideAt(xShapeInfo, dims[3]);
const LongType tadLen = static_cast<LongType>(xAxis1 * xAxis2 * xAxis3);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR {
for (auto i0 = start; i0 < stop; ++i0) {
auto x0 = x + i0 * xStrd0;
auto z0 = z + i0 * zStrd0;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x0));
if (xStrd1 == 1)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i1 = 0; i1 < xAxis1; ++i1) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld offset is %lld reduceExec41\n", i0,i1,i2,i3,i1 + i2 * xStrd2 + i3 * xStrd3);
#endif
s = OpType::update(s, OpType::op(x0[i1 + i2 * xStrd2 + i3 * xStrd3], compatibleExtraParams), compatibleExtraParams);
}
else if (xStrd2 == 1)
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i2 = 0; i2 < xAxis2; ++i2) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld offset is %lld reduceExec41\n", i0,i1,i2,i3,i1 * xStrd1 + i2 + i3 * xStrd3);
#endif
s = OpType::update(s, OpType::op(x0[i1 * xStrd1 + i2 + i3 * xStrd3], compatibleExtraParams), compatibleExtraParams);
}
else if (xStrd3 == 1)
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld offset is %lld reduceExec41\n", i0,i1,i2,i3,i1 * xStrd1 + i2 * xStrd2 + i3);
#endif
s = OpType::update(s, OpType::op(x0[i1 * xStrd1 + i2 * xStrd2 + i3], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld offset is %lld reduceExec41\n", i0,i1,i2,i3,i1 * xStrd1 + i2 * xStrd2 + i3 * xStrd3);
#endif
s = OpType::update(s, OpType::op(x0[i1 * xStrd1 + i2 * xStrd2 + i3 * xStrd3], compatibleExtraParams), compatibleExtraParams);
}
*z0 = OpType::postProcess(s, tadLen, compatibleExtraParams);
}
};
samediff::Threads::parallel_for(func, 0, xAxis0);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceExec42(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[1]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[1]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(0) : static_cast<LongType>(1));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[1] : dims[0]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[1] : dims[0]);
const LongType zStrd1 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(1) : static_cast<LongType>(0));
const LongType xAxis2 = shape::sizeAt(xShapeInfo, dims[2]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, dims[2]);
const LongType xAxis3 = shape::sizeAt(xShapeInfo, dims[3]);
const LongType xStrd3 = shape::strideAt(xShapeInfo, dims[3]);
const LongType tadLen = static_cast<LongType>(xAxis2 * xAxis3);
LongType xRank = shape::rank(xShapeInfo);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR_2D {
for (auto i0 = start_x; i0 < stop_x; ++i0) {
for (auto i1 = start_y; i1 < stop_y; ++i1) {
auto x1 = x + i0 * xStrd0 + i1 * xStrd1;
auto z1 = z + i0 * zStrd0 + i1 * zStrd1;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x1));
if (xStrd2 == 1)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i2 = 0; i2 < xAxis2; ++i2) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld reduceExec42\n", i0,i1,i2,i3);
#endif
s = OpType::update(s, OpType::op(x1[i2 + i3 * xStrd3], compatibleExtraParams), compatibleExtraParams);
}
else if (xStrd3 == 1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld offset %lld reduceExec42\n", i0,i1,i2,i3,i2 * xStrd2 + i3);
#endif
s = OpType::update(s, OpType::op(x1[i2 * xStrd2 + i3], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld offset %lld reduceExec42\n", i0,i1,i2,i3,i2 * xStrd2 + i3 * xStrd3);
#endif
s = OpType::update(s, OpType::op(x1[i2 * xStrd2 + i3 * xStrd3], compatibleExtraParams), compatibleExtraParams);
}
*z1 = OpType::postProcess(s, tadLen, compatibleExtraParams);
}
}
};
samediff::Threads::parallel_for(func, 0, xAxis0, 1, 0, xAxis1, 1);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceExec43(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[2]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[2]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(0) : static_cast<LongType>(2));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, dims[1]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, dims[1]);
const LongType zStrd1 = shape::strideAt(zShapeInfo, static_cast<LongType>(1));
const LongType xAxis2 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[2] : dims[0]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[2] : dims[0]);
const LongType zStrd2 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(2) : static_cast<LongType>(0));
const LongType xAxis3 = shape::sizeAt(xShapeInfo, dims[3]);
const LongType xStrd3 = shape::strideAt(xShapeInfo, dims[3]);
LongType xRank = shape::rank(xShapeInfo);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR_3D {
for (auto i0 = start_x; i0 < stop_x; ++i0) {
for (auto i1 = start_y; i1 < stop_y; ++i1) {
for (auto i2 = start_z; i2 < stop_z; ++i2) {
auto x2 = x + i0 * xStrd0 + i1 * xStrd1 + i2 * xStrd2;
auto z2 = z + i0 * zStrd0 + i1 * zStrd1 + i2 * zStrd2;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x2));
if (xStrd3 == 1)
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld reduceExec43\n", i0,i1,i2,i3);
#endif
s = OpType::update(s, OpType::op(x2[i3], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3 is %lld,%lld,%lld,%lld reduceExec43\n", i0,i1,i2,i3);
#endif
s = OpType::update(s, OpType::op(x2[i3 * xStrd3], compatibleExtraParams), compatibleExtraParams);
}
*z2 = OpType::postProcess(s, static_cast<LongType>(xAxis3), compatibleExtraParams);
}
}
}
};
samediff::Threads::parallel_for(func, 0, xAxis0, 1, 0, xAxis1, 1, 0, xAxis2, 1);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceExec51(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, dims[0]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, dims[0]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, static_cast<LongType>(0));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, dims[1]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, dims[1]);
const LongType xAxis2 = shape::sizeAt(xShapeInfo, dims[2]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, dims[2]);
const LongType xAxis3 = shape::sizeAt(xShapeInfo, dims[3]);
const LongType xStrd3 = shape::strideAt(xShapeInfo, dims[3]);
const LongType xAxis4 = shape::sizeAt(xShapeInfo, dims[4]);
const LongType xStrd4 = shape::strideAt(xShapeInfo, dims[4]);
const LongType tadLen = static_cast<LongType>(xAxis1 * xAxis2 * xAxis3 * xAxis4);
LongType xRank = shape::rank(xShapeInfo);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR {
for (auto i0 = start; i0 < stop; ++i0) {
auto x0 = x + i0 * xStrd0;
auto z0 = z + i0 * zStrd0;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x0));
if (xStrd1 == 1)
for (LongType i4 = 0; i4 < xAxis4; ++i4)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i1 = 0; i1 < xAxis1; ++i1) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld reduceExec51\n", i0,i1,i2,i3,i4);
#endif
s = OpType::update(s, OpType::op(x0[i1 + i2 * xStrd2 + i3 * xStrd3 + i4 * xStrd4], compatibleExtraParams),
compatibleExtraParams);
}
else if (xStrd2 == 1)
for (LongType i4 = 0; i4 < xAxis4; ++i4)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i2 = 0; i2 < xAxis2; ++i2) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lldreduceExec51\n", i0,i1,i2,i3,i4,i1 * xStrd1 + i2 + i3 * xStrd3 + i4 * xStrd4);
#endif
s = OpType::update(s, OpType::op(x0[i1 * xStrd1 + i2 + i3 * xStrd3 + i4 * xStrd4], compatibleExtraParams),
compatibleExtraParams);
}
else if (xStrd3 == 1)
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i4 = 0; i4 < xAxis4; ++i4)
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec51\n", i0,i1,i2,i3,i4,i1 * xStrd1 + i2 * xStrd2 + i3 + i4 * xStrd4);
#endif
s = OpType::update(s, OpType::op(x0[i1 * xStrd1 + i2 * xStrd2 + i3 + i4 * xStrd4], compatibleExtraParams),
compatibleExtraParams);
}
else if (xStrd4 == 1)
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i4 = 0; i4 < xAxis4; ++i4) {
#if defined(PRINT_INDICES)
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec51\n", i0,i1,i2,i3,i4,i1 * xStrd1 + i2 * xStrd2 + i3 * xStrd3 + i4);
#endif
s = OpType::update(s, OpType::op(x0[i1 * xStrd1 + i2 * xStrd2 + i3 * xStrd3 + i4], compatibleExtraParams),
compatibleExtraParams);
}
else
for (LongType i1 = 0; i1 < xAxis1; ++i1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i4 = 0; i4 < xAxis4; ++i4) {
#if defined(PRINT_INDICES)
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec51\n", i0,i1,i2,i3,i4,i1 * xStrd1 + i2 * xStrd2 + i3 * xStrd3 + i4 * xStrd4);
#endif
s = OpType::update(
s, OpType::op(x0[i1 * xStrd1 + i2 * xStrd2 + i3 * xStrd3 + i4 * xStrd4], compatibleExtraParams), compatibleExtraParams);
}
*z0 = OpType::postProcess(s, tadLen, compatibleExtraParams);
}
};
samediff::Threads::parallel_for(func, 0, xAxis0);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceExec52(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[1]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[1]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(0) : static_cast<LongType>(1));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[1] : dims[0]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[1] : dims[0]);
const LongType zStrd1 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(1) : static_cast<LongType>(0));
const LongType xAxis2 = shape::sizeAt(xShapeInfo, dims[2]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, dims[2]);
const LongType xAxis3 = shape::sizeAt(xShapeInfo, dims[3]);
const LongType xStrd3 = shape::strideAt(xShapeInfo, dims[3]);
const LongType xAxis4 = shape::sizeAt(xShapeInfo, dims[4]);
const LongType xStrd4 = shape::strideAt(xShapeInfo, dims[4]);
const LongType tadLen = static_cast<LongType>(xAxis2 * xAxis3 * xAxis4);
LongType xRank = shape::rank(xShapeInfo);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR_2D {
for (auto i0 = start_x; i0 < stop_x; ++i0) {
for (auto i1 = start_y; i1 < stop_y; ++i1) {
auto x1 = x + i0 * xStrd0 + i1 * xStrd1;
auto z1 = z + i0 * zStrd0 + i1 * zStrd1;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x1));
if (xStrd2 == 1)
for (LongType i4 = 0; i4 < xAxis4; ++i4)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i2 = 0; i2 < xAxis2; ++i2) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec52\n", i0,i1,i2,i3,i4,i2 + i3 * xStrd3 + i4 * xStrd4);
#endif
s = OpType::update(s, OpType::op(x1[i2 + i3 * xStrd3 + i4 * xStrd4], compatibleExtraParams), compatibleExtraParams);
}
else if (xStrd3 == 1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i4 = 0; i4 < xAxis4; ++i4)
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec52\n", i0,i1,i2,i3,i4,i2 + i3 * xStrd3 + i4 * xStrd4);
#endif
s = OpType::update(s, OpType::op(x1[i2 * xStrd2 + i3 + i4 * xStrd4], compatibleExtraParams), compatibleExtraParams);
}
else if (xStrd4 == 1)
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i4 = 0; i4 < xAxis4; ++i4) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec52\n", i0,i1,i2,i3,i4,i2 * xStrd2 + i3 + i4 * xStrd4);
#endif
s = OpType::update(s, OpType::op(x1[i2 * xStrd2 + i3 * xStrd3 + i4], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i2 = 0; i2 < xAxis2; ++i2)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i4 = 0; i4 < xAxis4; ++i4) {
#if defined(PRINT_INDICES)
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec52\n", i0,i1,i2,i3,i4,i2 * xStrd2 + i3 * xStrd3 + i4 * xStrd4);
#endif
s = OpType::update(s, OpType::op(x1[i2 * xStrd2 + i3 * xStrd3 + i4 * xStrd4], compatibleExtraParams),
compatibleExtraParams);
}
*z1 = OpType::postProcess(s, tadLen, compatibleExtraParams);
}
}
};
samediff::Threads::parallel_for(func, 0, xAxis0, 1, 0, xAxis1, 1);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceExec53(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[2]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[2]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(0) : static_cast<LongType>(2));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, dims[1]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, dims[1]);
const LongType zStrd1 = shape::strideAt(zShapeInfo, static_cast<LongType>(1));
const LongType xAxis2 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[2] : dims[0]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[2] : dims[0]);
const LongType zStrd2 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(2) : static_cast<LongType>(0));
const LongType xAxis3 = shape::sizeAt(xShapeInfo, dims[3]);
const LongType xStrd3 = shape::strideAt(xShapeInfo, dims[3]);
const LongType xAxis4 = shape::sizeAt(xShapeInfo, dims[4]);
const LongType xStrd4 = shape::strideAt(xShapeInfo, dims[4]);
const LongType tadLen = static_cast<LongType>(xAxis3 * xAxis4);
LongType xRank = shape::rank(xShapeInfo);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR_3D {
for (auto i0 = start_x; i0 < stop_x; ++i0) {
for (auto i1 = start_y; i1 < stop_y; ++i1) {
for (auto i2 = start_z; i2 < stop_z; ++i2) {
auto x2 = x + i0 * xStrd0 + i1 * xStrd1 + i2 * xStrd2;
auto z2 = z + i0 * zStrd0 + i1 * zStrd1 + i2 * zStrd2;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x2));
if (xStrd3 == 1)
for (LongType i4 = 0; i4 < xAxis4; ++i4)
for (LongType i3 = 0; i3 < xAxis3; ++i3) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec53\n", i0,i1,i2,i3,i4,i3 + i4 * xStrd4);
#endif
s = OpType::update(s, OpType::op(x2[i3 + i4 * xStrd4], compatibleExtraParams), compatibleExtraParams);
}
else if (xStrd4 == 1)
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i4 = 0; i4 < xAxis4; ++i4) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec53\n", i0,i1,i2,i3,i4,i3 * xStrd3 + i4);
#endif
s = OpType::update(s, OpType::op(x2[i3 * xStrd3 + i4], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i3 = 0; i3 < xAxis3; ++i3)
for (LongType i4 = 0; i4 < xAxis4; ++i4) {
#if defined(PRINT_INDICES)
printf("Index i0,i1,i2,i3,i4 is %lld,%lld,%lld,%lld,%lld offset %lld reduceExec53\n", i0,i1,i2,i3,i4,i3 * xStrd3 + i4 * xStrd4);
#endif
s = OpType::update(s, OpType::op(x2[i3 * xStrd3 + i4 * xStrd4], compatibleExtraParams), compatibleExtraParams);
}
*z2 = OpType::postProcess(s, tadLen, compatibleExtraParams);
}
}
}
};
samediff::Threads::parallel_for(func, 0, xAxis0, 1, 0, xAxis1, 1, 0, xAxis2, 1);
}
//////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceExec54(const X* x, const LongType* xShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* dims, E* extraParams) {
const LongType xAxis0 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[3]);
const LongType xStrd0 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[0] : dims[3]);
const LongType zStrd0 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(0) : static_cast<LongType>(3));
const LongType xAxis1 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[1] : dims[2]);
const LongType xStrd1 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[1] : dims[2]);
const LongType zStrd1 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(1) : static_cast<LongType>(2));
const LongType xAxis2 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[2] : dims[1]);
const LongType xStrd2 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[2] : dims[1]);
const LongType zStrd2 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(2) : static_cast<LongType>(1));
const LongType xAxis3 = shape::sizeAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[3] : dims[0]);
const LongType xStrd3 = shape::strideAt(xShapeInfo, shape::order(zShapeInfo) == 'c' ? dims[3] : dims[0]);
const LongType zStrd3 = shape::strideAt(zShapeInfo, shape::order(zShapeInfo) == 'c' ? static_cast<LongType>(3) : static_cast<LongType>(0));
const LongType xAxis4 = shape::sizeAt(xShapeInfo, dims[4]);
const LongType xStrd4 = shape::strideAt(xShapeInfo, dims[4]);
LongType xRank = shape::rank(xShapeInfo);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR_3D {
for (auto i0 = start_x; i0 < stop_x; ++i0) {
for (auto i1 = start_y; i1 < stop_y; ++i1) {
for (auto i2 = start_z; i2 < stop_z; ++i2) {
for (auto i3 = 0; i3 < xAxis3; ++i3) {
auto x3 = x + i0 * xStrd0 + i1 * xStrd1 + i2 * xStrd2 + i3 * xStrd3;
auto z3 = z + i0 * zStrd0 + i1 * zStrd1 + i2 * zStrd2 + i3 * zStrd3;
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(x3));
if (xStrd4 == 1)
for (LongType i4 = 0; i4 < xAxis4; ++i4) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
#endif
s = OpType::update(s, OpType::op(x3[i4], compatibleExtraParams), compatibleExtraParams);
}
else
for (LongType i4 = 0; i4 < xAxis4; ++i4) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(xShapeInfo);
shape::printShapeInfo(zShapeInfo);
#endif
s = OpType::update(s, OpType::op(x3[i4 * xStrd4], compatibleExtraParams), compatibleExtraParams);
}
*z3 = OpType::postProcess(s, static_cast<LongType>(xAxis4), compatibleExtraParams);
}
}
}
}
};
samediff::Threads::parallel_for(func, 0, xAxis0, 1, 0, xAxis1, 1, 0, xAxis2, 1);
}
////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E, typename OpType>
SD_LIB_HIDDEN void reduceDefault(memory::Workspace* workspace, const X* x, const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims, E* extraParams) {
const int zRank = shape::rank(zShapeInfo);
const int tadRank = shape::rank(xShapeInfo) - zRank;
LongType* outerXTadShapeInfo = ShapeBuilders::createSubArrShapeInfo(xShapeInfo, dims, zRank);
LongType* innerXTadShapeInfo = ShapeBuilders::createSubArrShapeInfo(xShapeInfo, dims + zRank, tadRank);
const bool sameOffsets1 = shape::haveSameShapeAndStrides(zShapeInfo, outerXTadShapeInfo);
const bool sameOffsets2 = shape::haveSameShapeAndStrides(zShapeInfo, innerXTadShapeInfo);
const LongType zLen = shape::length(zShapeInfo);
const LongType tadLen = shape::length(innerXTadShapeInfo);
LongType* zOffsets = nullptr;
ALLOCATE(zOffsets, workspace, zLen, sd::LongType);
shape::calcOffsets(zShapeInfo, zOffsets);
LongType* outerXTadOffsets = zOffsets;
if (!sameOffsets1) {
ALLOCATE(outerXTadOffsets, workspace, zLen, sd::LongType);
shape::calcOffsets(outerXTadShapeInfo, outerXTadOffsets);
}
LongType* innerXTadOffsets = zOffsets;
if (!sameOffsets2) {
ALLOCATE(innerXTadOffsets, workspace, tadLen, sd::LongType);
shape::calcOffsets(innerXTadShapeInfo, innerXTadOffsets);
}
LongType xRank = shape::rank(xShapeInfo);
Z convertedParams[8] = {0};
Z* compatibleExtraParams = nullptr;
if (extraParams != nullptr) {
if constexpr (std::is_same_v<E, Z>) {
compatibleExtraParams = reinterpret_cast<Z*>(extraParams);
} else {
for (int i = 0; i < 8; ++i) {
convertedParams[i] = static_cast<Z>(extraParams[i]);
}
compatibleExtraParams = convertedParams;
}
}
auto func = PRAGMA_THREADS_FOR {
for (auto i = start; i < stop; ++i) {
const auto tad = x + outerXTadOffsets[i];
auto s = static_cast<typename OpType::InterType>(OpType::startingValue(tad));
for (LongType j = 0; j < tadLen; j++) {
#if defined(PRINT_INDICES)
shape::printShapeInfo(outerXTadShapeInfo);
shape::printShapeInfo(innerXTadShapeInfo);
printf("Index i,j is %lld,%lld offset %lld reduceDefault\n", i,j,innerXTadOffsets[j]);
#endif
s = OpType::update(s, OpType::op(tad[innerXTadOffsets[j]], compatibleExtraParams), compatibleExtraParams);
}
z[zOffsets[i]] = OpType::postProcess(s, tadLen, compatibleExtraParams);
}
};
samediff::Threads::parallel_for(func, 0, shape::length(zShapeInfo));
RELEASE(outerXTadShapeInfo, workspace);
RELEASE(innerXTadShapeInfo, workspace);
RELEASE(zOffsets, workspace);
if (!sameOffsets1) RELEASE(outerXTadOffsets, workspace);
if (!sameOffsets2) RELEASE(innerXTadOffsets, workspace);
}
//////////////////////////////////////////////////////////////////////////////
template <typename X, typename Z, typename E>
template <typename OpType>
SD_LIB_HIDDEN void ReductionLoops<X, Z, E>::loopReduce(memory::Workspace* workspace, const X* x,
const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo, const LongType* dims,
E* extraParams) {
const LongType xRank = shape::rank(xShapeInfo);
const LongType zRank = shape::rank(zShapeInfo);
if (xRank == 2 && zRank == 1)
reduceExec21<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 3 && zRank == 1)
reduceExec31<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 3 && zRank == 2)
reduceExec32<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 4 && zRank == 1)
reduceExec41<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 4 && zRank == 2)
reduceExec42<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 4 && zRank == 3)
reduceExec43<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 5 && zRank == 1)
reduceExec51<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 5 && zRank == 2)
reduceExec52<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 5 && zRank == 3)
reduceExec53<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else if (xRank == 5 && zRank == 4)
reduceExec54<X, Z, E, OpType>(x, xShapeInfo, z, zShapeInfo, dims, extraParams);
else
reduceDefault<X, Z, E, OpType>(workspace, x, xShapeInfo, z, zShapeInfo, dims, extraParams);
}
template <typename X, typename Z, typename E>
template <typename OpType>
SD_LIB_HIDDEN void TransformLoops<X, Z, E>::loopTransform(const X* x,
const LongType* xShapeInfo, Z* z,
const LongType* zShapeInfo,
E* extraParams,
LongType threadId, LongType numThreads) {
// Basic validation
if(xShapeInfo == nullptr) {
THROW_EXCEPTION("TransformLoops::loopTransform: Input x shape info was null!");
}
if(zShapeInfo == nullptr) {
THROW_EXCEPTION("TransformLoops::loopTransform: Input z shape info was null!");
}
if(x == nullptr) {
THROW_EXCEPTION("TransformLoops::loopTransform: Input x buffer was null!");
}
if(z == nullptr) {
THROW_EXCEPTION("TransformLoops::loopTransform: Output z buffer was null!");
}
if(xShapeInfo[0] > SD_MAX_RANK || xShapeInfo[0] < 0) {
THROW_EXCEPTION("TransformLoops::loopTransform: x shape info appears to be corrupt (invalid rank).");
}
if(zShapeInfo[0] > SD_MAX_RANK || zShapeInfo[0] < 0) {
THROW_EXCEPTION("TransformLoops::loopTransform: z shape info appears to be corrupt (invalid rank).");
}
// Get basic shape information
const LongType zLen = shape::length(zShapeInfo);
const LongType xLen = shape::length(xShapeInfo);
const LongType xRank = shape::rank(xShapeInfo);
const LongType zRank = shape::rank(zShapeInfo);
// For element-wise transforms (like Assign), input and output lengths must match
// This validation catches mismatched TAD shapes that could cause out-of-bounds access
if (xLen != zLen) {
std::string error = "TransformLoops::loopTransform: input length ";
error += std::to_string(xLen);
error += " != output length ";
error += std::to_string(zLen);
error += ". This indicates a shape mismatch between input and output arrays.";
THROW_EXCEPTION(error.c_str());
}
const LongType* xShape = shape::shapeOf(const_cast<LongType*>(xShapeInfo));
const LongType* zShape = shape::shapeOf(const_cast<LongType*>(zShapeInfo));
const LongType* xStride = shape::stride(const_cast<LongType*>(xShapeInfo));
const LongType* zStride = shape::stride(const_cast<LongType*>(zShapeInfo));
// Determine thread work span
auto span = samediff::Span::build(threadId, numThreads, 0, zLen, 1);
// Process each element
for (auto i = span.startX(); i < span.stopX(); i++) {
// Calculate coordinates and offsets
LongType xCoords[SD_MAX_RANK];
LongType zCoords[SD_MAX_RANK];
INDEX2COORDS(i, xRank, xShape, xCoords);
INDEX2COORDS(i, zRank, zShape, zCoords);
LongType xOffset;
LongType zOffset;
COORDS2INDEX(xRank, xStride, xCoords, xOffset);
COORDS2INDEX(zRank, zStride, zCoords, zOffset);
// Bounds checking for calculated offsets
// These checks prevent segfaults when TAD shapes don't match or offsets are miscalculated
if (xOffset < 0 || xOffset >= xLen) {
// Skip invalid offsets rather than crash - this can happen with malformed TADs
continue;
}
if (zOffset < 0 || zOffset >= zLen) {
// Skip invalid offsets rather than crash
continue;
}
// Simple heuristic based on operation patterns observed
Z result;
// For X -> bool transformations (any input type to bool output)
if constexpr (std::is_same_v<Z, bool>) {
// Operations that expect X* (input type pointer)
constexpr bool expects_x_ptr =
std::is_same_v<OpType, simdOps::IsInf<X, Z>> ||
std::is_same_v<OpType, simdOps::IsNan<X, Z>> ||
std::is_same_v<OpType, simdOps::MatchConditionBool<X, Z>> ||
std::is_same_v<OpType, simdOps::IsPositive<X, Z>> ||
std::is_same_v<OpType, simdOps::Not<X, Z>> ||
std::is_same_v<OpType, simdOps::IsNegative<X, Z>> ||
std::is_same_v<OpType, simdOps::Assign<X, Z>>;
if constexpr (expects_x_ptr) {
result = OpType::op(x[xOffset], static_cast<X*>(nullptr));
} else {
// Operations that expect Z* (bool*): IsFinite, IsInfOrNan, etc.
result = OpType::op(x[xOffset], static_cast<Z*>(nullptr));
}
}
// For same-type transformations, use input type
else if constexpr (std::is_same_v<X, Z>) {
result = OpType::op(x[xOffset], static_cast<X*>(nullptr));
}
// Default: try with extraParams if types match, otherwise check for operations that expect Z*
else {
// Operations that typically expect Z* (output type pointer)
constexpr bool expects_z_ptr =
std::is_same_v<OpType, simdOps::Sqrt<X, Z>> ||
std::is_same_v<OpType, simdOps::RSqrt<X, Z>>; // Added RSqrt here
if constexpr (expects_z_ptr) {
result = OpType::op(x[xOffset], static_cast<Z*>(nullptr));
} else if constexpr (std::is_same_v<E, X>) {
result = OpType::op(x[xOffset], extraParams);
} else {
result = OpType::op(x[xOffset], static_cast<X*>(nullptr));
}
}
z[zOffset] = result;
}
}
//////////////////////////////////////////////////////////////////////////////
template <typename X, typename Z>
template <typename OpType>
void Reduction3Loops<X, Z>::loopReduce3(const X* x, const LongType* xShapeInfo, const X* y,
const LongType* yShapeInfo, Z* z, const LongType* zShapeInfo,
LongType* dims, int dimsLen, Z* extraParameters, int64_t start, int64_t stop) {
// both tads have same shape, however strides and ews may differ
Z param0(OpType::startingValue(x)), param1(OpType::startingValue(x)),
param2(extraParameters ? extraParameters[0] : OpType::startingValue(x));
const LongType xLen = shape::length(xShapeInfo);
const LongType yLen = shape::length(yShapeInfo);
const LongType *xTadShapeInfo = nullptr, *yTadShapeInfo = nullptr, *xTadOffsets = nullptr, *yTadOffsets = nullptr;
std::shared_ptr<TadPack> tadPackX, tadPackY;
std::vector<LongType> zeroOffsets;
if (xLen == yLen) {
tadPackX = ConstantTadHelper::getInstance().tadForDimensions(const_cast<sd::LongType*>(xShapeInfo), dims, dimsLen);
tadPackY = ConstantTadHelper::getInstance().tadForDimensions(const_cast<sd::LongType*>(yShapeInfo), dims, dimsLen);
xTadShapeInfo = tadPackX->primaryShapeInfo();
yTadShapeInfo = tadPackY->primaryShapeInfo();
xTadOffsets = tadPackX->primaryOffsets();
yTadOffsets = tadPackY->primaryOffsets();
} else if (yLen > xLen) {
tadPackY = ConstantTadHelper::getInstance().tadForDimensions(const_cast<sd::LongType*>(yShapeInfo), dims, dimsLen);
xTadShapeInfo = xShapeInfo;
yTadShapeInfo = tadPackY->primaryShapeInfo();
yTadOffsets = tadPackY->primaryOffsets();
} else {
tadPackX = ConstantTadHelper::getInstance().tadForDimensions(const_cast<sd::LongType*>(xShapeInfo), dims, dimsLen);
yTadShapeInfo = yShapeInfo;
xTadShapeInfo = tadPackX->primaryShapeInfo();
xTadOffsets = tadPackX->primaryOffsets();
}
const auto zLen = shape::length(zShapeInfo);
const auto tadLen = shape::length(xTadShapeInfo);
const auto tadShape = shape::shapeOf(xTadShapeInfo);
const auto xTadStride = shape::stride(xTadShapeInfo);
const auto yTadStride = shape::stride(xTadShapeInfo);
int numThreads = OmpLaunchHelper::tadThreads(tadLen, zLen);
LongType castXTadShapeInfo[SD_MAX_RANK];
const bool canCastXTad = DataTypeUtils::castShapeInfo<LongType>(xTadShapeInfo, castXTadShapeInfo);
LongType castYTadShapeInfo[SD_MAX_RANK];
const bool canCastYTad = DataTypeUtils::castShapeInfo<LongType>(yTadShapeInfo, castYTadShapeInfo);
sd::LongType zRank = shape::rank(zShapeInfo);
sd::LongType *zShape = shape::shapeOf(zShapeInfo);
sd::LongType *zStride = shape::stride(zShapeInfo);
Z extraParams[3];
for (auto i = start; i < stop; i++) {
extraParams[0] = param0;
extraParams[1] = param1;
extraParams[2] = param2;
const auto xTad = xTadOffsets ? x + xTadOffsets[i] : x;
const auto yTad = yTadOffsets ? y + yTadOffsets[i] : y;
auto s = OpType::startingValue(xTad);
// Calculate z coordinates for this iteration
LongType zCoords[SD_MAX_RANK];
INDEX2COORDS(i,zRank, zShape, zCoords);
LongType zOffset;
COORDS2INDEX(zRank, zStride, zCoords, zOffset);
sd::LongType xTadRank = shape::rank(xTadShapeInfo);
sd::LongType yTadRank = shape::rank(yTadShapeInfo);
sd::LongType *xTadShape = shape::shapeOf(xTadShapeInfo);
sd::LongType *yTadShape = shape::shapeOf(yTadShapeInfo);
for (LongType j = 0; j < tadLen; ++j) {
LongType coords[SD_MAX_RANK];
LongType yCoords[SD_MAX_RANK];
INDEX2COORDS(j, xTadRank, xTadShape, coords);
INDEX2COORDS(j, yTadRank,yTadShape, yCoords);
LongType xTadOffset, yTadOffset;
COORDS2INDEX(xTadRank, xTadStride, coords, xTadOffset);
COORDS2INDEX(yTadRank,yTadStride, yCoords, yTadOffset);
#if defined(PRINT_INDICES)
shape::printShapeInfo(xTadShapeInfo);
shape::printShapeInfo(yTadShapeInfo);
#endif
s = OpType::update(s, OpType::op(xTad[xTadOffset], yTad[yTadOffset], extraParams), extraParams);
}
z[zOffset] = OpType::postProcess(s, tadLen, extraParams);
};
}
//////////////////////////////////////////////////////////////////////////////
template <typename X, typename Z>
template <typename OpType>
void Reduction3Loops<X, Z>::loopReduce3All(const X* x, const LongType* xShapeInfo, const X* y,
const LongType* yShapeInfo, Z* z, const LongType* zShapeInfo,
const LongType* xTadShapeInfo, const LongType* xTadOffsets,
const LongType* yTadShapeInfo, const LongType* yTadOffsets,
Z* extraParameters, int64_t start, int64_t stop) {
// both tads have same shape, however strides and ews may differ
Z param0(OpType::startingValue(x)), param1(OpType::startingValue(x)),
param2(extraParameters ? extraParameters[0] : OpType::startingValue(x));
const auto zLen = shape::length(zShapeInfo);
const auto tadLen = shape::length(xTadShapeInfo);
const auto numXTads = shape::length(xShapeInfo) / tadLen;
const auto numYTads = shape::length(yShapeInfo) / tadLen;
const auto tadShape = shape::shapeOf(xTadShapeInfo);
const auto xTadStride = shape::stride(xTadShapeInfo);
const auto yTadStride = shape::stride(yTadShapeInfo);
const auto startVal = OpType::startingValue(x);
int numThreads = OmpLaunchHelper::tadThreads(tadLen, numXTads * numYTads);
//*********************************************//
LongType castXTadShapeInfo[SD_MAX_RANK];
LongType castYTadShapeInfo[SD_MAX_RANK];
const bool canCastYTad = DataTypeUtils::castShapeInfo<LongType>(yTadShapeInfo, castYTadShapeInfo);
Z extraParams[3];
sd::LongType *xTadShape = shape::shapeOf(xTadShapeInfo);
sd::LongType *yTadShape = shape::shapeOf(yTadShapeInfo);
sd::LongType xTadRank = shape::rank(xTadShapeInfo);
sd::LongType zRank = shape::rank(zShapeInfo);
sd::LongType *zShape = shape::shapeOf(zShapeInfo);
sd::LongType *zStride = shape::stride(zShapeInfo);
sd::LongType yTadRank = shape::rank(yTadShapeInfo);
for (LongType ix = 0; ix < numXTads; ix++) {
for (LongType iy = 0; iy < numYTads; iy++) {
extraParams[0] = param0;
extraParams[1] = param1;
extraParams[2] = param2;
const auto xTad = x + xTadOffsets[ix];
const auto yTad = y + yTadOffsets[iy];
auto s = startVal;
for (LongType j = 0; j < tadLen; ++j) {
LongType coords[SD_MAX_RANK];
INDEX2COORDS(j, xTadRank, xTadShape, coords);
LongType xTadOffset, yTadOffset;
COORDS2INDEX(xTadRank, xTadStride, coords, xTadOffset);
COORDS2INDEX(yTadRank, yTadStride, coords, yTadOffset);
#if defined(PRINT_INDICES)
shape::printShapeInfo(xTadShapeInfo);
shape::printShapeInfo(yTadShapeInfo);
printf("Index is %lld offset is %lld loop kind: default Reduction3Loops<X, Z>::loopReduce3All\n", ix * numYTads + iy, j);
#endif
s = OpType::update(s, OpType::op(xTad[xTadOffset], yTad[yTadOffset], extraParams), extraParams);
}
z[ix * numYTads + iy] = OpType::postProcess(s, tadLen, extraParams);
}
}
}
} // namespace sd
// Include implementation for ReductionLongLoops to make innerloopReduce visible for inlining
#ifdef SD_LOOPS_INLINED
#include <helpers/cpu/loops/ReductionLoops_long.cpp>
#endif
#endif // LIBND4J_LOOPS_H