/* ****************************************************************************** * * * 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 raver119@gmail.com, created on 07.10.2017. // @author Yurii Shyrma (iuriish@yahoo.com) // #include #include #include #include #include #include #include namespace sd { template void SpecialTypeConverter::convertGeneric(sd::Pointer *extras, void *dx, sd::LongType N, void *dz) { auto x = reinterpret_cast(dx); auto z = reinterpret_cast(dz); auto func = PRAGMA_THREADS_FOR { for (auto i = start; i < stop; i++) { z[i] = static_cast(x[i]); } }; samediff::Threads::parallel_for(func, 0, N); }; template void quickSort_parallel_internal_key(X *key, sd::LongType const *xShapeInfo, Y *values, sd::LongType const *yShapeInfo, LongType left, LongType right, LongType cutoff, bool descending) { sd::LongType i = left, j = right; X ktmp; LongType pivotCoords[] = {(left + right) / 2}; LongType pivotIndex; COORDS2INDEX(1, shape::stride(xShapeInfo), pivotCoords, pivotIndex); X pivot = key[pivotIndex]; Y vtmp; { /* PARTITION PART */ while (i <= j) { if (descending) { LongType iIndex, jIndex; LongType iCoords[] = {i}; LongType jCoords[] = {j}; COORDS2INDEX(1, shape::stride(xShapeInfo), iCoords, iIndex); COORDS2INDEX(1, shape::stride(xShapeInfo), jCoords, jIndex); while (key[iIndex] > pivot) { i++; COORDS2INDEX(1, shape::stride(xShapeInfo), iCoords, iIndex); } while (key[jIndex] < pivot) { j--; COORDS2INDEX(1, shape::stride(xShapeInfo), jCoords, jIndex); } if (i <= j) { ktmp = key[iIndex]; key[iIndex] = key[jIndex]; key[jIndex] = ktmp; LongType iValueIndex, jValueIndex; COORDS2INDEX(1, shape::stride(yShapeInfo), iCoords, iValueIndex); COORDS2INDEX(1, shape::stride(yShapeInfo), jCoords, jValueIndex); vtmp = values[iValueIndex]; values[iValueIndex] = values[jValueIndex]; values[jValueIndex] = vtmp; i++; j--; } } else { LongType iIndex, jIndex; LongType iCoords[] = {i}; LongType jCoords[] = {j}; COORDS2INDEX(1, shape::stride(xShapeInfo), iCoords, iIndex); COORDS2INDEX(1, shape::stride(xShapeInfo), jCoords, jIndex); while (key[iIndex] < pivot) { i++; COORDS2INDEX(1, shape::stride(xShapeInfo), iCoords, iIndex); } while (key[jIndex] > pivot) { j--; COORDS2INDEX(1, shape::stride(xShapeInfo), jCoords, jIndex); } if (i <= j) { ktmp = key[iIndex]; key[iIndex] = key[jIndex]; key[jIndex] = ktmp; LongType iValueIndex, jValueIndex; COORDS2INDEX(1, shape::stride(yShapeInfo), iCoords, iValueIndex); COORDS2INDEX(1, shape::stride(yShapeInfo), jCoords, jValueIndex); vtmp = values[iValueIndex]; values[iValueIndex] = values[jValueIndex]; values[jValueIndex] = vtmp; i++; j--; } } } } if (((right - left) < cutoff)) { if (left < j) { quickSort_parallel_internal_key(key, xShapeInfo, values, yShapeInfo, left, j, cutoff, descending); } if (i < right) { quickSort_parallel_internal_key(key, xShapeInfo, values, yShapeInfo, i, right, cutoff, descending); } } else { PRAGMA_OMP_TASK { quickSort_parallel_internal_key(key, xShapeInfo, values, yShapeInfo, left, j, cutoff, descending); } PRAGMA_OMP_TASK { quickSort_parallel_internal_key(key, xShapeInfo, values, yShapeInfo, i, right, cutoff, descending); } } } template void quickSort_parallel_internal_value(X *key, sd::LongType const *xShapeInfo, Y *value, sd::LongType const *yShapeInfo, LongType left, LongType right, LongType cutoff, bool descending) { sd::LongType i = left, j = right; X ktmp; LongType pivotCoords[] = {(left + right) / 2}; LongType pivotIndex; COORDS2INDEX(1, shape::stride(yShapeInfo), pivotCoords, pivotIndex); Y pivot = value[pivotIndex]; Y vtmp; { /* PARTITION PART */ while (i <= j) { if (descending) { LongType iIndex, jIndex; LongType iCoords[] = {i}; LongType jCoords[] = {j}; COORDS2INDEX(1, shape::stride(yShapeInfo), iCoords, iIndex); COORDS2INDEX(1, shape::stride(yShapeInfo), jCoords, jIndex); while (value[iIndex] > pivot) { i++; COORDS2INDEX(1, shape::stride(yShapeInfo), iCoords, iIndex); } while (value[jIndex] < pivot) { j--; COORDS2INDEX(1, shape::stride(yShapeInfo), jCoords, jIndex); } if (i <= j) { LongType iKeyIndex, jKeyIndex; COORDS2INDEX(1, shape::stride(xShapeInfo), iCoords, iKeyIndex); COORDS2INDEX(1, shape::stride(xShapeInfo), jCoords, jKeyIndex); ktmp = key[iKeyIndex]; key[iKeyIndex] = key[jKeyIndex]; key[jKeyIndex] = ktmp; vtmp = value[iIndex]; value[iIndex] = value[jIndex]; value[jIndex] = vtmp; i++; j--; } } else { LongType iIndex, jIndex; LongType iCoords[] = {i}; LongType jCoords[] = {j}; COORDS2INDEX(1, shape::stride(yShapeInfo), iCoords, iIndex); COORDS2INDEX(1, shape::stride(yShapeInfo), jCoords, jIndex); while (value[iIndex] < pivot) { i++; COORDS2INDEX(1, shape::stride(yShapeInfo), iCoords, iIndex); } while (value[jIndex] > pivot) { j--; COORDS2INDEX(1, shape::stride(yShapeInfo), jCoords, jIndex); } if (i <= j) { LongType iKeyIndex, jKeyIndex; COORDS2INDEX(1, shape::stride(xShapeInfo), iCoords, iKeyIndex); COORDS2INDEX(1, shape::stride(xShapeInfo), jCoords, jKeyIndex); ktmp = key[iKeyIndex]; key[iKeyIndex] = key[jKeyIndex]; key[jKeyIndex] = ktmp; vtmp = value[iIndex]; value[iIndex] = value[jIndex]; value[jIndex] = vtmp; i++; j--; } } } } if (((right - left) < cutoff)) { if (left < j) { quickSort_parallel_internal_value(key, xShapeInfo, value, yShapeInfo, left, j, cutoff, descending); } if (i < right) { quickSort_parallel_internal_value(key, xShapeInfo, value, yShapeInfo, i, right, cutoff, descending); } } else { PRAGMA_OMP_TASK { quickSort_parallel_internal_value(key, xShapeInfo, value, yShapeInfo, left, j, cutoff, descending); } PRAGMA_OMP_TASK { quickSort_parallel_internal_value(key, xShapeInfo, value, yShapeInfo, i, right, cutoff, descending); } } } template static void quickSort_parallel_key(NDArray *x, NDArray *y, sd::LongType lenArray, int numThreads, bool descending) { auto array = reinterpret_cast(x->bufferAsT()); auto values = reinterpret_cast(y->bufferAsT()); int cutoff = 1000; PRAGMA_OMP_PARALLEL_THREADS(numThreads) { PRAGMA_OMP_SINGLE_ARGS(nowait) { quickSort_parallel_internal_key(array, x->shapeInfo(), values, y->shapeInfo(), 0, lenArray - 1, cutoff, descending); } } } template static void quickSort_parallel_value(NDArray *x, NDArray *y, sd::LongType lenArray, int numThreads, bool descending) { auto array = reinterpret_cast(x->bufferAsT()); auto values = reinterpret_cast(y->bufferAsT()); int cutoff = 1000; PRAGMA_OMP_PARALLEL_THREADS(numThreads) { PRAGMA_OMP_SINGLE_ARGS(nowait) { quickSort_parallel_internal_value(array, x->shapeInfo(), values,y->shapeInfo(), 0, lenArray - 1, cutoff, descending); } } } template void DoubleMethods::sortByKey(NDArray *x,NDArray *y, bool descending) { quickSort_parallel_key(x,y, x->lengthOf(),Environment::getInstance().maxMasterThreads(), descending); } template void DoubleMethods::sortByValue(NDArray *x,NDArray *y, bool descending) { quickSort_parallel_value(x,y,x->lengthOf(),Environment::getInstance().maxMasterThreads(), descending); } template void DoubleMethods::sortTadByKey(NDArray *xArr,NDArray *yArr, NDArray *dimension, bool descending) { auto x = xArr->bufferAsT(); auto y = yArr->bufferAsT(); auto dimensionData = dimension->bufferAsT(); auto dimensionLength = dimension->lengthOf(); auto packX = ConstantTadHelper::getInstance().tadForDimensions(xArr->shapeInfo(), dimensionData, dimensionLength); auto packY = ConstantTadHelper::getInstance().tadForDimensions(yArr->shapeInfo(), dimensionData, dimensionLength); auto xLength = xArr->lengthOf(); auto xTadLength = shape::length(packX->primaryShapeInfo()); auto numTads = packX->numberOfTads(); auto func = PRAGMA_THREADS_FOR { for (auto r = start; r < stop; r++) { NDArray *xView = packX->extractTadView(xArr,r); NDArray *yView = packY->extractTadView(yArr,r); quickSort_parallel_key(xView, yView, xTadLength, 1, descending); delete xView; delete yView; } }; samediff::Threads::parallel_tad(func, 0, numTads); } template void DoubleMethods::sortTadByValue(NDArray *xArr, NDArray *yArr, NDArray *dimension, bool descending) { auto x = reinterpret_cast(xArr->bufferAsT()); auto y = reinterpret_cast(yArr->bufferAsT()); auto dimensionData = dimension->bufferAsT(); auto len = dimension->lengthOf(); auto packX = ConstantTadHelper::getInstance().tadForDimensions(xArr->shapeInfo(), dimensionData, len); auto packY = ConstantTadHelper::getInstance().tadForDimensions(yArr->shapeInfo(), dimensionData, len); auto xLength = xArr->lengthOf(); auto xTadLength = shape::length(packX->primaryShapeInfo()); auto numTads = packX->numberOfTads(); auto func = PRAGMA_THREADS_FOR { for (auto r = start; r < stop; r++) { NDArray *xView = packX->extractTadView(xArr,r); NDArray *yView = packY->extractTadView(yArr,r); quickSort_parallel_value(xView, yView, xTadLength, 1, descending); delete xView; delete yView; } }; samediff::Threads::parallel_tad(func, 0, numTads); } } // namespace sd