Revert "Update validation in runtime (#1351)" (#1406)
author서상민/동작제어Lab(SR)/Senior Engineer/삼성전자 <sangmin7.seo@samsung.com>
Tue, 29 May 2018 05:51:07 +0000 (14:51 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Tue, 29 May 2018 05:51:07 +0000 (14:51 +0900)
This reverts commit 86bbecea1fce90cac87a40782900eb24ff09db95.

PR #1351 caused many test failures, which were not noticed by our CI.

Signed-off-by: Sangmin Seo <sangmin7.seo@samsung.com>
runtimes/nn/common/CMakeLists.txt
runtimes/nn/common/Utils.cpp
runtimes/nn/common/ValidateHal.cpp [deleted file]
runtimes/nn/common/include/Utils.h
runtimes/nn/common/include/ValidateHal.h [deleted file]
runtimes/nn/runtime/ModelBuilder.cpp

index f5c51d5..428b924 100644 (file)
@@ -13,7 +13,6 @@ SET (CUR_SRCS
      ${CMAKE_CURRENT_SOURCE_DIR}/CpuExecutor.cpp
      ${CMAKE_CURRENT_SOURCE_DIR}/OperationsUtils.cpp
      ${CMAKE_CURRENT_SOURCE_DIR}/Utils.cpp
-     ${CMAKE_CURRENT_SOURCE_DIR}/ValidateHal.cpp
      ${CMAKE_CURRENT_SOURCE_DIR}/NNFWKernels.cpp
      ${CMAKE_CURRENT_SOURCE_DIR}/operations/Activation.cpp
      ${CMAKE_CURRENT_SOURCE_DIR}/operations/Conv2D.cpp
index 31c48f9..c83ee53 100644 (file)
@@ -319,1121 +319,171 @@ int validateOperandList(uint32_t count, const uint32_t *list, uint32_t operandCo
   return ANEURALNETWORKS_NO_ERROR;
 }
 
-int validateOperationOperandTypes(const std::vector<Operand> &operands, uint32_t inOperandCount,
-                                  const uint32_t *inOperandIndexes,
-                                  const std::vector<OperandType> &inExpectedTypes,
-                                  uint32_t outOperandCount, const uint32_t *outOperandIndexes,
-                                  const std::vector<OperandType> &outExpectedInTypes)
+static bool validOperandIndexes(const hidl_vec<uint32_t> indexes, size_t operandCount)
 {
-  if (inOperandCount > static_cast<uint32_t>(inExpectedTypes.size()) ||
-      outOperandCount > static_cast<uint32_t>(outExpectedInTypes.size()))
+  for (uint32_t i : indexes)
   {
-    return ANEURALNETWORKS_BAD_DATA;
-  }
-  for (uint32_t i = 0; i < inOperandCount; i++)
-  {
-    if (operands[inOperandIndexes[i]].type != inExpectedTypes[i])
-    {
-      LOG(ERROR) << "Invalid input tensor type " << toString(operands[inOperandIndexes[i]].type)
-                 << " for input " << i << ", expected " << toString(inExpectedTypes[i]);
-      return ANEURALNETWORKS_BAD_DATA;
-    }
-  }
-  for (uint32_t i = 0; i < outOperandCount; i++)
-  {
-    if (operands[outOperandIndexes[i]].type != outExpectedInTypes[i])
+    if (i >= operandCount)
     {
-      LOG(ERROR) << "Invalid output tensor type " << toString(operands[outOperandIndexes[i]].type)
-                 << " for input " << i << ", expected " << toString(outExpectedInTypes[i]);
-      return ANEURALNETWORKS_BAD_DATA;
+      LOG(ERROR) << "Index out of range " << i << "/" << operandCount;
+      return false;
     }
   }
-
-  return ANEURALNETWORKS_NO_ERROR;
+  return true;
 }
 
-int validateOperation(OperationType opType, uint32_t inputCount, const uint32_t *inputIndexes,
-                      uint32_t outputCount, const uint32_t *outputIndexes,
-                      const std::vector<Operand> &operands)
+static bool validOperands(const hidl_vec<Operand> &operands, const hidl_vec<uint8_t> &operandValues,
+                          size_t poolCount)
 {
-  int opTypeVal = toUnderlying(opType);
-
-  int n = validateOperandList(inputCount, inputIndexes, static_cast<uint32_t>(operands.size()),
-                              "ANeuralNetworksModel_addOperation inputs");
-  if (n != ANEURALNETWORKS_NO_ERROR)
+  for (auto &operand : operands)
   {
-    return n;
-  }
-  n = validateOperandList(outputCount, outputIndexes, static_cast<uint32_t>(operands.size()),
-                          "ANeuralNetworksModel_addOperation outputs");
-  if (n != ANEURALNETWORKS_NO_ERROR)
-  {
-    return n;
-  }
-
-  auto logInvalidInOutNumber = [opTypeVal, inputCount, outputCount](int expIn, int expOut) {
-    LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected " << expIn
-               << ") or output operands (" << outputCount << ", expected " << expOut
-               << ") for operation " << kOperationNames[opTypeVal];
-  };
-
-  switch (opType)
-  {
-    case OperationType::ADD:
+    if (!validCode(kNumberOfDataTypes, kNumberOfDataTypesOEM, static_cast<uint32_t>(operand.type)))
     {
-      if (inputCount != 3 || outputCount != 1)
-      {
-        logInvalidInOutNumber(3, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::MUL:
-    {
-      if (inputCount != 3 || outputCount != 1)
-      {
-        logInvalidInOutNumber(3, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
+      LOG(ERROR) << "Invalid operand type ";
+      return false;
     }
-    case OperationType::FLOOR:
-    {
-      if (inputCount != 1 || outputCount != 1)
-      {
-        logInvalidInOutNumber(1, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
+    /* TODO validate dim with type
+    if (!validOperandIndexes(operand.dimensions, mDimensions)) {
+        return false;
     }
-    case OperationType::DEQUANTIZE:
+    */
+    switch (operand.lifetime)
     {
-      if (inputCount != 1 || outputCount != 1)
-      {
-        logInvalidInOutNumber(1, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
+      case OperandLifeTime::CONSTANT_COPY:
+        if (operand.location.offset + operand.location.length > operandValues.size())
+        {
+          LOG(ERROR) << "OperandValue location out of range.  Starts at " << operand.location.offset
+                     << ", length " << operand.location.length << ", max " << operandValues.size();
+          return false;
+        }
+        break;
+      case OperandLifeTime::TEMPORARY_VARIABLE:
+      case OperandLifeTime::MODEL_INPUT:
+      case OperandLifeTime::MODEL_OUTPUT:
+      case OperandLifeTime::NO_VALUE:
+        if (operand.location.offset != 0 || operand.location.length != 0)
+        {
+          LOG(ERROR) << "Unexpected offset " << operand.location.offset << " or length "
+                     << operand.location.length << " for runtime location.";
+          return false;
+        }
+        break;
+      case OperandLifeTime::CONSTANT_REFERENCE:
+        if (operand.location.poolIndex >= poolCount)
+        {
+          LOG(ERROR) << "Invalid poolIndex " << operand.location.poolIndex << "/" << poolCount;
+          return false;
+        }
+        break;
+      // TODO: Validate that we are within the pool.
+      default:
+        LOG(ERROR) << "Invalid lifetime";
+        return false;
     }
-    case OperationType::DEPTHWISE_CONV_2D:
-    {
-      if ((inputCount != 11 && inputCount != 8) || outputCount != 1)
-      {
-        LOG(ERROR) << "Invalid number of input operands (" << inputCount
-                   << ", expected 11 or 8) or output operands (" << outputCount
-                   << ", expected 1) for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-                           OperandType::TENSOR_FLOAT32, OperandType::INT32,
-                           OperandType::INT32,          OperandType::INT32,
-                           OperandType::INT32,          OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::TENSOR_INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
+  }
+  return true;
+}
 
-      if (inputCount == 11)
-      {
-        std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32);
-        inExpectedTypes.insert(inExpectedTypes.end(), explicitScalarTypes.begin(),
-                               explicitScalarTypes.end());
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::CONV_2D:
+static bool validOperations(const hidl_vec<Operation> &operations, size_t operandCount)
+{
+  for (auto &op : operations)
+  {
+    if (!validCode(kNumberOfOperationTypes, kNumberOfOperationTypesOEM, kNumberOfOperationTypesEx,
+                   static_cast<uint32_t>(op.type)))
     {
-      if ((inputCount != 10 && inputCount != 7) || outputCount != 1)
-      {
-        LOG(ERROR) << "Invalid number of input operands (" << inputCount
-                   << ", expected 10 or 7) or output operands (" << outputCount
-                   << ", expected 1) for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-                           OperandType::TENSOR_FLOAT32, OperandType::INT32,
-                           OperandType::INT32,          OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::TENSOR_INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-
-      if (inputCount == 10)
-      {
-        std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32);
-        inExpectedTypes.insert(inExpectedTypes.end(), explicitScalarTypes.begin(),
-                               explicitScalarTypes.end());
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
+      LOG(ERROR) << "Invalid operation type ";
+      return false;
     }
-    case OperationType::AVERAGE_POOL_2D:
+    if (!validOperandIndexes(op.inputs, operandCount) ||
+        !validOperandIndexes(op.outputs, operandCount))
     {
-      if ((inputCount != 10 && inputCount != 7) || outputCount != 1)
-      {
-        LOG(ERROR) << "Invalid number of input operands (" << inputCount
-                   << ", expected 10 or 7) or output operands (" << outputCount
-                   << ", expected 1) for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::INT32, OperandType::INT32,
-                           OperandType::INT32,          OperandType::INT32, OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-
-      if (inputCount == 10)
-      {
-        std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32);
-        inExpectedTypes.insert(inExpectedTypes.end(), explicitScalarTypes.begin(),
-                               explicitScalarTypes.end());
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
+      return false;
     }
-    case OperationType::L2_POOL_2D:
-    {
-      if ((inputCount != 10 && inputCount != 7) || outputCount != 1)
-      {
-        LOG(ERROR) << "Invalid number of input operands (" << inputCount
-                   << ", expected 10 or 7) or output operands (" << outputCount
-                   << ", expected 1) for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::INT32, OperandType::INT32,
-                           OperandType::INT32,          OperandType::INT32, OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
+  }
+  return true;
+}
 
-      if (inputCount == 10)
-      {
-        std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32);
-        inExpectedTypes.insert(inExpectedTypes.end(), explicitScalarTypes.begin(),
-                               explicitScalarTypes.end());
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::MAX_POOL_2D:
-    {
-      if ((inputCount != 10 && inputCount != 7) || outputCount != 1)
-      {
-        LOG(ERROR) << "Invalid number of input operands (" << inputCount
-                   << ", expected 10 or 7) or output operands (" << outputCount
-                   << ", expected 1) for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::INT32, OperandType::INT32,
-                           OperandType::INT32,          OperandType::INT32, OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
+// TODO doublecheck
+bool validateModel(const Model &model)
+{
+  const size_t operandCount = model.operands.size();
+  return (validOperands(model.operands, model.operandValues, model.pools.size()) &&
+          validOperations(model.operations, operandCount) &&
+          validOperandIndexes(model.inputIndexes, operandCount) &&
+          validOperandIndexes(model.outputIndexes, operandCount));
+}
 
-      if (inputCount == 10)
-      {
-        std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32);
-        inExpectedTypes.insert(inExpectedTypes.end(), explicitScalarTypes.begin(),
-                               explicitScalarTypes.end());
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::RELU:
-    {
-      if (inputCount != 1 || outputCount != 1)
-      {
-        logInvalidInOutNumber(1, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::RELU1:
-    {
-      if (inputCount != 1 || outputCount != 1)
-      {
-        logInvalidInOutNumber(1, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::RELU6:
-    {
-      if (inputCount != 1 || outputCount != 1)
-      {
-        logInvalidInOutNumber(1, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::TANH:
-    {
-      if (inputCount != 1 || outputCount != 1)
-      {
-        logInvalidInOutNumber(1, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::LOGISTIC:
-    {
-      if (inputCount != 1 || outputCount != 1)
-      {
-        logInvalidInOutNumber(1, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::SOFTMAX:
-    {
-      if (inputCount != 2 || outputCount != 1)
-      {
-        logInvalidInOutNumber(2, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, OperandType::FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::FULLY_CONNECTED:
-    {
-      if (inputCount != 4 || outputCount != 1)
-      {
-        logInvalidInOutNumber(4, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-                           OperandType::TENSOR_FLOAT32, OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::TENSOR_INT32, OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::CONCATENATION:
-    {
-      if (inputCount < 2 || outputCount != 1)
-      {
-        LOG(ERROR) << "Invalid number of input operands (" << inputCount
-                   << ", expected at least 2) or output operands (" << outputCount
-                   << ", expected 1) for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes(inputCount, inputType);
-      std::vector<OperandType> outExpectedTypes = {inputType};
-      // The last one is the activation function.
-      inExpectedTypes.back() = OperandType::INT32;
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::L2_NORMALIZATION:
-    {
-      if (inputCount != 1 || outputCount != 1)
-      {
-        logInvalidInOutNumber(1, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::LOCAL_RESPONSE_NORMALIZATION:
-    {
-      if (inputCount != 5 || outputCount != 1)
-      {
-        logInvalidInOutNumber(5, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::INT32, OperandType::FLOAT32,
-                           OperandType::FLOAT32, OperandType::FLOAT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::RESHAPE:
-    {
-      if (inputCount != 2 || outputCount != 1)
-      {
-        logInvalidInOutNumber(2, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::RESIZE_BILINEAR:
-    {
-      if (inputCount != 3 || outputCount != 1)
-      {
-        logInvalidInOutNumber(3, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::INT32, OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::DEPTH_TO_SPACE:
-    {
-      if (inputCount != 2 || outputCount != 1)
-      {
-        logInvalidInOutNumber(2, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::SPACE_TO_DEPTH:
-    {
-      if (inputCount != 2 || outputCount != 1)
-      {
-        logInvalidInOutNumber(2, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::EMBEDDING_LOOKUP:
-    {
-      if (inputCount != 2 || outputCount != 1)
-      {
-        logInvalidInOutNumber(2, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[1]].type;
-      std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_INT32, inputType};
-      std::vector<OperandType> outExpectedTypes = {inputType};
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::HASHTABLE_LOOKUP:
-    {
-      if (inputCount != 3 || outputCount != 2)
-      {
-        logInvalidInOutNumber(3, 2);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[2]].type;
-      std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_INT32,
-                                                  OperandType::TENSOR_INT32, inputType};
-      std::vector<OperandType> outExpectedTypes = {inputType, OperandType::TENSOR_QUANT8_ASYMM};
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::LSH_PROJECTION:
+bool validRequestArguments(const hidl_vec<RequestArgument> &arguments,
+                           const hidl_vec<uint32_t> &operandIndexes,
+                           const hidl_vec<Operand> &operands, size_t poolCount, const char *type)
+{
+  const size_t argumentCount = arguments.size();
+  if (argumentCount != operandIndexes.size())
+  {
+    LOG(ERROR) << "Request specifies " << argumentCount << " " << type << "s but the model has "
+               << operandIndexes.size();
+    return false;
+  }
+  for (size_t argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++)
+  {
+    const RequestArgument &argument = arguments[argumentIndex];
+    const uint32_t operandIndex = operandIndexes[argumentIndex];
+    const Operand &operand = operands[operandIndex];
+    if (argument.hasNoValue)
     {
-      if (inputCount != 4 || outputCount != 1)
+      if (argument.location.poolIndex != 0 || argument.location.offset != 0 ||
+          argument.location.length != 0 || argument.dimensions.size() != 0)
       {
-        logInvalidInOutNumber(4, 1);
-        return ANEURALNETWORKS_BAD_DATA;
+        LOG(ERROR) << "Request " << type << " " << argumentIndex
+                   << " has no value yet has details.";
+        return false;
       }
-      auto inputType = operands[inputIndexes[1]].type;
-      std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_FLOAT32, inputType,
-                                                  OperandType::TENSOR_FLOAT32, OperandType::INT32};
-      std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_INT32};
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
     }
-    case OperationType::LSTM:
+    if (argument.location.poolIndex >= poolCount)
     {
-      if (inputCount != 23 || outputCount != 4)
-      {
-        logInvalidInOutNumber(23, 4);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      std::vector<OperandType> inExpectedTypes = {
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::INT32,
-          OperandType::FLOAT32,        OperandType::FLOAT32};
-      std::vector<OperandType> outExpectedTypes = {
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32};
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
+      LOG(ERROR) << "Request " << type << " " << argumentIndex << " has an invalid poolIndex "
+                 << argument.location.poolIndex << "/" << poolCount;
+      return false;
     }
-    case OperationType::RNN:
+    // TODO: Validate that we are within the pool.
+    uint32_t rank = argument.dimensions.size();
+    if (rank > 0)
     {
-      if (inputCount != 6 || outputCount != 2)
+      if (rank != operand.dimensions.size())
       {
-        logInvalidInOutNumber(6, 2);
-        return ANEURALNETWORKS_BAD_DATA;
+        LOG(ERROR) << "Request " << type << " " << argumentIndex << " has number of dimensions ("
+                   << rank << ") different than the model's (" << operand.dimensions.size() << ")";
+        return false;
       }
-      std::vector<OperandType> inExpectedTypes = {
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::INT32};
-      std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_FLOAT32,
-                                                   OperandType::TENSOR_FLOAT32};
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::SVDF:
-    {
-      if (inputCount != 7 || outputCount != 2)
+      for (size_t i = 0; i < rank; i++)
       {
-        logInvalidInOutNumber(7, 2);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      std::vector<OperandType> inExpectedTypes = {
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-          OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32, OperandType::INT32,
-          OperandType::INT32};
-      std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_FLOAT32,
-                                                   OperandType::TENSOR_FLOAT32};
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-#if 0  // REF-ANN
-        case OperationType::BATCH_TO_SPACE_ND: {
-            if (inputCount != 2 || outputCount != 1) {
-                logInvalidInOutNumber(2, 1);
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            auto inputType = operands[inputIndexes[0]].type;
-            std::vector<OperandType> inExpectedTypes;
-            std::vector<OperandType> outExpectedTypes;
-            if (inputType == OperandType::TENSOR_FLOAT32) {
-                inExpectedTypes = {OperandType::TENSOR_FLOAT32,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-            } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
-                inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-            } else {
-                LOG(ERROR) << "Unsupported input tensor type for operation "
-                           << kOperationNames[opTypeVal];
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            return validateOperationOperandTypes(operands,
-                                                 inputCount, inputIndexes,
-                                                 inExpectedTypes,
-                                                 outputCount, outputIndexes,
-                                                 outExpectedTypes);
-        }
-        case OperationType::SPACE_TO_BATCH_ND: {
-            if (inputCount != 3 || outputCount != 1) {
-                logInvalidInOutNumber(3, 1);
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            auto inputType = operands[inputIndexes[0]].type;
-            std::vector<OperandType> inExpectedTypes;
-            std::vector<OperandType> outExpectedTypes;
-            if (inputType == OperandType::TENSOR_FLOAT32) {
-                inExpectedTypes = {OperandType::TENSOR_FLOAT32,
-                                   OperandType::TENSOR_INT32,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-            } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
-                inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                                   OperandType::TENSOR_INT32,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-            } else {
-                LOG(ERROR) << "Unsupported input tensor type for operation "
-                           << kOperationNames[opTypeVal];
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            return validateOperationOperandTypes(operands,
-                                                 inputCount, inputIndexes,
-                                                 inExpectedTypes,
-                                                 outputCount, outputIndexes,
-                                                 outExpectedTypes);
-        }
-        case OperationType::PAD: {
-            if (inputCount != 2 || outputCount != 1) {
-                logInvalidInOutNumber(2, 1);
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            auto inputType = operands[inputIndexes[0]].type;
-            std::vector<OperandType> inExpectedTypes;
-            std::vector<OperandType> outExpectedTypes;
-            if (inputType == OperandType::TENSOR_FLOAT32) {
-                inExpectedTypes = {OperandType::TENSOR_FLOAT32,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-            } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
-                inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-            } else {
-                LOG(ERROR) << "Unsupported input tensor type for operation "
-                           << kOperationNames[opTypeVal];
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            return validateOperationOperandTypes(operands,
-                                                 inputCount, inputIndexes,
-                                                 inExpectedTypes,
-                                                 outputCount, outputIndexes,
-                                                 outExpectedTypes);
+        if (argument.dimensions[i] != operand.dimensions[i] && operand.dimensions[i] != 0)
+        {
+          LOG(ERROR) << "Request " << type << " " << argumentIndex << " has dimension " << i
+                     << " of " << operand.dimensions[i] << " different than the model's "
+                     << operand.dimensions[i];
+          return false;
         }
-        case OperationType::SQUEEZE: {
-            if (inputCount != 2 || outputCount != 1) {
-                logInvalidInOutNumber(2, 1);
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            auto inputType = operands[inputIndexes[0]].type;
-            std::vector<OperandType> inExpectedTypes;
-            std::vector<OperandType> outExpectedTypes;
-            if (inputType == OperandType::TENSOR_FLOAT32) {
-                inExpectedTypes = {OperandType::TENSOR_FLOAT32,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-            } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
-                inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-            } else {
-                LOG(ERROR) << "Unsupported input tensor type for operation "
-                           << kOperationNames[opTypeVal];
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            return validateOperationOperandTypes(operands,
-                                                 inputCount, inputIndexes,
-                                                 inExpectedTypes,
-                                                 outputCount, outputIndexes,
-                                                 outExpectedTypes);
+        if (argument.dimensions[i] == 0)
+        {
+          LOG(ERROR) << "Request " << type << " " << argumentIndex << " has dimension " << i
+                     << " of zero";
+          return false;
         }
-        case OperationType::TRANSPOSE: {
-            if (inputCount != 2 || outputCount != 1) {
-                logInvalidInOutNumber(2, 1);
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            auto inputType = operands[inputIndexes[0]].type;
-            std::vector<OperandType> inExpectedTypes;
-            std::vector<OperandType> outExpectedTypes;
-            if (inputType == OperandType::TENSOR_FLOAT32) {
-                inExpectedTypes = {OperandType::TENSOR_FLOAT32,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-            } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
-                inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                                   OperandType::TENSOR_INT32};
-                outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-            } else {
-                LOG(ERROR) << "Unsupported input tensor type for operation "
-                           << kOperationNames[opTypeVal];
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            return validateOperationOperandTypes(operands,
-                                                 inputCount, inputIndexes,
-                                                 inExpectedTypes,
-                                                 outputCount, outputIndexes,
-                                                 outExpectedTypes);
-        }
-#endif // REF-ANN
-    case OperationType::STRIDED_SLICE:
-    {
-      if (inputCount != 7 || outputCount != 1)
-      {
-        logInvalidInOutNumber(7, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_INT32,
-                           OperandType::TENSOR_INT32,   OperandType::TENSOR_INT32,
-                           OperandType::INT32,          OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else if (inputType == OperandType::TENSOR_QUANT8_ASYMM)
-      {
-        inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                           OperandType::TENSOR_INT32,
-                           OperandType::TENSOR_INT32,
-                           OperandType::TENSOR_INT32,
-                           OperandType::INT32,
-                           OperandType::INT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::DIV:
-    {
-      if (inputCount != 3 || outputCount != 1)
-      {
-        logInvalidInOutNumber(3, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-      }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-    case OperationType::SUB:
-    {
-      if (inputCount != 3 || outputCount != 1)
-      {
-        logInvalidInOutNumber(3, 1);
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      auto inputType = operands[inputIndexes[0]].type;
-      std::vector<OperandType> inExpectedTypes;
-      std::vector<OperandType> outExpectedTypes;
-      if (inputType == OperandType::TENSOR_FLOAT32)
-      {
-        inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
-                           OperandType::INT32};
-        outExpectedTypes = {OperandType::TENSOR_FLOAT32};
       }
-      else
-      {
-        LOG(ERROR) << "Unsupported input tensor type for operation " << kOperationNames[opTypeVal];
-        return ANEURALNETWORKS_BAD_DATA;
-      }
-      return validateOperationOperandTypes(operands, inputCount, inputIndexes, inExpectedTypes,
-                                           outputCount, outputIndexes, outExpectedTypes);
-    }
-#if 0  // REF-ANN
-        case OperationType::MEAN: {
-            if (inputCount != 3 || outputCount != 1) {
-                logInvalidInOutNumber(3, 1);
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            auto inputType = operands[inputIndexes[0]].type;
-            std::vector<OperandType> inExpectedTypes;
-            std::vector<OperandType> outExpectedTypes;
-            if (inputType == OperandType::TENSOR_FLOAT32) {
-                inExpectedTypes = {OperandType::TENSOR_FLOAT32,
-                                   OperandType::TENSOR_INT32,
-                                   OperandType::INT32};
-                outExpectedTypes = {OperandType::TENSOR_FLOAT32};
-            } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
-                inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
-                                   OperandType::TENSOR_INT32,
-                                   OperandType::INT32};
-                outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
-            } else {
-                LOG(ERROR) << "Unsupported input tensor type for operation "
-                           << kOperationNames[opTypeVal];
-                return ANEURALNETWORKS_BAD_DATA;
-            }
-            return validateOperationOperandTypes(operands,
-                                                 inputCount, inputIndexes,
-                                                 inExpectedTypes,
-                                                 outputCount, outputIndexes,
-                                                 outExpectedTypes);
-        }
-#endif // REF-ANN
-    case OperationType::CAST:
-    {
-      // TODO-NNRT : implement validation this operation.
-    }
-    case OperationType::GATHER:
-    {
-      // TODO-NNRT : implement validation this operation.
     }
-    case OperationType::TOPK_V2:
-    {
-      // TODO-NNRT : implement validation this operation.
-    }
-    case OperationType::TENSORFLOW_MAX:
-    {
-      // TODO-NNRT : implement validation of this operation.
-    }
-    default:
-      return ANEURALNETWORKS_BAD_DATA;
   }
+  return true;
+}
+
+// TODO doublecheck
+bool validateRequest(const Request &request, const Model &model)
+{
+  const size_t poolCount = request.pools.size();
+  return (validRequestArguments(request.inputs, model.inputIndexes, model.operands, poolCount,
+                                "input") &&
+          validRequestArguments(request.outputs, model.outputIndexes, model.operands, poolCount,
+                                "output"));
 }
 
 } // namespace rt
diff --git a/runtimes/nn/common/ValidateHal.cpp b/runtimes/nn/common/ValidateHal.cpp
deleted file mode 100644 (file)
index 2645e56..0000000
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
- * Copyright (C) 2017 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.
- */
-
-#define LOG_TAG "ValidateHal"
-
-#include "ValidateHal.h"
-#include "NeuralNetworks.h"
-#include "Utils.h"
-
-#include "Logging.h"
-
-namespace nnfw
-{
-namespace rt
-{
-
-class MemoryAccessVerifier
-{
-public:
-  MemoryAccessVerifier(const hidl_vec<hidl_memory> &pools)
-      : mPoolCount(pools.size()), mPoolSizes(mPoolCount)
-  {
-    for (size_t i = 0; i < mPoolCount; i++)
-    {
-      mPoolSizes[i] = pools[i].size();
-    }
-  }
-  bool validate(const DataLocation &location)
-  {
-    if (location.poolIndex >= mPoolCount)
-    {
-      LOG(ERROR) << "Invalid poolIndex " << location.poolIndex << "/" << mPoolCount;
-      return false;
-    }
-    const size_t size = mPoolSizes[location.poolIndex];
-    // Do the addition using size_t to avoid potential wrap-around problems.
-    if (static_cast<size_t>(location.offset) + location.length > size)
-    {
-      LOG(ERROR) << "Reference to pool " << location.poolIndex << " with offset " << location.offset
-                 << " and length " << location.length << " exceeds pool size of " << size;
-      return false;
-    }
-    return true;
-  }
-
-private:
-  size_t mPoolCount;
-  std::vector<size_t> mPoolSizes;
-};
-
-static bool validateOperands(const hidl_vec<Operand> &operands,
-                             const hidl_vec<uint8_t> &operandValues,
-                             const hidl_vec<hidl_memory> &pools)
-{
-  uint32_t index = 0;
-  MemoryAccessVerifier poolVerifier(pools);
-  for (auto &operand : operands)
-  {
-    // Validate type and dimensions.
-    switch (operand.type)
-    {
-      case OperandType::FLOAT32:
-      case OperandType::INT32:
-      case OperandType::UINT32:
-      case OperandType::OEM:
-      {
-        size_t count = operand.dimensions.size();
-        if (count != 0)
-        {
-          LOG(ERROR) << "Operand " << index << ": Scalar data has dimensions of rank " << count;
-          return false;
-        }
-        break;
-      }
-      case OperandType::TENSOR_FLOAT32:
-      case OperandType::TENSOR_INT32:
-      case OperandType::TENSOR_QUANT8_ASYMM:
-      case OperandType::TENSOR_OEM_BYTE:
-      {
-        if (operand.dimensions.size() == 0)
-        {
-          LOG(ERROR) << "Operand " << index << ": Tensor has dimensions of rank 0";
-          return false;
-        }
-        break;
-      }
-      default:
-        LOG(ERROR) << "Operand " << index << ": Invalid operand type " << toString(operand.type);
-        return false;
-    }
-
-    // TODO Validate the numberOfConsumers.
-    // TODO Since we have to validate it, there was no point in including it. For the next
-    // release, consider removing unless we have an additional process in system space
-    // that creates this value. In that case, it would not have to be validated.
-
-    // Validate the scale.
-    switch (operand.type)
-    {
-      case OperandType::FLOAT32:
-      case OperandType::INT32:
-      case OperandType::UINT32:
-      case OperandType::TENSOR_FLOAT32:
-        if (operand.scale != 0.f)
-        {
-          LOG(ERROR) << "Operand " << index << ": Operand of type "
-                     << getOperandTypeName(operand.type) << " with a non-zero scale ("
-                     << operand.scale << ")";
-          return false;
-        }
-        break;
-      case OperandType::TENSOR_INT32:
-        // TENSOR_INT32 may be used with or without scale, depending on the operation.
-        if (operand.scale < 0.f)
-        {
-          LOG(ERROR) << "Operand " << index << ": Operand of type "
-                     << getOperandTypeName(operand.type) << " with a negative scale";
-          return false;
-        }
-        break;
-      case OperandType::TENSOR_QUANT8_ASYMM:
-        if (operand.scale <= 0.f)
-        {
-          LOG(ERROR) << "Operand " << index << ": Operand of type "
-                     << getOperandTypeName(operand.type) << " with a non-positive scale";
-          return false;
-        }
-        break;
-      default:
-        // No validation for the OEM types.
-        // TODO We should have had a separate type for TENSOR_INT32 that a scale
-        // and those who don't.  Document now and fix in the next release.
-        break;
-    }
-
-    // Validate the zeroPoint.
-    switch (operand.type)
-    {
-      case OperandType::FLOAT32:
-      case OperandType::INT32:
-      case OperandType::UINT32:
-      case OperandType::TENSOR_FLOAT32:
-      case OperandType::TENSOR_INT32:
-        if (operand.zeroPoint != 0)
-        {
-          LOG(ERROR) << "Operand " << index << ": Operand of type "
-                     << getOperandTypeName(operand.type) << " with an non-zero zeroPoint "
-                     << operand.zeroPoint;
-          return false;
-        }
-        break;
-      case OperandType::TENSOR_QUANT8_ASYMM:
-        if (operand.zeroPoint < 0 || operand.zeroPoint > 255)
-        {
-          LOG(ERROR) << "Operand " << index << ": Operand of type "
-                     << getOperandTypeName(operand.type) << " with an invalid zeroPoint "
-                     << operand.zeroPoint << ", must be in range [0, 255]";
-          return false;
-        }
-        break;
-      default:
-        // No validation for the OEM types.
-        break;
-    }
-
-    // Validate the lifetime and the location.
-    const DataLocation &location = operand.location;
-    switch (operand.lifetime)
-    {
-      case OperandLifeTime::CONSTANT_COPY:
-        if (location.poolIndex != 0)
-        {
-          LOG(ERROR) << "Operand " << index << ": CONSTANT_COPY with a non-zero poolIndex "
-                     << location.poolIndex;
-          return false;
-        }
-        // Do the addition using size_t to avoid potential wrap-around problems.
-        if (static_cast<size_t>(location.offset) + location.length > operandValues.size())
-        {
-          LOG(ERROR) << "Operand " << index << ": OperandValue location out of range.  Starts at "
-                     << location.offset << ", length " << location.length << ", max "
-                     << operandValues.size();
-          return false;
-        }
-        break;
-      case OperandLifeTime::CONSTANT_REFERENCE:
-        if (!poolVerifier.validate(location))
-        {
-          return false;
-        }
-        break;
-      case OperandLifeTime::TEMPORARY_VARIABLE:
-      case OperandLifeTime::MODEL_INPUT:
-      case OperandLifeTime::MODEL_OUTPUT:
-      case OperandLifeTime::NO_VALUE:
-        if (location.poolIndex != 0 || location.offset != 0 || location.length != 0)
-        {
-          LOG(ERROR) << "Operand " << index << ": Unexpected poolIndex " << location.poolIndex
-                     << ", offset " << location.offset << ", or length " << location.length
-                     << " for operand of lifetime " << toString(operand.lifetime);
-          return false;
-        }
-        break;
-      default:
-        LOG(ERROR) << "Operand " << index << ": Invalid lifetime " << toString(operand.lifetime);
-        return false;
-    }
-
-    // For constants, validate that the length is as expected. The other lifetimes
-    // expect the length to be 0. Don't validate for OEM types.
-    if (operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE ||
-        operand.lifetime == OperandLifeTime::CONSTANT_COPY)
-    {
-      if (operand.type != OperandType::OEM && operand.type != OperandType::TENSOR_OEM_BYTE)
-      {
-        uint32_t expectedLength = sizeOfData(operand.type, operand.dimensions);
-        if (location.length != expectedLength)
-        {
-          LOG(ERROR) << "Operand " << index << ": For operand " << toString(operand)
-                     << " expected a size of " << expectedLength << " but got " << location.length;
-          return false;
-        }
-      }
-    }
-
-    index++;
-  }
-  return true;
-}
-
-static bool validOperationType(OperationType operation)
-{
-  switch (operation)
-  {
-    case OperationType::ADD:
-    case OperationType::AVERAGE_POOL_2D:
-    case OperationType::CONCATENATION:
-    case OperationType::CONV_2D:
-    case OperationType::DEPTHWISE_CONV_2D:
-    case OperationType::DEPTH_TO_SPACE:
-    case OperationType::DEQUANTIZE:
-    case OperationType::EMBEDDING_LOOKUP:
-    case OperationType::FLOOR:
-    case OperationType::FULLY_CONNECTED:
-    case OperationType::HASHTABLE_LOOKUP:
-    case OperationType::L2_NORMALIZATION:
-    case OperationType::L2_POOL_2D:
-    case OperationType::LOCAL_RESPONSE_NORMALIZATION:
-    case OperationType::LOGISTIC:
-    case OperationType::LSH_PROJECTION:
-    case OperationType::LSTM:
-    case OperationType::MAX_POOL_2D:
-    case OperationType::MUL:
-    case OperationType::RELU:
-    case OperationType::RELU1:
-    case OperationType::RELU6:
-    case OperationType::RESHAPE:
-    case OperationType::RESIZE_BILINEAR:
-    case OperationType::RNN:
-    case OperationType::SOFTMAX:
-    case OperationType::SPACE_TO_DEPTH:
-    case OperationType::SVDF:
-    case OperationType::TANH:
-    case OperationType::DIV:
-    case OperationType::STRIDED_SLICE:
-    case OperationType::SUB:
-    case OperationType::OEM_OPERATION:
-    case OperationType::CAST:
-    case OperationType::GATHER:
-    case OperationType::TOPK_V2:
-    case OperationType::TENSORFLOW_MAX:
-      return true;
-    default:
-      return false;
-  }
-}
-
-template <typename VersionedOperation>
-static bool validateOperations(const hidl_vec<VersionedOperation> &operations,
-                               const hidl_vec<Operand> &operands)
-{
-  const size_t operandCount = operands.size();
-  // This vector keeps track of whether there's an operation that writes to
-  // each operand. It is used to validate that temporary variables and
-  // model outputs will be written to.
-  std::vector<bool> writtenTo(operandCount, false);
-  for (auto &op : operations)
-  {
-    if (!validOperationType(op.type))
-    {
-      LOG(ERROR) << "Invalid operation type " << toString(op.type);
-      return false;
-    }
-    // TODO Validate the shapes and any known values. This is currently
-    // done in CpuExecutor but should be done here for all drivers.
-    int error = validateOperation(
-        op.type, op.inputs.size(), op.inputs.size() > 0 ? op.inputs.data() : nullptr,
-        op.outputs.size(), op.outputs.size() > 0 ? op.outputs.data() : nullptr, operands);
-    if (error != ANEURALNETWORKS_NO_ERROR)
-    {
-      return false;
-    }
-
-    for (uint32_t i : op.outputs)
-    {
-      const Operand &operand = operands[i];
-      if (operand.lifetime != OperandLifeTime::TEMPORARY_VARIABLE &&
-          operand.lifetime != OperandLifeTime::MODEL_OUTPUT)
-      {
-        LOG(ERROR) << "Writing to an operand with incompatible lifetime "
-                   << toString(operand.lifetime);
-        return false;
-      }
-
-      // Check that we only write once to an operand.
-      if (writtenTo[i])
-      {
-        LOG(ERROR) << "Operand " << i << " written a second time";
-        return false;
-      }
-      writtenTo[i] = true;
-    }
-  }
-  for (size_t i = 0; i < operandCount; i++)
-  {
-    if (!writtenTo[i])
-    {
-      const Operand &operand = operands[i];
-      if (operand.lifetime == OperandLifeTime::TEMPORARY_VARIABLE ||
-          operand.lifetime == OperandLifeTime::MODEL_OUTPUT)
-      {
-        LOG(ERROR) << "Operand " << i << " with lifetime " << toString(operand.lifetime)
-                   << " is not being written to.";
-        return false;
-      }
-    }
-  }
-  // TODO More whole graph verifications are possible, for example that an
-  // operand is not use as input & output for the same op, and more
-  // generally that it is acyclic.
-  return true;
-}
-
-static bool validatePools(const hidl_vec<hidl_memory> &pools)
-{
-  for (const hidl_memory &memory : pools)
-  {
-    const auto name = memory.name();
-    if (name != "ashmem" && name != "mmap_fd")
-    {
-      LOG(ERROR) << "Unsupported memory type " << name;
-      return false;
-    }
-    if (memory.handle() == nullptr)
-    {
-      LOG(ERROR) << "Memory of type " << name << " is null";
-      return false;
-    }
-  }
-  return true;
-}
-
-static bool validateModelInputOutputs(const hidl_vec<uint32_t> indexes,
-                                      const hidl_vec<Operand> &operands, OperandLifeTime lifetime)
-{
-  const size_t operandCount = operands.size();
-  for (uint32_t i : indexes)
-  {
-    if (i >= operandCount)
-    {
-      LOG(ERROR) << "Model input or output index out of range: " << i << "/" << operandCount;
-      return false;
-    }
-    const Operand &operand = operands[i];
-    if (operand.lifetime != lifetime)
-    {
-      LOG(ERROR) << "Model input or output has lifetime of " << toString(operand.lifetime)
-                 << " instead of the expected " << toString(lifetime);
-      return false;
-    }
-  }
-
-  std::vector<uint32_t> sortedIndexes = indexes;
-  std::sort(sortedIndexes.begin(), sortedIndexes.end());
-  auto adjacentI = std::adjacent_find(sortedIndexes.begin(), sortedIndexes.end());
-  if (adjacentI != sortedIndexes.end())
-  {
-    LOG(ERROR) << "Model input or output occurs multiple times: " << *adjacentI;
-    return false;
-  }
-  return true;
-}
-
-template <typename VersionedModel> static bool validateModelVersioned(const VersionedModel &model)
-{
-  return (
-      validateOperands(model.operands, model.operandValues, model.pools) &&
-      validateOperations(model.operations, model.operands) &&
-      validateModelInputOutputs(model.inputIndexes, model.operands, OperandLifeTime::MODEL_INPUT) &&
-      validateModelInputOutputs(model.outputIndexes, model.operands,
-                                OperandLifeTime::MODEL_OUTPUT) &&
-      validatePools(model.pools));
-}
-
-bool validateModel(const Model &model) { return validateModelVersioned(model); }
-
-// Validates the arguments of a request. type is either "input" or "output" and is used
-// for printing error messages. The operandIndexes is the appropriate array of input
-// or output operand indexes that was passed to the ANeuralNetworksModel_identifyInputsAndOutputs.
-static bool validateRequestArguments(const hidl_vec<RequestArgument> &requestArguments,
-                                     const hidl_vec<uint32_t> &operandIndexes,
-                                     const hidl_vec<Operand> &operands,
-                                     const hidl_vec<hidl_memory> &pools, const char *type)
-{
-  MemoryAccessVerifier poolVerifier(pools);
-  // The request should specify as many arguments as were described in the model.
-  const size_t requestArgumentCount = requestArguments.size();
-  if (requestArgumentCount != operandIndexes.size())
-  {
-    LOG(ERROR) << "Request specifies " << requestArgumentCount << " " << type
-               << "s but the model has " << operandIndexes.size();
-    return false;
-  }
-  for (size_t requestArgumentIndex = 0; requestArgumentIndex < requestArgumentCount;
-       requestArgumentIndex++)
-  {
-    const RequestArgument &requestArgument = requestArguments[requestArgumentIndex];
-    const DataLocation &location = requestArgument.location;
-    // Get the operand index for this argument. We extract it from the list
-    // that was provided in the call to ANeuralNetworksModel_identifyInputsAndOutputs.
-    // We assume in this function that the model has been validated already.
-    const uint32_t operandIndex = operandIndexes[requestArgumentIndex];
-    const Operand &operand = operands[operandIndex];
-    if (requestArgument.hasNoValue)
-    {
-      if (location.poolIndex != 0 || location.offset != 0 || location.length != 0 ||
-          requestArgument.dimensions.size() != 0)
-      {
-        LOG(ERROR) << "Request " << type << " " << requestArgumentIndex
-                   << " has no value yet has details.";
-        return false;
-      }
-    }
-    else
-    {
-      // Validate the location.
-      if (!poolVerifier.validate(location))
-      {
-        return false;
-      }
-      // If the argument specified a dimension, validate it.
-      uint32_t rank = requestArgument.dimensions.size();
-      if (rank == 0)
-      {
-        // Validate that all the dimensions are specified in the model.
-        for (size_t i = 0; i < operand.dimensions.size(); i++)
-        {
-          if (operand.dimensions[i] == 0)
-          {
-            LOG(ERROR) << "Model has dimension " << i
-                       << " set to 0 but the request does specify the dimension.";
-            return false;
-          }
-        }
-      }
-      else
-      {
-        if (rank != operand.dimensions.size())
-        {
-          LOG(ERROR) << "Request " << type << " " << requestArgumentIndex
-                     << " has number of dimensions (" << rank << ") different than the model's ("
-                     << operand.dimensions.size() << ")";
-          return false;
-        }
-        for (size_t i = 0; i < rank; i++)
-        {
-          if (requestArgument.dimensions[i] != operand.dimensions[i] && operand.dimensions[i] != 0)
-          {
-            LOG(ERROR) << "Request " << type << " " << requestArgumentIndex << " has dimension "
-                       << i << " of " << requestArgument.dimensions[i]
-                       << " different than the model's " << operand.dimensions[i];
-            return false;
-          }
-          if (requestArgument.dimensions[i] == 0)
-          {
-            LOG(ERROR) << "Request " << type << " " << requestArgumentIndex << " has dimension "
-                       << i << " of zero";
-            return false;
-          }
-        }
-      }
-    }
-  }
-  return true;
-}
-
-template <typename VersionedModel>
-static bool validateRequestVersioned(const Request &request, const VersionedModel &model)
-{
-  return (validateRequestArguments(request.inputs, model.inputIndexes, model.operands,
-                                   request.pools, "input") &&
-          validateRequestArguments(request.outputs, model.outputIndexes, model.operands,
-                                   request.pools, "output") &&
-          validatePools(request.pools));
-}
-
-bool validateRequest(const Request &request, const Model &model)
-{
-  return validateRequestVersioned(request, model);
-}
-
-} // namespace rt
-} // namespace nnfw
index 3af130d..caa4735 100644 (file)
 
 #include <vector>
 #include <algorithm>
-#include <type_traits>
 
 namespace nnfw
 {
 namespace rt
 {
 
-template <typename E> constexpr typename std::underlying_type<E>::type toUnderlying(E e)
-{
-  return static_cast<typename std::underlying_type<E>::type>(e);
-}
-
 // The number of data types (OperandCode) defined in NeuralNetworks.h.
 const int kNumberOfDataTypes = 6;
 
@@ -147,9 +141,8 @@ int validateOperandType(const ANeuralNetworksOperandType &type, const char *tag,
 int validateOperandList(uint32_t count, const uint32_t *list, uint32_t operandCount,
                         const char *tag);
 
-int validateOperation(OperationType opType, uint32_t inputCount, const uint32_t *inputIndexes,
-                      uint32_t outputCount, const uint32_t *outputIndexes,
-                      const std::vector<Operand> &operands);
+bool validateModel(const Model &model);
+bool validateRequest(const Request &request, const Model &model);
 
 inline size_t getSizeFromInts(int lower, int higher)
 {
diff --git a/runtimes/nn/common/include/ValidateHal.h b/runtimes/nn/common/include/ValidateHal.h
deleted file mode 100644 (file)
index 4ff60ed..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
- * Copyright (C) 2017 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.
- */
-
-#ifndef __NNFW_RT_VALIDATEHAL_H__
-#define __NNFW_RT_VALIDATEHAL_H__
-
-#include "HalInterfaces.h"
-
-namespace nnfw
-{
-namespace rt
-{
-
-// Verifies that the model is valid, i.e. it is consistent, takes
-// only acceptable values, the constants don't extend outside the memory
-// regions they are part of, etc.
-// IMPORTANT: This function cannot validate that OEM operation and operands
-// are correctly defined, as these are specific to each implementation.
-// Each driver should do their own validation of OEM types.
-bool validateModel(const Model &model);
-
-// Verfies that the request for the given model is valid.
-// IMPORTANT: This function cannot validate that OEM operation and operands
-// are correctly defined, as these are specific to each implementation.
-// Each driver should do their own validation of OEM types.
-bool validateRequest(const Request &request, const Model &model);
-
-} // namespace rt
-} // namespace nnfw
-
-#endif // __NNFW_RT_VALIDATEHAL_H__
index 723eb5b..da2b234 100644 (file)
@@ -18,7 +18,6 @@
 #include "ModelBuilder.h"
 
 #include "CompilationBuilder.h"
-#include "ValidateHal.h"
 
 namespace nnfw
 {
@@ -233,7 +232,14 @@ int ModelBuilder::addOperation(OperationType type, uint32_t inputCount, const ui
                << static_cast<uint32_t>(type);
     return ANEURALNETWORKS_BAD_DATA;
   }
-  int n = validateOperation(type, inputCount, inputs, outputCount, outputs, mOperands);
+  int n = validateOperandList(inputCount, inputs, operandCount(),
+                              "ANeuralNetworksModel_addOperation inputs");
+  if (n != ANEURALNETWORKS_NO_ERROR)
+  {
+    return n;
+  }
+  n = validateOperandList(outputCount, outputs, operandCount(),
+                          "ANeuralNetworksModel_addOperation outputs");
   if (n != ANEURALNETWORKS_NO_ERROR)
   {
     return n;