/* * 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 spaceToDepthConstructor(Type, uint32_t rank, RandomOperation* op) { NN_FUZZER_CHECK(rank == 4); bool useNchw = false; if (op->inputs.size() > 2) useNchw = op->inputs[2]->value<bool8>(); int heightIndex = useNchw ? 2 : 1; int widthIndex = useNchw ? 3 : 2; int depthIndex = useNchw ? 1 : 3; op->inputs[0]->dimensions = {RandomVariableType::FREE, RandomVariableType::FREE, RandomVariableType::FREE, RandomVariableType::FREE}; int32_t blockSize = op->inputs[1]->value<int32_t>(); auto outHeight = op->inputs[0]->dimensions[heightIndex].exactDiv(blockSize); auto outWidth = op->inputs[0]->dimensions[widthIndex].exactDiv(blockSize); auto outDepth = op->inputs[0]->dimensions[depthIndex] * (blockSize * blockSize); if (useNchw) { op->outputs[0]->dimensions = {op->inputs[0]->dimensions[0], outDepth, outHeight, outWidth}; } else { op->outputs[0]->dimensions = {op->inputs[0]->dimensions[0], outHeight, outWidth, outDepth}; } setSameQuantization(op->outputs[0], op->inputs[0]); } DEFINE_OPERATION_SIGNATURE(SPACE_TO_DEPTH_V1_0){ .opType = ANEURALNETWORKS_SPACE_TO_DEPTH, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {4}, .version = HalVersion::V1_0, .inputs = {INPUT_DEFAULT, PARAMETER_RANGE(Type::INT32, 1, 5)}, .outputs = {OUTPUT_DEFAULT}, .constructor = spaceToDepthConstructor}; DEFINE_OPERATION_SIGNATURE(SPACE_TO_DEPTH_V1_2){ .opType = ANEURALNETWORKS_SPACE_TO_DEPTH, .supportedDataTypes = {Type::TENSOR_FLOAT16}, .supportedRanks = {4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_RANGE(Type::INT32, 1, 5)}, .outputs = {OUTPUT_DEFAULT}, .constructor = spaceToDepthConstructor}; DEFINE_OPERATION_SIGNATURE(SPACE_TO_DEPTH_layout_V1_2){ .opType = ANEURALNETWORKS_SPACE_TO_DEPTH, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM, Type::TENSOR_FLOAT16}, .supportedRanks = {4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_RANGE(Type::INT32, 1, 5), PARAMETER_CHOICE(Type::BOOL, true, false)}, .outputs = {OUTPUT_DEFAULT}, .constructor = spaceToDepthConstructor}; static void depthToSpaceConstructor(Type, uint32_t rank, RandomOperation* op) { NN_FUZZER_CHECK(rank == 4); bool useNchw = false; if (op->inputs.size() > 2) useNchw = op->inputs[2]->value<bool8>(); int heightIndex = useNchw ? 2 : 1; int widthIndex = useNchw ? 3 : 2; int depthIndex = useNchw ? 1 : 3; op->inputs[0]->dimensions = {RandomVariableType::FREE, RandomVariableType::FREE, RandomVariableType::FREE, RandomVariableType::FREE}; int32_t blockSize = op->inputs[1]->value<int32_t>(); auto outHeight = op->inputs[0]->dimensions[heightIndex] * blockSize; auto outWidth = op->inputs[0]->dimensions[widthIndex] * blockSize; auto outDepth = op->inputs[0]->dimensions[depthIndex].exactDiv(blockSize * blockSize); if (useNchw) { op->outputs[0]->dimensions = {op->inputs[0]->dimensions[0], outDepth, outHeight, outWidth}; } else { op->outputs[0]->dimensions = {op->inputs[0]->dimensions[0], outHeight, outWidth, outDepth}; } setSameQuantization(op->outputs[0], op->inputs[0]); } DEFINE_OPERATION_SIGNATURE(DEPTH_TO_SPACE_V1_0){ .opType = ANEURALNETWORKS_DEPTH_TO_SPACE, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {4}, .version = HalVersion::V1_0, .inputs = {INPUT_DEFAULT, PARAMETER_RANGE(Type::INT32, 1, 3)}, .outputs = {OUTPUT_DEFAULT}, .constructor = depthToSpaceConstructor}; DEFINE_OPERATION_SIGNATURE(DEPTH_TO_SPACE_V1_2){ .opType = ANEURALNETWORKS_DEPTH_TO_SPACE, .supportedDataTypes = {Type::TENSOR_FLOAT16}, .supportedRanks = {4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_RANGE(Type::INT32, 1, 3)}, .outputs = {OUTPUT_DEFAULT}, .constructor = depthToSpaceConstructor}; DEFINE_OPERATION_SIGNATURE(DEPTH_TO_SPACE_layout_V1_2){ .opType = ANEURALNETWORKS_DEPTH_TO_SPACE, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM, Type::TENSOR_FLOAT16}, .supportedRanks = {4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_RANGE(Type::INT32, 1, 3), PARAMETER_CHOICE(Type::BOOL, true, false)}, .outputs = {OUTPUT_DEFAULT}, .constructor = depthToSpaceConstructor}; static void reshapeConstructor(Type, uint32_t rank, RandomOperation* op) { setFreeDimensions(op->inputs[0], rank); op->inputs[1]->dimensions = {rank}; op->inputs[1]->randomBuffer.resize(rank); RandomVariable numInputElements = 1; RandomVariable numOutputElements = 1; for (uint32_t i = 0; i < rank; i++) { op->inputs[1]->randomBuffer[i] = RandomVariableType::FREE; numInputElements = numInputElements * op->inputs[0]->dimensions[i]; numOutputElements = numOutputElements * op->inputs[1]->randomBuffer[i]; } numInputElements.setEqual(numOutputElements); op->outputs[0]->dimensions = op->inputs[1]->randomBuffer; setSameQuantization(op->outputs[0], op->inputs[0]); } DEFINE_OPERATION_SIGNATURE(RESHAPE_V1_0){ .opType = ANEURALNETWORKS_RESHAPE, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_0, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = reshapeConstructor}; DEFINE_OPERATION_SIGNATURE(RESHAPE_V1_2){ .opType = ANEURALNETWORKS_RESHAPE, .supportedDataTypes = {Type::TENSOR_FLOAT16}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = reshapeConstructor}; static void batchToSpaceConstructor(Type, uint32_t rank, RandomOperation* op) { NN_FUZZER_CHECK(rank == 4); bool useNchw = false; if (op->inputs.size() > 2) useNchw = op->inputs[2]->value<bool8>(); int heightIndex = useNchw ? 2 : 1; int widthIndex = useNchw ? 3 : 2; op->inputs[0]->dimensions = {RandomVariableType::FREE, RandomVariableType::FREE, RandomVariableType::FREE, RandomVariableType::FREE}; int32_t blockHeight = op->inputs[1]->value<int32_t>(0); int32_t blockWidth = op->inputs[1]->value<int32_t>(1); auto outBatch = op->inputs[0]->dimensions[0].exactDiv(blockHeight * blockWidth); auto outHeight = op->inputs[0]->dimensions[heightIndex] * blockHeight; auto outWidth = op->inputs[0]->dimensions[widthIndex] * blockWidth; if (useNchw) { op->outputs[0]->dimensions = {outBatch, op->inputs[0]->dimensions[1], outHeight, outWidth}; } else { op->outputs[0]->dimensions = {outBatch, outHeight, outWidth, op->inputs[0]->dimensions[3]}; } setSameQuantization(op->outputs[0], op->inputs[0]); } DEFINE_OPERATION_SIGNATURE(BATCH_TO_SPACE_ND_V1_1){ .opType = ANEURALNETWORKS_BATCH_TO_SPACE_ND, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {4}, .version = HalVersion::V1_1, .inputs = {INPUT_DEFAULT, PARAMETER_VEC_RANGE(Type::TENSOR_INT32, /*len=*/2, /*range=*/1, 3)}, .outputs = {OUTPUT_DEFAULT}, .constructor = batchToSpaceConstructor}; DEFINE_OPERATION_SIGNATURE(BATCH_TO_SPACE_ND_V1_2){ .opType = ANEURALNETWORKS_BATCH_TO_SPACE_ND, .supportedDataTypes = {Type::TENSOR_FLOAT16}, .supportedRanks = {4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_VEC_RANGE(Type::TENSOR_INT32, /*len=*/2, /*range=*/1, 3)}, .outputs = {OUTPUT_DEFAULT}, .constructor = batchToSpaceConstructor}; DEFINE_OPERATION_SIGNATURE(BATCH_TO_SPACE_ND_layout_V1_2){ .opType = ANEURALNETWORKS_BATCH_TO_SPACE_ND, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM, Type::TENSOR_FLOAT16}, .supportedRanks = {4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_VEC_RANGE(Type::TENSOR_INT32, /*len=*/2, /*range=*/1, 3), PARAMETER_CHOICE(Type::BOOL, true, false)}, .outputs = {OUTPUT_DEFAULT}, .constructor = batchToSpaceConstructor}; static void spaceToBatchConstructor(Type, uint32_t rank, RandomOperation* op) { NN_FUZZER_CHECK(rank == 4); bool useNchw = false; if (op->inputs.size() > 3) useNchw = op->inputs[3]->value<bool8>(); int heightIndex = useNchw ? 2 : 1; int widthIndex = useNchw ? 3 : 2; op->inputs[0]->dimensions = {RandomVariableType::FREE, RandomVariableType::FREE, RandomVariableType::FREE, RandomVariableType::FREE}; // Compute padded height and width. auto paddedHeight = op->inputs[0]->dimensions[heightIndex] + (op->inputs[2]->value<int32_t>(0) + op->inputs[2]->value<int32_t>(1)); auto paddedWidth = op->inputs[0]->dimensions[widthIndex] + (op->inputs[2]->value<int32_t>(2) + op->inputs[2]->value<int32_t>(3)); // blockHeight/blockWidth must be a divisor of padded height/width int32_t blockHeight = op->inputs[1]->value<int32_t>(0); int32_t blockWidth = op->inputs[1]->value<int32_t>(1); auto outBatch = op->inputs[0]->dimensions[0] * (blockHeight * blockWidth); auto outHeight = paddedHeight.exactDiv(blockHeight); auto outWidth = paddedWidth.exactDiv(blockWidth); if (useNchw) { op->outputs[0]->dimensions = {outBatch, op->inputs[0]->dimensions[1], outHeight, outWidth}; } else { op->outputs[0]->dimensions = {outBatch, outHeight, outWidth, op->inputs[0]->dimensions[3]}; } setSameQuantization(op->outputs[0], op->inputs[0]); } // The paddings tensor in SPACE_TOBATCH_ND, a [2, 2] tensor with value selected from [0, 10]. static const OperandSignature paddingTensor_SPACE_TO_BATCH_ND = { .type = RandomOperandType::CONST, .constructor = [](Type, uint32_t, RandomOperand* op) { op->dataType = Type::TENSOR_INT32; op->dimensions = {2, 2}; op->resizeBuffer<int32_t>(4); for (int i = 0; i < 4; i++) op->value<int32_t>(i) = getUniform<int32_t>(0, 10); }}; DEFINE_OPERATION_SIGNATURE(SPACE_TO_BATCH_ND_V1_1){ .opType = ANEURALNETWORKS_SPACE_TO_BATCH_ND, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {4}, .version = HalVersion::V1_1, .inputs = {INPUT_DEFAULT, PARAMETER_VEC_RANGE(Type::TENSOR_INT32, /*len=*/2, /*range=*/1, 5), paddingTensor_SPACE_TO_BATCH_ND}, .outputs = {OUTPUT_DEFAULT}, .constructor = spaceToBatchConstructor}; DEFINE_OPERATION_SIGNATURE(SPACE_TO_BATCH_ND_V1_2){ .opType = ANEURALNETWORKS_SPACE_TO_BATCH_ND, .supportedDataTypes = {Type::TENSOR_FLOAT16}, .supportedRanks = {4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_VEC_RANGE(Type::TENSOR_INT32, /*len=*/2, /*range=*/1, 5), paddingTensor_SPACE_TO_BATCH_ND}, .outputs = {OUTPUT_DEFAULT}, .constructor = spaceToBatchConstructor}; DEFINE_OPERATION_SIGNATURE(SPACE_TO_BATCH_ND_layout_V1_2){ .opType = ANEURALNETWORKS_SPACE_TO_BATCH_ND, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM, Type::TENSOR_FLOAT16}, .supportedRanks = {4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_VEC_RANGE(Type::TENSOR_INT32, /*len=*/2, /*range=*/1, 5), paddingTensor_SPACE_TO_BATCH_ND, PARAMETER_CHOICE(Type::BOOL, true, false)}, .outputs = {OUTPUT_DEFAULT}, .constructor = spaceToBatchConstructor}; static void padConstructor(Type, uint32_t rank, RandomOperation* op) { setFreeDimensions(op->inputs[0], rank); op->inputs[1]->dimensions = {rank, 2}; op->inputs[1]->resizeBuffer<int32_t>(rank * 2); op->outputs[0]->dimensions.resize(rank); for (uint32_t i = 0; i < rank; i++) { int32_t left = getUniform<int32_t>(0, 5), right = getUniform<int32_t>(0, 5); op->inputs[1]->value<int32_t>(i * 2) = left; op->inputs[1]->value<int32_t>(i * 2 + 1) = right; op->outputs[0]->dimensions[i] = op->inputs[0]->dimensions[i] + (left + right); } setSameQuantization(op->outputs[0], op->inputs[0]); } static const OperandSignature paddingScalar_PAD_V2 = { .type = RandomOperandType::CONST, .constructor = [](Type dataType, uint32_t, RandomOperand* op) { switch (dataType) { case Type::TENSOR_FLOAT32: op->dataType = Type::FLOAT32; op->setScalarValue<float>(getUniform<float>(-10.0f, 10.0f)); break; case Type::TENSOR_FLOAT16: op->dataType = Type::FLOAT16; op->setScalarValue<_Float16>(getUniform<_Float16>(-10.0f, 10.0f)); break; case Type::TENSOR_QUANT8_ASYMM: op->dataType = Type::INT32; op->setScalarValue<int32_t>(getUniform<int32_t>(0, 255)); break; default: NN_FUZZER_CHECK(false) << "Unsupported data type for PAD_V2"; } }}; DEFINE_OPERATION_SIGNATURE(PAD_V1_1){ .opType = ANEURALNETWORKS_PAD, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_1, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = padConstructor}; DEFINE_OPERATION_SIGNATURE(PAD_V1_2){.opType = ANEURALNETWORKS_PAD, .supportedDataTypes = {Type::TENSOR_FLOAT16}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = padConstructor}; DEFINE_OPERATION_SIGNATURE(PAD_V2_V1_2){ .opType = ANEURALNETWORKS_PAD_V2, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM, Type::TENSOR_FLOAT16}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32), paddingScalar_PAD_V2}, .outputs = {OUTPUT_DEFAULT}, .constructor = padConstructor}; static void transposeConstructor(Type, uint32_t rank, RandomOperation* op) { // Create the permutation value by randomly shuffling a sequential array. std::vector<int32_t> permutation(rank); std::iota(permutation.begin(), permutation.end(), 0); randomShuffle(&permutation); op->inputs[1]->resizeBuffer<int32_t>(rank); std::copy(permutation.begin(), permutation.end(), reinterpret_cast<int32_t*>(op->inputs[1]->buffer.data())); setFreeDimensions(op->inputs[0], rank); op->inputs[1]->dimensions = {rank}; op->outputs[0]->dimensions.resize(rank); for (uint32_t i = 0; i < rank; i++) { op->outputs[0]->dimensions[i] = op->inputs[0]->dimensions[permutation[i]]; } setSameQuantization(op->outputs[0], op->inputs[0]); } // TODO: Test the case when the second input is omitted. DEFINE_OPERATION_SIGNATURE(TRANSPOSE_V1_1){ .opType = ANEURALNETWORKS_TRANSPOSE, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_1, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = transposeConstructor}; DEFINE_OPERATION_SIGNATURE(TRANSPOSE_V1_2){ .opType = ANEURALNETWORKS_TRANSPOSE, .supportedDataTypes = {Type::TENSOR_FLOAT16}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = transposeConstructor}; static void channelShuffleConstructor(Type dataType, uint32_t rank, RandomOperation* op) { sameShapeOpConstructor(dataType, rank, op); // The number of groups must be a divisor of the target axis size. int32_t axis = getUniform<int32_t>(-rank, rank - 1); op->inputs[2]->setScalarValue<int32_t>(axis); int32_t numGroups = op->inputs[1]->value<int32_t>(); if (axis < 0) axis += rank; (op->inputs[0]->dimensions[axis] % numGroups).setEqual(0); } DEFINE_OPERATION_SIGNATURE(CHANNEL_SHUFFLE_V1_2){ .opType = ANEURALNETWORKS_CHANNEL_SHUFFLE, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM, Type::TENSOR_FLOAT16}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_RANGE(Type::INT32, 1, 5), PARAMETER_NONE(Type::INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = channelShuffleConstructor}; static void squeezeConstructor(Type, uint32_t rank, RandomOperation* op) { // A boolean array indicating whether each dimension is selected to be squeezed. bool squeeze[4] = {false, false, false, false}; 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++) { // Generate values for the "axis" tensor. int32_t dim = getUniform<int32_t>(0, rank - 1); op->inputs[1]->value<int32_t>(i) = dim; squeeze[dim] = true; } op->inputs[0]->dimensions.resize(rank); for (uint32_t i = 0; i < rank; i++) { if (squeeze[i]) { op->inputs[0]->dimensions[i] = 1; } else { op->inputs[0]->dimensions[i] = RandomVariableType::FREE; op->outputs[0]->dimensions.emplace_back(op->inputs[0]->dimensions[i]); } } setSameQuantization(op->outputs[0], op->inputs[0]); } // TODO: Test the case when the second input is omitted. DEFINE_OPERATION_SIGNATURE(SQUEEZE_V1_1){ .opType = ANEURALNETWORKS_SQUEEZE, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_1, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = squeezeConstructor}; DEFINE_OPERATION_SIGNATURE(SQUEEZE_V1_2){ .opType = ANEURALNETWORKS_SQUEEZE, .supportedDataTypes = {Type::TENSOR_FLOAT16}, .supportedRanks = {1, 2, 3, 4}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = squeezeConstructor}; static void expandDimsConstructor(Type, uint32_t rank, RandomOperation* op) { // Generate values for the "axis" tensor. int32_t axis = getUniform<int32_t>(-rank - 1, rank); op->inputs[1]->setScalarValue<int32_t>(axis); if (axis < 0) axis += rank + 1; setFreeDimensions(op->inputs[0], rank); for (uint32_t i = 0; i < rank; i++) { if (i == static_cast<uint32_t>(axis)) { op->outputs[0]->dimensions.push_back(1); } op->outputs[0]->dimensions.push_back(op->inputs[0]->dimensions[i]); } if (rank == static_cast<uint32_t>(axis)) op->outputs[0]->dimensions.push_back(1); setSameQuantization(op->outputs[0], op->inputs[0]); } DEFINE_OPERATION_SIGNATURE(EXPAND_DIMS_V1_2){ .opType = ANEURALNETWORKS_EXPAND_DIMS, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_FLOAT16, Type::TENSOR_INT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {1, 2, 3, 4, 5}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = expandDimsConstructor}; static void tileConstructor(Type, uint32_t rank, RandomOperation* op) { setFreeDimensions(op->inputs[0], rank); op->outputs[0]->dimensions.resize(rank); op->inputs[1]->dimensions = {rank}; op->inputs[1]->resizeBuffer<int32_t>(rank); for (uint32_t i = 0; i < rank; i++) { int32_t multiple = getUniform<int32_t>(1, 5); op->inputs[1]->value<int32_t>(i) = multiple; op->outputs[0]->dimensions[i] = op->inputs[0]->dimensions[i] * multiple; } setSameQuantization(op->outputs[0], op->inputs[0]); } DEFINE_OPERATION_SIGNATURE(TILE_V1_2){ .opType = ANEURALNETWORKS_TILE, .supportedDataTypes = {Type::TENSOR_FLOAT32, Type::TENSOR_FLOAT16, Type::TENSOR_INT32, Type::TENSOR_QUANT8_ASYMM}, .supportedRanks = {1, 2, 3, 4, 5}, .version = HalVersion::V1_2, .inputs = {INPUT_DEFAULT, PARAMETER_NONE(Type::TENSOR_INT32)}, .outputs = {OUTPUT_DEFAULT}, .constructor = tileConstructor}; } // namespace fuzzing_test } // namespace nn } // namespace android