REQUIRE_TRUE(reductionMode==0||reductionMode==1||reductionMode==2||reductionMode==3,0,"MEAN_PAIRWSSQERR_LOSS OP: reduction mode value is not acceptable, possible values are 0, 1, 2, 3, but got %i instead!",reductionMode);
if(labels->rankOf()==1){// If labels and predictions are of rank 1, it means that all data entries are 0-tensor (scalar) so that the result of becomes always zero.
// weights array can be single scalar or has the same rank as labels, and must be broadcastable to labels
REQUIRE_TRUE(weights->isScalar()||weights->rankOf()==E.rankOf(),0,"MEAN_PAIRWSSQERR_LOSS_GRAD OP: weights array should be scalar or have the same rank as results array, but got %i and %i correspondingly!",weights->rankOf(),E.rankOf());
// check whether broadcast operation is possible for weights array
REQUIRE_TRUE(weights->isScalar()||ShapeUtils::areShapesBroadcastable(*weights,E),0,"MEAN_PAIRWSSQERR_LOSS_GRAD OP: shapes of weights and labels arrays should be broadcastable, but got weights = %s and results = %s instead!",ShapeUtils::shapeAsString(weights).c_str(),ShapeUtils::shapeAsString(&E).c_str());
// perform weights broadcasting/tile to labels if needed
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
// 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,"MEAN_PAIRWSSQERR_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,"MEAN_PAIRWSSQERR_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;
// inputs validation
REQUIRE_TRUE(labels->isSameShape(predictions),0,"MEAN_PAIRWSSQERR_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,"MEAN_PAIRWSSQERR_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 rank as labels, and must be broadcastable to labels
REQUIRE_TRUE(weights->isScalar()||weights->rankOf()==E.rankOf(),0,"MEAN_PAIRWSSQERR_LOSS_GRAD OP: weights array should be scalar or have the same rank as results array, but got %i and %i correspondingly!",weights->rankOf(),E.rankOf());
// check whether broadcast operation is possible for weights array
REQUIRE_TRUE(weights->isScalar()||ShapeUtils::areShapesBroadcastable(*weights,E),0,"MEAN_PAIRWSSQERR_LOSS_GRAD OP: shapes of weights and labels arrays should be broadcastable, but got weights = %s and results = %s instead!",ShapeUtils::shapeAsString(weights).c_str(),ShapeUtils::shapeAsString(&E).c_str());
// perform weights broadcasting/tile to labels if needed
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,"MEAN_PAIRWSSQERR_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 labels, and must be broadcastable to labels
REQUIRE_TRUE(shape::isScalar(weightsShapeInfo)||shape::rank(weightsShapeInfo)==shape::rank(labelsShapeInfo),0,"MEAN_PAIRWSSQERR_LOSS_GRAD OP: weights array should be scalar or have the same rank as labels array, but got %i and %i correspondingly!",shape::rank(weightsShapeInfo),shape::rank(labelsShapeInfo));
// check whether broadcast operation is possible for weights array
REQUIRE_TRUE(shape::isScalar(weightsShapeInfo)||ShapeUtils::areShapesBroadcastable(weightsShapeInfo,labelsShapeInfo),0,"MEAN_PAIRWSSQERR_LOSS_GRAD OP: shapes of weights and labels arrays should be broadcastable, but got weights = %s and labels = %s instead!",ShapeUtils::shapeAsString(weightsShapeInfo).c_str(),ShapeUtils::shapeAsString(labelsShapeInfo).c_str());