Define all reduce ops in operation manager.

Bug: 129569810
Test: NeuralNetworksTest_static_fuzzing
Change-Id: I4d753287dc7caee3fe88af0e4e647570fc272ce1
Merged-In: I4d753287dc7caee3fe88af0e4e647570fc272ce1
(cherry picked from commit 2e55ea6153a6380164100782f44d7fba07cf535b)
diff --git a/runtime/test/fuzzing/operation_signatures/Reduce.cpp b/runtime/test/fuzzing/operation_signatures/Reduce.cpp
new file mode 100644
index 0000000..38dcdcb
--- /dev/null
+++ b/runtime/test/fuzzing/operation_signatures/Reduce.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+#include "fuzzing/operation_signatures/OperationSignatureUtils.h"
+
+namespace android {
+namespace nn {
+namespace fuzzing_test {
+
+static void reduceOpConstructor(Type, uint32_t rank, RandomOperation* op) {
+    setFreeDimensions(op->inputs[0], rank);
+
+    // A boolean array indicating whether each dimension is selected to be reduced.
+    bool reduce[4] = {false, false, false, false};
+
+    // Generate values for the "axis" tensor.
+    uint32_t numAxis = getUniform<int32_t>(1, 10);
+    op->inputs[1]->dimensions = {numAxis};
+    op->inputs[1]->resizeBuffer<int32_t>(numAxis);
+    for (uint32_t i = 0; i < numAxis; i++) {
+        int32_t dim = getUniform<int32_t>(-rank, rank - 1);
+        op->inputs[1]->value<int32_t>(i) = dim;
+        reduce[dim < 0 ? dim + rank : dim] = true;
+    }
+
+    // This scalar may have two types: in MEAN it is INT32, in REDUCE_* it is BOOL
+    bool keepDims;
+    if (op->inputs[2]->dataType == Type::BOOL) {
+        keepDims = op->inputs[2]->value<bool8>();
+    } else {
+        keepDims = op->inputs[2]->value<int32_t>() > 0;
+    }
+
+    for (uint32_t i = 0; i < rank; i++) {
+        if (!reduce[i]) {
+            op->outputs[0]->dimensions.emplace_back(op->inputs[0]->dimensions[i]);
+        } else if (keepDims) {
+            op->outputs[0]->dimensions.emplace_back(1);
+        }
+    }
+    setSameQuantization(op->outputs[0], op->inputs[0]);
+}
+
+#define DEFINE_MEAN_SIGNATURE(ver, ...)                                   \
+    DEFINE_OPERATION_SIGNATURE(MEAN_##ver){                               \
+            .opType = ANEURALNETWORKS_MEAN,                               \
+            .supportedDataTypes = {__VA_ARGS__},                          \
+            .supportedRanks = {1, 2, 3, 4},                               \
+            .version = HalVersion::ver,                                   \
+            .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32), \
+                       PARAMETER_CHOICE(Type::INT32, -100, 100)},         \
+            .outputs = {OUTPUT_DEFAULT},                                  \
+            .constructor = reduceOpConstructor};
+
+DEFINE_MEAN_SIGNATURE(V1_1, Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM);
+DEFINE_MEAN_SIGNATURE(V1_2, Type::TENSOR_FLOAT16);
+
+#define DEFINE_REDUCE_SIGNATURE(op, ver, ...)                             \
+    DEFINE_OPERATION_SIGNATURE(op##_##ver){                               \
+            .opType = ANEURALNETWORKS_##op,                               \
+            .supportedDataTypes = {__VA_ARGS__},                          \
+            .supportedRanks = {1, 2, 3, 4},                               \
+            .version = HalVersion::ver,                                   \
+            .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32), \
+                       PARAMETER_CHOICE(Type::BOOL, true, false)},        \
+            .outputs = {OUTPUT_DEFAULT},                                  \
+            .constructor = reduceOpConstructor};
+
+DEFINE_REDUCE_SIGNATURE(REDUCE_ALL, V1_2, Type::TENSOR_BOOL8);
+DEFINE_REDUCE_SIGNATURE(REDUCE_ANY, V1_2, Type::TENSOR_BOOL8);
+DEFINE_REDUCE_SIGNATURE(REDUCE_PROD, V1_2, Type::TENSOR_FLOAT32, Type::TENSOR_FLOAT16);
+DEFINE_REDUCE_SIGNATURE(REDUCE_SUM, V1_2, Type::TENSOR_FLOAT32, Type::TENSOR_FLOAT16);
+DEFINE_REDUCE_SIGNATURE(REDUCE_MAX, V1_2, Type::TENSOR_FLOAT32, Type::TENSOR_FLOAT16,
+                        Type::TENSOR_QUANT8_ASYMM);
+DEFINE_REDUCE_SIGNATURE(REDUCE_MIN, V1_2, Type::TENSOR_FLOAT32, Type::TENSOR_FLOAT16,
+                        Type::TENSOR_QUANT8_ASYMM);
+
+static void singleAxisReduceOpConstructor(Type, uint32_t rank, RandomOperation* op) {
+    setFreeDimensions(op->inputs[0], rank);
+    // "axis" must be in the range [-rank, rank).
+    // Negative "axis" is used to specify axis from the end.
+    int32_t axis = getUniform<int32_t>(-rank, rank - 1);
+    op->inputs[1]->setScalarValue<int32_t>(axis);
+    for (uint32_t i = 0; i < rank; i++) {
+        if (i != static_cast<uint32_t>(axis) && i != axis + rank) {
+            op->outputs[0]->dimensions.emplace_back(op->inputs[0]->dimensions[i]);
+        }
+    }
+}
+
+#define DEFINE_ARGMIN_MAX_SIGNATURE(op, ver, ...)                                                  \
+    DEFINE_OPERATION_SIGNATURE(op##_##ver){                                                        \
+            .opType = ANEURALNETWORKS_##op,                                                        \
+            .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_FLOAT16, Type::TENSOR_INT32, \
+                                   Type::TENSOR_QUANT8_ASYMM},                                     \
+            .supportedRanks = {1, 2, 3, 4, 5},                                                     \
+            .version = HalVersion::ver,                                                            \
+            .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::INT32)},                                \
+            .outputs = {OUTPUT_TYPED(Type::TENSOR_INT32)},                                         \
+            .constructor = singleAxisReduceOpConstructor};
+
+DEFINE_ARGMIN_MAX_SIGNATURE(ARGMAX, V1_2);
+DEFINE_ARGMIN_MAX_SIGNATURE(ARGMIN, V1_2);
+
+}  // namespace fuzzing_test
+}  // namespace nn
+}  // namespace android