chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:47:05 +08:00
commit 4f3b7da785
7394 changed files with 2005594 additions and 0 deletions
@@ -0,0 +1,107 @@
/* ******************************************************************************
*
*
* 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 03.09.2018
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_broadcast_to)
#include <ops/declarable/headers/shape.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(broadcast_to, 2, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto shape = INPUT_VARIABLE(1);
auto output = OUTPUT_VARIABLE(0);
const int inputRank = input->rankOf();
const int shapeRank = shape->rankOf();
const LongType shapeLen = shape->lengthOf();
REQUIRE_TRUE(shapeRank <= 1, 0, "BROADCAST_TO op: rank of shape array should be <= 1, bot got %i instead !",
shapeRank);
REQUIRE_TRUE(inputRank <= shapeLen, 0,
"BROADCAST_TO op: rank of input shape array should be <= length of shape array, bot got %i and %i "
"correspondingly !",
inputRank, shapeLen);
std::vector<LongType> shapeBuff = shape->getBufferAsVector<LongType>();
std::vector<LongType> outShape(shapeBuff.begin(), shapeBuff.end());
for (int i = 1; i <= inputRank; ++i)
REQUIRE_TRUE(input->sizeAt(inputRank - i) == outShape[shapeLen - i] || input->sizeAt(inputRank - i) == 1, 0,
"BROADCAST_TO op: shape of input array %s can't be broadcasted to the shape %s !",
ShapeUtils::shapeAsString(input).c_str(), ShapeUtils::shapeAsString(outShape).c_str());
input->tile(*output);
return Status::OK;
}
DECLARE_TYPES(broadcast_to) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
//////////////////////////////////////////////////////////////////////////
DECLARE_SHAPE_FN(broadcast_to) {
auto inputShapeInfo = inputShape->at(0);
auto shape = INPUT_VARIABLE(1);
const LongType inputRank = inputShapeInfo[0];
const LongType shapeRank = shape->rankOf();
const LongType shapeLen = shape->lengthOf();
REQUIRE_TRUE(shapeRank <= 1, 0, "BROADCAST_TO op: rank of input shape array should be <= 1, bit got %i instead !",
shapeRank);
REQUIRE_TRUE(inputRank <= shapeLen, 0,
"BROADCAST_TO op: rank of input shape array should be <= length of shape array, bot got %i and %i "
"correspondingly !",
inputRank, shapeLen);
if(shape->isScalar()) {
std::vector<LongType> outShape;
outShape.reserve(1);
auto firstVal = shape->cast(INT64)->e<LongType>(0);
outShape[0] = firstVal;
ShapeDescriptor shapeDescriptor(ArrayOptions::dataType(inputShapeInfo), shape::order(inputShapeInfo), {firstVal});
auto outShapeInfo = ConstantShapeHelper::getInstance().createShapeInfo(&shapeDescriptor);
return SHAPELIST(outShapeInfo);
}
std::vector<LongType> shapeBuff = shape->getBufferAsVector<LongType>();
std::vector<LongType> outShape(shapeBuff.begin(), shapeBuff.end());
for (int i = 1; i <= inputRank; ++i)
REQUIRE_TRUE(inputShapeInfo[inputRank + 1 - i] == outShape[shapeLen - i] || inputShapeInfo[inputRank + 1 - i] == 1,
0, "BROADCAST_TO op: shape of input array %s can't be broadcasted to the shape %s !",
ShapeUtils::shapeAsString(inputShapeInfo).c_str(), ShapeUtils::shapeAsString(outShape).c_str());
auto outShapeInfo = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inputShapeInfo),
shape::order(inputShapeInfo), outShape);
return SHAPELIST(outShapeInfo);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,84 @@
/* ******************************************************************************
*
*
* 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
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_evaluate_reduction_shape)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(evaluate_reduction_shape, 2, 1, false, 0, 0) {
auto inputShape = INPUT_VARIABLE(0);
auto axis = INPUT_VARIABLE(1)->asVectorT<LongType>();
auto keepDims = block.numB() > 0 ? B_ARG(0) : false;
auto oldFormat = block.numB() > 1 ? B_ARG(1) : false;
auto output = OUTPUT_VARIABLE(0);
auto shape = inputShape->asVectorT<LongType>();
auto tempShapeInfo = ConstantShapeHelper::getInstance().createShapeInfo(INT64, 'c', shape);
auto tempReductionShapeInfo =
ShapeUtils::evalReduceShapeInfo('c', &axis, tempShapeInfo, keepDims, oldFormat, block.workspace());
REQUIRE_TRUE(output->lengthOf() == shape::rank(tempReductionShapeInfo), 0,
"evaluate_reduction_shape: output length should be %i, but got %i instead",
shape::rank(tempReductionShapeInfo), output->lengthOf());
for (int e = 0; e < shape::rank(tempReductionShapeInfo); e++) output->p(e, tempReductionShapeInfo[e + 1]);
return Status::OK;
}
DECLARE_TYPES(evaluate_reduction_shape) {
getOpDescriptor()
->setAllowedInputTypes(0, {ALL_INTS})
->setAllowedInputTypes(1, {ALL_INTS})
->setAllowedOutputTypes(0, INT64);
}
DECLARE_SHAPE_FN(evaluate_reduction_shape) {
auto input = INPUT_VARIABLE(0);
auto axis = INPUT_VARIABLE(1)->asVectorT<int>();
auto keepDims = block.numB() > 0 ? B_ARG(0) : false;
auto oldFormat = block.numB() > 1 ? B_ARG(1) : false;
LongType length = input->lengthOf();
if (keepDims) {
if (oldFormat) {
// for oldFormat we can't go below rank 2
length = sd::math::sd_max<int>(2, length);
}
} else {
length -= axis.size();
if (oldFormat) {
length = sd::math::sd_max<int>(2, length);
}
}
return SHAPELIST(ConstantShapeHelper::getInstance().vectorShapeInfo(length, sd::DataType::INT64));
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,100 @@
/* ******************************************************************************
*
*
* 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
******************************************************************************/
//
// Created by raver119 on 02.11.2017.
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_expand_dims)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(expand_dims, 1, 1, false, 0, -2) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
LongType axis = block.numI() > 0 ? INT_ARG(0) : INPUT_VARIABLE(1)->e<LongType>(0);
if (axis < 0) axis += input->rankOf() + 1;
if(!input->isEmpty() && !input->isScalar())
REQUIRE_TRUE(axis >= 0 && axis <= input->rankOf(), 0,
"ExpandDims: axis should be in range of 0...%i in this case, but got %i instead", input->rankOf() + 1,
axis);
//note we used to have a specific copy case here but we should
//be abstracting away data copy and reshape details like buffer copying
if(input->isEmpty()) {
return Status::OK;
}
NDArray::copyDataForAssign(input,output,output->shapeInfo(),true);
return Status::OK;
}
DECLARE_TYPES(expand_dims) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
DECLARE_SHAPE_FN(expand_dims) {
auto inShape = inputShape->at(0);
auto rank = shape::rank(inShape);
// 0D scalar edge case
if (shape::isScalar(inShape)) {
if(rank < 1) {
LongType x = 1;
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inShape), 'c', 1, &x, -1);
return SHAPELIST(newShape);
} else {
std::vector<LongType> x = {1, 1};
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inShape), 'c', 2, x.data(), -1);
return SHAPELIST(newShape);
}
}
auto input = INPUT_VARIABLE(0);
if(input->isEmpty() && input->rankOf() < 1) {
auto newShape = ConstantShapeHelper::getInstance().emptyShapeInfo(ArrayOptions::dataType(inShape));
return SHAPELIST(newShape);
}
auto x_rank = shape::rank(inShape);
char order = shape::order(inShape);
LongType axis = block.numI() > 0 ? INT_ARG(0) : INPUT_VARIABLE(1)->e<LongType>(0);
if (axis < 0) axis += x_rank + 1;
REQUIRE_TRUE(axis >= 0 && axis <= input->rankOf(), 0,
"ExpandDims: axis should be in range of 0...%i in this case, but got %i instead", input->rankOf() + 1,
axis);
std::vector<LongType> shape;
for (LongType e = 0; e < x_rank; e++) shape.emplace_back(shape::shapeOf(inShape)[e]);
shape.insert(shape.begin() + axis, 1);
auto newShape = input->isEmpty() ? ConstantShapeHelper::getInstance().emptyShapeInfoWithShape(ArrayOptions::dataType(inShape), shape) :
ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inShape), order, shape);
return SHAPELIST(newShape);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,70 @@
/* ******************************************************************************
*
*
* 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
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_)
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/flatten.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(flatten, -1, 1, false, 0, 1) {
auto output = OUTPUT_VARIABLE(0);
auto zType = output->dataType();
auto xType = INPUT_VARIABLE(0)->dataType();
REQUIRE_TRUE(xType == zType, 0, "Flatten: output array must have same data type as input arrays");
std::vector<NDArray*> arrays(block.width());
for (size_t e = 0; e < block.width(); e++) {
auto input = INPUT_VARIABLE(e);
REQUIRE_TRUE(xType == input->dataType(), 0, "Flatten: all input arrays must have the same data type");
arrays[e] = input;
}
char order = (char)INT_ARG(0);
helpers::flatten(block.launchContext(), arrays, output, order);
return Status::OK;
}
DECLARE_TYPES(flatten) {
getOpDescriptor()->setAllowedInputTypes({ALL_INTS, ALL_FLOATS, BOOL});
getOpDescriptor()->setAllowedOutputTypes(0, {ALL_FLOATS, ALL_INTS, BOOL});
}
DECLARE_SHAPE_FN(flatten) {
LongType length = 0;
DataType dtype = ArrayOptions::dataType(inputShape->at(0));
for (size_t e = 0; e < block.width(); e++) {
length += shape::length(inputShape->at(e));
REQUIRE_TRUE(dtype == ArrayOptions::dataType(inputShape->at(e)), 0,
"Flatten: all input arrays must have the same datatype");
}
return SHAPELIST(ConstantShapeHelper::getInstance().vectorShapeInfo(length, dtype));
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,92 @@
/* ******************************************************************************
*
*
* 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
******************************************************************************/
//
// Created by raver119 on 29/10/17.
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_flatten2d)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
// here iArgs is a vector with (optional) negative of order as first element:
// ({-order, dim1, dim2, dim3, ...})
CUSTOM_OP_IMPL(flatten_2d, 1, 1, false, 0, -2) {
auto x = INPUT_VARIABLE(0);
auto z = OUTPUT_VARIABLE(0);
// Special case: empty.reshape(<other empty shape>) -> return empty
if (x->isEmpty()) {
REQUIRE_TRUE(z->isEmpty(), 0, "Reshape: when input is empty, output must also be empty");
return Status::OK; // No op
}
REQUIRE_TRUE(x->lengthOf() == z->lengthOf(), 0,
"Reshape: lengths before and after reshape should match, but got %i vs %i", x->lengthOf(),
z->lengthOf());
auto* zShapeVec = z->getShapeAsVector();
if (Environment::getInstance().isDebugAndVerbose()) sd_printv("Reshape: new shape", *zShapeVec);
auto xReshaped = x->reshape(z->ordering(), *zShapeVec);
delete zShapeVec;
z->assign(xReshaped);
delete xReshaped;
return Status::OK;
}
DECLARE_TYPES(flatten_2d) {
getOpDescriptor()->setAllowedInputTypes(0, ANY)->setAllowedInputTypes(1, {ALL_INTS})->setSameMode(true);
}
DECLARE_SHAPE_FN(flatten_2d) {
const auto x = INPUT_VARIABLE(0);
const auto shape = x->shapeOf();
auto axis = INT_ARG(0);
if (axis < 0) {
axis += x->rankOf();
}
std::vector<int> reshapeArgs;
std::vector<LongType> shapeNew;
auto firstDim = 1;
auto lastDim = 1;
for (int i = 0; i < axis; i++) {
firstDim *= shape[i];
}
for (int i = axis; i < x->rankOf(); i++) {
lastDim *= shape[i];
}
shapeNew.push_back(firstDim);
shapeNew.push_back(lastDim);
auto len = shape::prodLong(shapeNew.data(), shapeNew.size());
REQUIRE_TRUE(x->lengthOf() == len, 0, "Reshape: lengths before and after reshape should match, but got %i vs %i",
x->lengthOf(), len);
return SHAPELIST(ConstantShapeHelper::getInstance().createShapeInfo(x->dataType(), x->ordering(), shapeNew));
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,55 @@
/* ******************************************************************************
*
*
* 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 Adam Gibson
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_broadcast_to)
#include <ops/declarable/headers/shape.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(linear_copy, 2, 1, false, 0, 0) {
auto output = OUTPUT_VARIABLE(0);
auto input = INPUT_VARIABLE(0);
DataBuffer::memcpy(output->dataBuffer(), input->dataBuffer(), 0, 0);
return Status::OK;
}
DECLARE_TYPES(linear_copy) { getOpDescriptor()->setAllowedInputTypes(ANY); }
//////////////////////////////////////////////////////////////////////////
DECLARE_SHAPE_FN(linear_copy) {
if(block.outputWidth() > 0)
return SHAPELIST(OUTPUT_VARIABLE(0)->shapeInfo());
auto input = INPUT_VARIABLE(0);
auto shape = INPUT_VARIABLE(1);
auto shapeBuilders = ShapeBuilders::createShapeInfo(input->dataType(),shape::order(input->shapeInfo()),shape->getBufferAsVector<sd::LongType>());
auto outShapeInfo = ConstantShapeHelper::getInstance().createFromExisting(shapeBuilders);
return SHAPELIST(outShapeInfo);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,55 @@
/* ******************************************************************************
*
*
* 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
******************************************************************************/
//
// Created by raver119 on 12.02.18.
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_order)
#include <ops/declarable/headers/shape.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(order, 1, 1, false, 0, 1) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
output->assign(input);
return Status::OK;
}
DECLARE_TYPES(order) {
getOpDescriptor()->setAllowedInputTypes(0, ANY)->setAllowedOutputTypes({ALL_INTS});
}
DECLARE_SHAPE_FN(order) {
auto input = inputShape->at(0);
auto isFOrder = INT_ARG(0) == 1;
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(
ArrayOptions::dataType(input), isFOrder ? 'f' : 'c', shape::rank(input), shape::shapeOf(input), -1);
return SHAPELIST(newShape);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,88 @@
/* ******************************************************************************
*
*
* 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
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_permute)
#include <helpers/ShapeUtils.h>
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
// here iArgs is int vector of ordered set of dimensions to be permuted
CUSTOM_OP_IMPL(permute, 1, 1, true, 0, -2) {
auto x = INPUT_VARIABLE(0);
auto z = OUTPUT_VARIABLE(0);
if (x->isEmpty()) {
REQUIRE_TRUE(z->isEmpty(), 0, "PERMUTE OP: when input is empty, output must also be empty");
return Status::OK; // No op
}
if (block.width() == 1 && block.getIArguments()->size() == 0) {
NDArray *t = x->transpose();
z->assign(t);
// FIXED: transpose() returns a view - only delete if not a view
if (t != nullptr && !t->isView()) {
delete t;
}
return Status::OK;
}
std::vector<LongType> permutationVector = block.width() > 1 ? INPUT_VARIABLE(1)->asVectorT<LongType>() : *block.getIArguments();
if(permutationVector.size() != static_cast<size_t>(x->rankOf())) {
sd_printf("PERMUTE OP: permutation vector size was %d and x input rank was %d\n",permutationVector.size(),x->rankOf());
}
REQUIRE_TRUE(permutationVector.size() == static_cast<size_t>(x->rankOf()),permutationVector.size(),"PERMUTE OP: number of permutations is less in size than input rank.");
z->assign(x->permute(permutationVector, false, false));
return Status::OK;
}
//////////////////////////////////////////////////////////////////////////
DECLARE_TYPES(permute) {
getOpDescriptor()->setAllowedInputTypes(0, ANY)->setAllowedInputTypes(1, {ALL_INTS})->setSameMode(true);
}
//////////////////////////////////////////////////////////////////////////
DECLARE_SHAPE_FN(permute) {
auto x = INPUT_VARIABLE(0);
if (block.width() == 1 && block.getIArguments()->size() == 0) {
auto ret = ShapeUtils::evalTransposeShapeInfo(*x, block.workspace(), true);
return SHAPELIST(ret);
}
std::vector<LongType> permutationVector = block.width() > 1 ? INPUT_VARIABLE(1)->asVectorT<LongType>() : *block.getIArguments();
auto outputShapeInfo =
ShapeUtils::evalPermShapeInfo(permutationVector.data(), x->rankOf(), x, block.workspace(), true);
return SHAPELIST(outputShapeInfo);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,52 @@
/* ******************************************************************************
*
*
* 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
******************************************************************************/
//
// Created by raver119 on 01.11.2017.
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_rank)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(rank, 1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
REQUIRE_TRUE(output->isScalar(), 0, "Rank output should be scalar");
output->p(0, input->rankOf());
output->syncToDevice();
return Status::OK;
}
DECLARE_SHAPE_FN(rank) { return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(sd::DataType::INT64)); }
DECLARE_TYPES(rank) {
getOpDescriptor()
->setAllowedInputTypes(ANY)
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS})
->allowOverride(true);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,245 @@
/* ******************************************************************************
*
*
* 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
******************************************************************************/
//
// Created by raver119 on 29/10/17.
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_reshape)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
// here iArgs is a vector with (optional) negative of order as first element:
// ({-order, dim1, dim2, dim3, ...})
CUSTOM_OP_IMPL(reshape, 1, 1, false, 0, -2) {
auto x = INPUT_VARIABLE(0);
auto z = OUTPUT_VARIABLE(0);
// Special case: empty.reshape(<other empty shape>) -> return empty
if (x->isEmpty()) {
REQUIRE_TRUE(z->isEmpty(), 0, "Reshape: when input is empty, output must also be empty");
return Status::OK; // No op
}
x->syncToHost();
//scalars can either be 0 or 1
if(!x->isScalar() && !x->isEmpty())
REQUIRE_TRUE(x->lengthOf() == z->lengthOf(), 0,
"Reshape: lengths before and after reshape should match, but "
"got %i vs %i",
x->lengthOf(), z->lengthOf());
auto* zShapeVec = z->getShapeAsVector();
if (Environment::getInstance().isDebugAndVerbose()) sd_printv("Reshape: new shape", *zShapeVec);
if(z->ordering() != 'c' && z->ordering() != 'f') {
std::string errorMessage;
errorMessage += "Reshape: new shape has unknown order: [";
errorMessage += z->ordering();
errorMessage += "]";
delete zShapeVec;
THROW_EXCEPTION(errorMessage.c_str());
}
//only perform assign when we aren't using a view
if(x->dataBuffer() != z->dataBuffer()) {
NDArray *reshapedX = x->reshape(z->ordering(), *zShapeVec, true);
delete zShapeVec;
z->assign(reshapedX);
delete reshapedX;
} else {
delete zShapeVec;
}
return Status::OK;
}
DECLARE_TYPES(reshape) {
getOpDescriptor()->setAllowedInputTypes(0, ANY)->setAllowedInputTypes(1, {ALL_INTS})->setSameMode(true);
}
bool handleOptionalOrder(std::vector<LongType> &reshapeArgs, char &ordering) {
if (reshapeArgs.size() > 0) {
// check if any optional negative ordering value is passed
auto optional = reshapeArgs[0];
if (optional < 0) {
optional = abs(optional);
// check if passed option is allowed. (-1 -> dynamic shape)
// in that case we will return back
if (optional == 1) return true;
// in this case it should obey allowed orderings
if (optional != 'c' && optional != 'f') return false;
reshapeArgs.erase(reshapeArgs.begin());
// ordering was passed and ok. let's assign
ordering = optional;
}
}
// skipped
return true;
}
LongType* handleScalarAndLength1Case(NDArray* x, std::vector<LongType>& reshapeArgs) {
//need to handle disambiguation between empty and scalar
if(x->isScalar() || x->lengthOf() == 1) {
if(reshapeArgs.size() < 1) {
return ConstantShapeHelper::getInstance().scalarShapeInfo(x->dataType());
}
// For scalar/length-1 input, if reshape args contain -1, replace it with 1
std::vector<LongType> finalShape = reshapeArgs;
for (size_t i = 0; i < finalShape.size(); i++) {
if (finalShape[i] == -1) {
finalShape[i] = 1;
}
}
return ConstantShapeHelper::getInstance().createShapeInfo(x->dataType(), 'c', finalShape);
}
return nullptr;
}
void processReshapeArgs(std::vector<LongType>& reshapeArgs, std::vector<LongType>& shapeNew,
LongType& newShapeLen, int& pos, bool& newShapeEmpty) {
newShapeLen = 1;
pos = -1;
newShapeEmpty = false;
for (size_t i = 0; i < reshapeArgs.size(); i++) {
int dim = reshapeArgs[i];
if (dim == -1) {
REQUIRE_TRUE(pos == -1, 0, "Reshape : Only one unknown dimension (-1) is allowed.");
pos = i;
shapeNew.push_back(1);
} else if (dim == 0) {
shapeNew.push_back(0);
newShapeEmpty = true;
} else {
shapeNew.push_back(dim);
newShapeLen *= dim;
}
}
}
void computeUnknownDimension(NDArray* x, std::vector<LongType>& shapeNew, int pos,
LongType newShapeLen, bool newShapeEmpty) {
if (pos != -1) {
LongType xLen = x->lengthOf();
if (x->isEmpty()) {
xLen = 1;
// For empty shapes, calculate length considering non-zero dimensions
for (LongType i = 0; i < x->rankOf(); ++i) // take into account possible empty shapes
if (x->sizeAt(i) > 0 || !newShapeEmpty) xLen *= x->sizeAt(i);
}
shapeNew[pos] = xLen / newShapeLen;
}
}
LongType* handleEmptyShapeCase(NDArray* x, std::vector<LongType> reshapeArgs, bool newShapeEmpty) {
if(newShapeEmpty) {
for(size_t i = 0; i < reshapeArgs.size(); i++) {
if(reshapeArgs[i] < 0)
reshapeArgs[i] = 1;
}
return ConstantShapeHelper::getInstance().emptyShapeInfoWithShape(x->dataType(), reshapeArgs);
}
return nullptr;
}
DECLARE_SHAPE_FN(reshape) {
auto x = INPUT_VARIABLE(0);
std::vector<LongType> reshapeArgs;
std::vector<LongType> shapeNew;
char orderNew = 'c';
/**
* NOTE: The value here is negative as a flag.
* A negative value signifies 1 of 3 values:
* -1 -> dynamic shape
* -99 -> c ordering
* -102 -> f ordering
*
*/
if (block.width() == 1) {
reshapeArgs = *block.getIArguments();
if (!handleOptionalOrder(reshapeArgs, orderNew)) {
THROW_EXCEPTION(
"reshape:: Value passed in must be -99 or -102 for the ordering if "
"an int array is present. -99 represents c ordering and -102 "
"represents f ordering. This number is negative for the long array "
"case to flag the difference between an ordering and a dimension "
"being specified.");
};
} else {
reshapeArgs = INPUT_VARIABLE(1)->getBufferAsVector<LongType>();
if (block.numI() > 0) {
// Note here that the ordering for this case can not be negative.
// Negative is used in the long array case to be used as a flag to
// differentiate between a 99 or 102 shaped array and
// the ordering. You can't have a -99 or -102 shaped array.
char potentialOrdering = (char)I_ARG(0);
if (!handleOptionalOrder(reshapeArgs, orderNew)) {
THROW_EXCEPTION(
"reshape:: Value passed in must be -99 or -102 for the ordering if "
"an int array is present. -99 represents c ordering and -102 "
"represents f ordering. This number is negative for the long array "
"case to flag the difference between an ordering and a dimension "
"being specified.");
};
orderNew = -potentialOrdering;
}
}
// Handle scalar/length 1 case
LongType* scalarResult = handleScalarAndLength1Case(x, reshapeArgs);
if (scalarResult != nullptr) {
return SHAPELIST(scalarResult);
}
LongType newShapeLen;
int pos;
bool newShapeEmpty;
// Process reshape arguments
processReshapeArgs(reshapeArgs, shapeNew, newShapeLen, pos, newShapeEmpty);
// Compute unknown dimension if needed
computeUnknownDimension(x, shapeNew, pos, newShapeLen, newShapeEmpty);
// Handle empty shape case
LongType* emptyResult = handleEmptyShapeCase(x, reshapeArgs, newShapeEmpty);
if (emptyResult != nullptr) {
return SHAPELIST(emptyResult);
}
auto len = shape::prodLong(shapeNew.data(), shapeNew.size());
if(!x->isScalar() && !x->isEmpty())
REQUIRE_TRUE(x->lengthOf() == len, 0,
"Reshape: lengths before and after reshape should match, but "
"got %i vs %i",
x->lengthOf(), len);
return SHAPELIST(ConstantShapeHelper::getInstance().createShapeInfo(x->dataType(), orderNew, shapeNew));
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,59 @@
/* ******************************************************************************
*
*
* 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
******************************************************************************/
//
// Created by raver119 on 29/10/17.
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_reshapeas)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reshapeas, 2, 1, false, 0, 0) {
auto x = INPUT_VARIABLE(0);
auto y = INPUT_VARIABLE(1);
auto z = OUTPUT_VARIABLE(0);
auto* yShape = y->getShapeAsVector();
bool reshapeResult = x->reshapei(y->ordering(), *yShape);
delete yShape;
if (reshapeResult) {
z->assign(x);
return Status::OK;
}
return Status::BAD_INPUT;
}
DECLARE_SYN(reshape_as, reshapeas);
DECLARE_SHAPE_FN(reshapeas) {
return SHAPELIST(ShapeBuilders::copyShapeInfo(INPUT_VARIABLE(1)->shapeInfo(), false, block.workspace()));
}
DECLARE_TYPES(reshapeas) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,168 @@
//
// Created by agibsonccc on 8/30/24.
//
#include <helpers/reshapeNoCopy.h>
#include <helpers/shape.h>
#include <ops/declarable/headers/shape.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(reshape_no_copy, -2, 1, false, 0, -2) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
//note that the calculate output shape that sets this flag does not have access to the data buffer
if (ArrayOptions::arrayNeedsCopy(const_cast<LongType *>(output->shapeInfo()))
|| output->dataBuffer() != input->dataBuffer()) {
//immitate a reshape operation but without triggering a copy. These helpers are to prevent stack overflows with reshape -> assign -> reshape which used to exist
auto* inputShape = input->getShapeAsVector();
sd::LongType *shapeInfo = NDArray::reshapeShapeInfo(output, output->ordering(), *inputShape);
delete inputShape;
NDArray::copyDataForAssign(input, output, shapeInfo, false);
}
// the rest is no op, we don't need to copy we just needed the new shape
return Status::OK;
}
DECLARE_SHAPE_FN(reshape_no_copy) {
auto inShape = inputShape->at(0);
if (ArrayOptions::dataType(inShape) == UNKNOWN) {
THROW_EXCEPTION("Illegal data type set for reshape: UNKNOWN");
}
DataType dtype = ArrayOptions::dataType(inShape);
char order = shape::order(inShape); // Default to input order
std::vector<sd::LongType> newShape;
if (block.width() > 1) {
auto shapeArg = INPUT_VARIABLE(1);
auto shapeBuffLong = shapeArg->getBufferAsVector<sd::LongType>();
// last is the ordering
for (size_t i = 0; i < shapeBuffLong.size() - 1; i++) {
newShape.push_back(shapeBuffLong[i]);
}
// Handle order when shape is provided as input
if (block.numI() > 0) {
auto orderArg = INT_ARG(0);
if (orderArg == RESHAPE_NO_COPY_F_ORDER_MARKER) {
order = 'f';
} else if (orderArg == RESHAPE_NO_COPY_C_ORDER_MARKER) {
order = 'c';
}
} else {
// Default to 'c' order if not specified
order = 'c';
}
} else {
std::vector<sd::LongType> *iArgs = block.getIArguments();
for (size_t i = 0; i < block.numI() - 1; i++) {
newShape.push_back(iArgs->at(i));
}
order = iArgs->at(iArgs->size() - 1) == RESHAPE_NO_COPY_F_ORDER_MARKER ? 'f' : 'c';
}
// Handle -1 in shape specification
sd::LongType negativeOneCount = 0;
sd::LongType negativeOneIndex = -1;
sd::LongType totalElements = shape::length(inShape);
sd::LongType knownDimProduct = 1;
// Count -1s and calculate product of known dimensions
for (size_t i = 0; i < newShape.size(); i++) {
if (newShape[i] == -1) {
negativeOneCount++;
negativeOneIndex = i;
} else if (newShape[i] <= 0) {
std::string errorMessage = "Shape value is invalid: ";
errorMessage += std::to_string(newShape[i]);
errorMessage += " at index ";
errorMessage += std::to_string(i);
errorMessage += " in shape ";
errorMessage += std::to_string(newShape.size());
THROW_EXCEPTION(errorMessage.c_str());
} else {
knownDimProduct *= newShape[i];
}
}
// Validate -1 usage
if (negativeOneCount > 1) {
THROW_EXCEPTION("Only one dimension can be -1 in reshape operation");
}
// Calculate the -1 dimension if present
if (negativeOneCount == 1) {
if (totalElements % knownDimProduct != 0) {
std::string errorMessage = "Cannot reshape array of size ";
errorMessage += std::to_string(totalElements);
errorMessage += " into shape with known dimensions product ";
errorMessage += std::to_string(knownDimProduct);
THROW_EXCEPTION(errorMessage.c_str());
}
newShape[negativeOneIndex] = totalElements / knownDimProduct;
}
sd::LongType len = shape::shapeInfoLength(newShape.size());
sd::LongType *newShapeInfo = new sd::LongType[len];
newShapeInfo[0] = newShape.size();
shape::setShape(newShapeInfo, newShape.data());
shape::setOrder(newShapeInfo, order);
auto newShapeView = shape::shapeOf(newShapeInfo);
for (size_t i = 0; i < newShape.size(); i++) {
if (newShape[i] != newShapeView[i]) {
std::string errorMessage;
errorMessage += "Failed to set shape. ";
errorMessage += "Shape ";
errorMessage += std::to_string(i);
errorMessage += ": ";
errorMessage += std::to_string(newShape[i]);
errorMessage += " != ";
errorMessage += std::to_string(newShapeView[i]);
THROW_EXCEPTION(errorMessage.c_str())
}
}
if (shape::isEmptyConst(inShape)) {
newShapeInfo[0] = newShape.size();
shape::setShape(newShapeInfo, newShape.data());
// If reshape is not possible without allocation, fall back to regular reshape
shape::updateStrides(newShapeInfo, order, true);
ArrayOptions::resetFlags(newShapeInfo);
ArrayOptions::setDataType(newShapeInfo, dtype);
ArrayOptions::toggleIsEmpty(newShapeInfo);
} else {
bool reshapeNoAllocSuccess = helpers::reshapeNoAlloc(inShape, newShape, order, newShapeInfo);
if (!reshapeNoAllocSuccess || shape::order(inShape) != order) {
//we need new strides if we can't handle the copy
shape::updateStrides(newShapeInfo, order, true);
ArrayOptions::resetFlags(newShapeInfo);
ArrayOptions::setDataType(newShapeInfo, dtype);
//ensure we trigger a proper data copy
ArrayOptions::togglePropertyBit(newShapeInfo, ARRAY_NEEDS_COPY);
} else {
//we set strides in the reshape alloc success already
newShapeInfo[0] = newShape.size();
shape::setShape(newShapeInfo, newShape.data());
ArrayOptions::resetFlags(newShapeInfo);
// we need this in order to preserve the offset of the original buffer when creating the output array
ArrayOptions::togglePropertyBit(newShapeInfo, ARRAY_COPY_OFFSET_INPUT_0);
ArrayOptions::setDataType(newShapeInfo, dtype);
}
}
auto newShape2 = ConstantShapeHelper::getInstance().createFromExisting(newShapeInfo);
delete[] newShapeInfo;
return SHAPELIST(CONSTANT(newShape2));
}
DECLARE_TYPES(reshape_no_copy) {
getOpDescriptor()
->setAllowedInputTypes(sd::DataType::ANY)
->setAllowedOutputTypes(sd::DataType::ANY)
->setSameMode(true);
}
}
}
@@ -0,0 +1,100 @@
/* ******************************************************************************
*
*
* 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
//
#include <system/op_boilerplate.h>
#include <ops/declarable/CustomOperations.h>
#if NOT_EXCLUDED(OP_shape_of)
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(shape_of, 1, 1, false, 0, 0) {
auto x = INPUT_VARIABLE(0);
auto z = OUTPUT_VARIABLE(0);
for (int e = 0; e < x->rankOf(); e++) z->p(e, x->sizeAt(e));
STORE_RESULT(z);
return Status::OK;
}
DECLARE_SYN(shape, shape_of);
DECLARE_SHAPE_FN(shape_of) {
auto inShape = inputShape->at(0);
// LONG by default
auto dtype = INT64;
if (block.numI() > 0) dtype = DataTypeUtils::fromInt(INT_ARG(0));
return SHAPELIST(ConstantShapeHelper::getInstance().vectorShapeInfo(shape::rank(inShape), dtype));
}
DECLARE_TYPES(shape_of) {
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes({ALL_INTS});
}
} // namespace ops
} // namespace sd
#endif
#if NOT_EXCLUDED(OP_set_shape)
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(set_shape, 2, 1, true, 0, 0) {
auto x = INPUT_VARIABLE(0);
auto shape = INPUT_VARIABLE(1);
auto z = OUTPUT_VARIABLE(0);
REQUIRE_TRUE(shape->isVector() || shape->isScalar(), 0, "Shape must be either a scalar or a vector");
auto newShapeInfo = ConstantShapeHelper::getInstance().createShapeInfo(x->dataType(), x->ordering(),
shape->asVectorT<LongType>());
z->setShapeInfo(newShapeInfo);
// if x and z aren't the same reference ensure the elements are the same.
// this op should almost always be used in place and in very specific circumstances.
if (x != z) {
z->assign(x, true);
}
return Status::OK;
}
DECLARE_SHAPE_FN(set_shape) {
auto inShape = INPUT_VARIABLE(1);
return SHAPELIST(inShape->shapeInfo());
}
DECLARE_TYPES(set_shape) {
getOpDescriptor()
->setAllowedInputTypes(0, ANY)
->setAllowedInputTypes(1, INT64)
->setAllowedOutputTypes({ANY});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,59 @@
/* ******************************************************************************
*
*
* 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
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_shapes_of)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(shapes_of, -1, -1, false, 0, 0) {
for (size_t e = 0; e < block.width(); e++) {
auto x = INPUT_VARIABLE(e);
auto z = OUTPUT_VARIABLE(e);
for (int i = 0; i < x->rankOf(); i++) z->p(i, x->sizeAt(i));
}
return Status::OK;
};
DECLARE_SYN(shape_n, shapes_of);
DECLARE_SHAPE_FN(shapes_of) {
auto shapeList = SHAPELIST();
for (int e = 0; e < inputShape->size(); e++) {
auto inShape = inputShape->at(e);
shapeList->push_back(ConstantShapeHelper::getInstance().vectorShapeInfo(shape::rank(inShape), INT64));
}
return shapeList;
};
DECLARE_TYPES(shapes_of) {
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes({ALL_INTS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,52 @@
/* ******************************************************************************
*
*
* 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
******************************************************************************/
//
// Created by raver119 on 01.11.2017.
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_size)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(size, 1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
REQUIRE_TRUE(output->isScalar(), 0, "Size output should be scalar");
output->p(0, input->lengthOf());
output->syncToDevice();
return Status::OK;
}
DECLARE_SHAPE_FN(size) { return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(sd::DataType::INT64)); }
DECLARE_TYPES(size) {
getOpDescriptor()
->setAllowedInputTypes(ANY)
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS})
->allowOverride(true);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,56 @@
/* ******************************************************************************
*
*
* 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
******************************************************************************/
//
// Created by raver119 on 12.02.18.
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_size_at)
#include <ops/declarable/headers/shape.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(size_at, 1, 1, false, 0, 1) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
auto dim = INT_ARG(0);
if (dim < 0) dim += input->rankOf();
REQUIRE_TRUE(dim < input->rankOf(), 0, "Size_At: Dim can't be higher then input rank")
output->p(0, input->sizeAt(dim));
output->syncToDevice();
return Status::OK;
}
DECLARE_SHAPE_FN(size_at) { return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(sd::DataType::INT64)); }
DECLARE_TYPES(size_at) {
getOpDescriptor()
->setAllowedInputTypes(ANY)
->setAllowedOutputTypes(INT64)
->allowOverride(true);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,163 @@
/* ******************************************************************************
*
*
* 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
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_squeeze)
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(squeeze, 1, 1, false, 0, -2) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
std::vector<LongType> axis;
if (block.numI() > 0)
for (size_t e = 0; e < block.numI(); e++) {
int _a = INT_ARG(e);
if (_a < 0) _a += input->rankOf();
axis.emplace_back(_a);
}
else if (block.width() > 1) {
auto a = INPUT_VARIABLE(1);
for (LongType e = 0; e < a->lengthOf(); e++) {
int _a = a->e<LongType>(e);
if (_a < 0) _a += input->rankOf();
axis.emplace_back(_a);
}
}
if (input->rankOf() == 0 || (input->rankOf() == 1 && input->lengthOf() == 1)) {
output->assign(input);
return Status::OK;
}
std::vector<LongType> shape;
if (axis.size() == 0) {
for (int d = 0; d < input->rankOf(); d++)
if (input->sizeAt(d) > 1) shape.emplace_back(input->sizeAt(d));
} else {
for (int d = 0; d < input->rankOf(); d++) {
if (input->sizeAt(d) == 1) {
if (std::find(axis.begin(), axis.end(), d) == axis.end()) shape.emplace_back(input->sizeAt(d));
} else
shape.emplace_back(input->sizeAt(d));
}
}
if (block.isInplace()) {
output->reshapei(input->ordering(), shape);
} else {
if (input->ews() == 1 && output->ews() == 1 && input->ordering() == output->ordering()) {
output->dataBuffer()->copyBufferFrom(*input->dataBuffer(),
output->lengthOf() * DataTypeUtils::sizeOfElement(output->dataType()), 0,
input->offset());
} else {
auto tmp = input->reshape(input->ordering(), shape);
output->assign(tmp);
delete tmp;
}
}
return Status::OK;
}
DECLARE_TYPES(squeeze) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
DECLARE_SHAPE_FN(squeeze) {
auto shapeList = SHAPELIST();
auto in = inputShape->at(0);
auto rank = shape::rank(in);
auto length = shape::length(in);
if (rank == 0 || (rank == 1 && length == 1)) {
shapeList->push_back(ConstantShapeHelper::getInstance().scalarShapeInfo(ArrayOptions::dataType(in)));
return shapeList;
}
std::vector<LongType> axis;
if (block.numI() > 0)
for (size_t e = 0; e < block.numI(); e++) {
int _a = INT_ARG(e);
if (_a < 0) _a += rank;
axis.emplace_back(_a);
}
else if (block.width() > 1) {
auto a = INPUT_VARIABLE(1);
for (LongType e = 0; e < a->lengthOf(); e++) {
LongType _a = a->e<LongType>(e);
if (_a < 0) _a += rank;
axis.emplace_back(_a);
}
}
auto order = shape::order(in);
auto oldShape = shape::shapeOf(in);
std::vector<LongType> shape;
if (axis.size() == 0) {
for (LongType d = 0; d < rank; d++)
if (oldShape[d] > 1) shape.emplace_back(oldShape[d]);
} else {
for (int d = 0; d < rank; d++) {
if (oldShape[d] == 1) {
if (std::find(axis.begin(), axis.end(), d) == axis.end()) shape.emplace_back(oldShape[d]);
} else
shape.emplace_back(oldShape[d]);
}
}
if (shape.size() == 0) {
shapeList->push_back(ConstantShapeHelper::getInstance().scalarShapeInfo(ArrayOptions::dataType(in)));
return shapeList;
}
if(shape::isEmptyConst(in)) {
if(shape::rank(in) < 1) {
shapeList->push_back(ConstantShapeHelper::getInstance().emptyShapeInfo(ArrayOptions::dataType(in)));
return shapeList;
}
shapeList->push_back(ConstantShapeHelper::getInstance().emptyShapeInfoWithShape(ArrayOptions::dataType(in),shape));
return shapeList;
} else {
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(in), order, shape);
shapeList->push_back(newShape);
}
return shapeList;
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,92 @@
/* ******************************************************************************
*
*
* 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
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_tile_to_shape)
#include <ops/declarable/headers/shape.h>
namespace sd {
namespace ops {
CUSTOM_OP_IMPL(tile_to_shape, 1, 1, false, 0, -1) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
std::vector<LongType> outShape(block.getIArguments()->begin(), block.getIArguments()->end());
if (block.isInplace()) {
input->tileToShape(outShape, *input);
} else {
input->tileToShape(outShape, *output);
}
return Status::OK;
}
DECLARE_SHAPE_FN(tile_to_shape) {
auto in = inputShape->at(0);
// output shape always equals to arguments
auto conv = ArrayUtils::toLongVector(*block.getIArguments());
auto newShape =
ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(in), shape::order(in), conv);
return SHAPELIST(newShape);
}
DECLARE_TYPES(tile_to_shape) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
DECLARE_TYPES(tile_to_shape_bp) {
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
CUSTOM_OP_IMPL(tile_to_shape_bp, 2, 1, true, 0, -1) {
auto input = INPUT_VARIABLE(0);
auto epsNext = INPUT_VARIABLE(1);
auto gradX = OUTPUT_VARIABLE(0);
auto axisX = ShapeUtils::evalBroadcastBackwardAxis(input->shapeInfo(), epsNext->shapeInfo());
// FIX ME: reduceAlongDimension should have a signature with result pass to avoid assigning twice
if (!axisX.empty()) {
auto tempRes = epsNext->reduceAlongDimension(reduce::Sum, &axisX);
gradX->assign(tempRes);
delete tempRes;
} else
gradX->assign(epsNext);
STORE_RESULT(gradX);
return Status::OK;
}
DECLARE_SHAPE_FN(tile_to_shape_bp) {
auto in = inputShape->at(0);
return SHAPELIST(CONSTANT(in));
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,133 @@
/* ******************************************************************************
*
*
* 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
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_transpose)
#include <helpers/ShapeUtils.h>
#include <ops/declarable/CustomOperations.h>
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(transpose, 1, 1, false, 0, 0) {
auto x = INPUT_VARIABLE(0);
auto z = OUTPUT_VARIABLE(0);
// Special case: empty.reshape(<other empty shape>) -> return empty
if (x->isEmpty()) {
REQUIRE_TRUE(z->isEmpty(), 0, "TRANSPOSE OP: when input is empty, output must also be empty");
return Status::OK; // No op
}
NDArray* castedPermute = nullptr;
std::vector<LongType> permutationVector;
if (block.width() > 1) {
castedPermute = INPUT_VARIABLE(1)->cast(INT64);
permutationVector = castedPermute->asVectorT<LongType>();
} else {
permutationVector = *block.getIArguments();
}
if (permutationVector.size() == 0) {
NDArray *t = x->transpose();
z->assign(t);
// FIXED: transpose() returns a view - only delete if not a view
if (t != nullptr && !t->isView()) {
delete t;
}
if (castedPermute != nullptr) delete castedPermute;
return Status::OK;
}
bool isPermuteNecessary = false;
int rank = permutationVector.size();
//handles empty permute vector case as well as case where array rank and permute vector rank
//are different
for (LongType i = 0; i < rank; ++i) {
if (permutationVector[i] != i) {
isPermuteNecessary = true;
break;
}
}
if(!isPermuteNecessary) {
z->assign(x);
return Status::OK;
}
z->assign(x->permute(permutationVector, false, false));
if (castedPermute != nullptr) delete castedPermute;
return Status::OK;
}
DECLARE_TYPES(transpose) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
DECLARE_SHAPE_FN(transpose) {
auto x = INPUT_VARIABLE(0);
const LongType rank = x->rankOf();
if(rank < 1)
return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(x->dataType()));
std::vector<LongType> permutationVector = block.width() > 1 ? INPUT_VARIABLE(1)->cast(INT64)->asVectorT<LongType>() : *block.getIArguments();
if (permutationVector.size() == 0) {
auto temp = ShapeUtils::evalTransposeShapeInfo(*x, nullptr, true);
auto ret = ConstantShapeHelper::getInstance().createFromExisting(temp);
RELEASE(temp, nullptr);
return SHAPELIST(ret);
}
bool isPermuteNecessary = false;
if(permutationVector.size() == static_cast<size_t>(rank))
for (LongType i = 0; i < rank; ++i) {
if (permutationVector[i] != i) {
isPermuteNecessary = true;
break;
}
}
if(!isPermuteNecessary) {
//note: do not deallocate this buffer. they are kept around.
auto permEvalShapeInfo = ConstantShapeHelper::getInstance().createFromExisting(inputShape->at(0));
return SHAPELIST(permEvalShapeInfo);
}
//note: do not deallocate this buffer. they are kept around.
auto permEvalShapeInfo = ShapeUtils::evalPermShapeInfo(permutationVector.data(), x->rankOf(), x, nullptr, true);
if(x->isEmpty()) {
ArrayOptions::setPropertyBit(permEvalShapeInfo, ARRAY_EMPTY);
}
auto ret = CONSTANT(permEvalShapeInfo);
return SHAPELIST(ret);
}
} // namespace ops
} // namespace sd
#endif