intdim=INT_ARG(1);// axis along which sum will be made
if(dim<0)
dim+=labels->rankOf();
// labels and predictions must have the same shapes
REQUIRE_TRUE(labels->isSameShape(predictions),0,"COSINE_DISTANCE_LOSS OP: labels and predictions arrays must have the same shapes, but got %s and %s correspondingly !",ShapeUtils::shapeAsString(labels).c_str(),ShapeUtils::shapeAsString(predictions).c_str());
// regard 4 possible reduction modes below
REQUIRE_TRUE(reductionMode==0||reductionMode==1||reductionMode==2||reductionMode==3,0,"COSINE_DISTANCE_LOSS OP: reduction mode value is not acceptable, possible values are 0, 1, 2, 3, but got %i instead!",reductionMode);
// input dimension can't be larger than labels/predictions/weights rank
REQUIRE_TRUE(dim<labels->rankOf(),0,"COSINE_DISTANCE_LOSS OP: input reduction dimension (got %i) must be < labels rank %i!",dim,labels->rankOf());
if(!output->isScalar()){
// weights array can be single scalar or has the same shape as output, and must be broadcastable to output shape
REQUIRE_TRUE(weights->isScalar()||weights->rankOf()==output->rankOf(),0,"SOFTMAX_CROSS_ENTROPY_LOSS OP: weights array should be scalar or have the same rank as output array, but got %i and %i correspondingly!",weights->rankOf(),output->rankOf());
// check whether broadcast operation is possible for weights array
REQUIRE_TRUE(weights->isScalar()||ShapeUtils::areShapesBroadcastable(*weights,*output),0,"COSINE_DISTANCE_LOSS OP: shapes of weights and output arrays should be broadcastable, but got weights = %s and output = %s instead!",ShapeUtils::shapeAsString(weights).c_str(),ShapeUtils::shapeAsString(labels).c_str());
case3:{// 3 - "weighted_sum_by_nonzero_weights", output is scalar and equal to scalar sum of all elements of E array divided by number of non-zero weights
// labels and predictions must have the same shapes
REQUIRE_TRUE(shape::shapeEquals(labelsShapeInfo,predictionsShapeInfo),0,"COSINE_DISTANCE_LOSS OP: labels and predictions arrays must have the same shapes, but got %s and %s correspondingly !",ShapeUtils::shapeAsString(labelsShapeInfo).c_str(),ShapeUtils::shapeAsString(predictionsShapeInfo).c_str());
// input dimension can't be larger than labels/predictions/weights rank
REQUIRE_TRUE(dim<labelsShapeInfo[0],0,"COSINE_DISTANCE_LOSS OP: input reduction dimension (got %i) must be < labels rank %i!",dim,labelsShapeInfo[0]);
// weights array can be single scalar or has the same rank as output, and must be broadcastable to output
REQUIRE_TRUE(shape::isScalar(weightsShapeInfo)||shape::rank(weightsShapeInfo)==shape::rank(outShapeInfo),0,"COSINE_DISTANCE_LOSS OP: weights array should be scalar or have the same rank as output array, but got %i and %i correspondingly!",shape::rank(weightsShapeInfo),shape::rank(outShapeInfo));
// check whether broadcast operation is possible for weights array
REQUIRE_TRUE(shape::isScalar(weightsShapeInfo)||ShapeUtils::areShapesBroadcastable(weightsShapeInfo,outShapeInfo),0,"COSINE_DISTANCE_LOSS OP: shapes of weights and output arrays should be broadcastable, but got weights = %s and output = %s instead!",ShapeUtils::shapeAsString(weightsShapeInfo).c_str(),ShapeUtils::shapeAsString(outShapeInfo).c_str());
// take into account Alex's proposition to treat "none" the same as "weighted_sum" mode when calculating gradients
if(reductionMode==0)
reductionMode=1;
intdim=INT_ARG(1);// axis along which sum will be made
if(dim<0)
dim+=labels->rankOf();
std::vector<int>dimensions={dim};
// input validation
REQUIRE_TRUE(labels->isSameShape(predictions),0,"COSINE_DISTANCE_LOSS_GRAD OP: labels and predictions arrays must have the same shapes, but got %s and %s correspondingly !",ShapeUtils::shapeAsString(labels).c_str(),ShapeUtils::shapeAsString(predictions).c_str());
// only 4 possible reduction modes exist
REQUIRE_TRUE(reductionMode==0||reductionMode==1||reductionMode==2||reductionMode==3,0,"COSINE_DISTANCE_LOSS_GRAD OP: reduction mode value is not acceptable, possible values are 0, 1, 2, 3, but got %i instead!",reductionMode);
// weights array can be single scalar or has the same shape as loss, and must be broadcastable to loss shape
REQUIRE_TRUE(weights->isScalar()||weights->rankOf()==shape::rank(lossShapeInfo),0,"COSINE_DISTANCE_LOSS_GRAD OP: weights array should be scalar or have the same rank as loss array, but got %i and %i correspondingly!",weights->rankOf(),shape::rank(lossShapeInfo));
// check whether broadcast operation is possible for weights array
REQUIRE_TRUE(weights->isScalar()||ShapeUtils::areShapesBroadcastable(weights->getShapeInfo(),lossShapeInfo),0,"COSINE_DISTANCE_LOSS_GRAD OP: shapes of weights and loss arrays should be broadcastable, but got weights = %s and loss = %s instead!",ShapeUtils::shapeAsString(weights).c_str(),ShapeUtils::shapeAsString(lossShapeInfo).c_str());
// input dimension can't be larger than labels/predictions/weights rank
REQUIRE_TRUE(dim<labels->rankOf(),0,"COSINE_DISTANCE_LOSS_GRAD OP: input reduction dimension (got %i) must be < labels rank %i!",dim,labels->rankOf());
case3:{// 3 - "weighted_sum_by_nonzero_weights", output is scalar and equal to scalar sum of all elements of E array divided by number of non-zero weights
/// labels and predictions must have the same shapes
autopredictionsShapeInfo=inputShape->at(0);
autoweightsShapeInfo=inputShape->at(1);
autolabelsShapeInfo=inputShape->at(2);
intdim=INT_ARG(1);
if(dim<0)
dim+=labelsShapeInfo[0];
std::vector<int>dimensions={dim};
// labels and predictions must have the same shapes
REQUIRE_TRUE(shape::shapeEquals(labelsShapeInfo,predictionsShapeInfo),0,"COSINE_DISTANCE_LOSS_GRAD OP: labels and predictions arrays must have the same shapes, but got %s and %s correspondingly !",ShapeUtils::shapeAsString(labelsShapeInfo).c_str(),ShapeUtils::shapeAsString(predictionsShapeInfo).c_str());
// weights array can be single scalar or has the same rank as loss, and must be broadcastable to loss
REQUIRE_TRUE(shape::isScalar(weightsShapeInfo)||shape::rank(weightsShapeInfo)==shape::rank(lossShapeInfo),0,"COSINE_DISTANCE_LOSS_GRAD OP: weights array should be scalar or have the same rank as loss array, but got %i and %i correspondingly!",shape::rank(weightsShapeInfo),shape::rank(lossShapeInfo));
// check whether broadcast operation is possible for weights array
REQUIRE_TRUE(shape::isScalar(weightsShapeInfo)||ShapeUtils::areShapesBroadcastable(weightsShapeInfo,lossShapeInfo),0,"COSINE_DISTANCE_LOSS_GRAD OP: shapes of weights and loss arrays should be broadcastable, but got weights = %s and loss = %s instead!",ShapeUtils::shapeAsString(weightsShapeInfo).c_str(),ShapeUtils::shapeAsString(lossShapeInfo).c_str());
// input dimension can't be larger than labels/predictions/weights rank
REQUIRE_TRUE(dim<labelsShapeInfo[0],0,"COSINE_DISTANCE_LOSS_GRAD OP: input reduction dimension (got %i) must be < labels rank %i!",dim,labelsShapeInfo[0]);