[ML][Common] Add TensorsInfo getters / setters 35/251435/9
authorRafal Walczyna <r.walczyna@samsung.com>
Wed, 13 Jan 2021 12:52:21 +0000 (13:52 +0100)
committerRafal Walczyna <r.walczyna@samsung.com>
Tue, 19 Jan 2021 10:04:13 +0000 (11:04 +0100)
ACR: TWDAPI-273

Methods added:
TensorsInfo.getTensorName
TensorsInfo.setTensorName
TensorsInfo.getTensorType
TensorsInfo.setTensorType
TensorsInfo.getDimensions
TensorsInfo.setDimensions

Test code:

var ti = new tizen.ml.TensorsInfo();
ti.addTensorInfo("tensor1", "UINT8", [1, 1])
console.log(ti.getTensorName(0));
ti.setTensorName(0, "changedName");
console.log(ti.getTensorName(0));
console.log(ti.getTensorType(0));
ti.setTensorType(0, "INT8");
console.log(ti.getTensorType(0));
console.log(ti.getDimensions(0));
ti.setDimensions(0, [2,4]);
console.log(ti.getDimensions(0));

[Verification] Built successful, tested in Chrome Dev console.

Change-Id: I197072bfbc48812fd44a00cfaceb09ee8928f1a1
Signed-off-by: Rafal Walczyna <r.walczyna@samsung.com>
src/ml/js/ml_common.js
src/ml/ml_instance.cc
src/ml/ml_instance.h

index 77c30eb..ad50940 100755 (executable)
@@ -156,7 +156,7 @@ TensorsInfo.prototype.addTensorInfo = function() {
     args.dimensions.forEach(function(d) {
         if (Number.isInteger(d) == false) {
             throw new WebAPIException(
-                WebAPIException.INVALID_VALUES_ERR,
+                WebAPIException.TYPE_MISMATCH_ERR,
                 'dimensions array has to contain only integers'
             );
         }
@@ -179,6 +179,12 @@ TensorsInfo.prototype.addTensorInfo = function() {
     }
 };
 
+var TensorsInfoGettersSettersValidExceptions = [
+    'AbortError',
+    'InvalidValuesError',
+    'NotSupportedError'
+];
+
 TensorsInfo.prototype.clone = function() {
     throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented');
 };
@@ -188,27 +194,224 @@ TensorsInfo.prototype.equals = function() {
 };
 
 TensorsInfo.prototype.getDimensions = function() {
-    throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented');
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'index',
+            type: types_.LONG
+        }
+    ]);
+
+    if (!args.has.index) {
+        throw new WebAPIException(
+            WebAPIException.INVALID_VALUES_ERR,
+            'Invalid parameter: index is undefined'
+        );
+    }
+
+    var callArgs = {
+        index: args.index,
+        tensorsInfoId: this._id
+    };
+
+    var result = native_.callSync('MLTensorsInfoGetDimensions', callArgs);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObjectAndValidate(
+            result,
+            TensorsInfoGettersSettersValidExceptions,
+            AbortError
+        );
+    }
+    return native_.getResultObject(result);
 };
 
+var TensorsInfoSetDimensionsExceptions = [
+    'InvalidValuesError',
+    'TypeMismatchError',
+    'NotSupportedError',
+    'AbortError'
+];
+
 TensorsInfo.prototype.setDimensions = function() {
-    throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented');
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'index',
+            type: types_.LONG
+        },
+        {
+            name: 'dimensions',
+            type: types_.ARRAY
+        }
+    ]);
+
+    args.dimensions.forEach(function(d) {
+        if (Number.isInteger(d) == false) {
+            throw new WebAPIException(
+                WebAPIException.TYPE_MISMATCH_ERR,
+                'dimensions array has to contain only integers'
+            );
+        }
+    });
+
+    var callArgs = {
+        index: args.index,
+        dimensions: args.dimensions,
+        tensorsInfoId: this._id
+    };
+
+    var result = native_.callSync('MLTensorsInfoSetDimensions', callArgs);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObjectAndValidate(
+            result,
+            TensorsInfoSetDimensionsExceptions,
+            AbortError
+        );
+    }
 };
 
 TensorsInfo.prototype.getTensorName = function() {
-    throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented');
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'index',
+            type: types_.LONG
+        }
+    ]);
+
+    if (!args.has.index) {
+        throw new WebAPIException(
+            WebAPIException.INVALID_VALUES_ERR,
+            'Invalid parameter: index is undefined'
+        );
+    }
+
+    var callArgs = {
+        index: args.index,
+        tensorsInfoId: this._id
+    };
+
+    var result = native_.callSync('MLTensorsInfoGetTensorName', callArgs);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObjectAndValidate(
+            result,
+            TensorsInfoGettersSettersValidExceptions,
+            AbortError
+        );
+    }
+    return native_.getResultObject(result);
 };
 
 TensorsInfo.prototype.setTensorName = function() {
-    throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented');
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'index',
+            type: types_.LONG
+        },
+        {
+            name: 'name',
+            type: types_.STRING
+        }
+    ]);
+
+    if (!args.has.index) {
+        throw new WebAPIException(
+            WebAPIException.INVALID_VALUES_ERR,
+            'Invalid parameter: index is undefined'
+        );
+    }
+
+    if (!args.has.name) {
+        throw new WebAPIException(
+            WebAPIException.INVALID_VALUES_ERR,
+            'Invalid parameter: name is undefined'
+        );
+    }
+
+    var callArgs = {
+        index: args.index,
+        name: args.name,
+        tensorsInfoId: this._id
+    };
+
+    var result = native_.callSync('MLTensorsInfoSetTensorName', callArgs);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObjectAndValidate(
+            result,
+            TensorsInfoGettersSettersValidExceptions,
+            AbortError
+        );
+    }
 };
 
 TensorsInfo.prototype.getTensorType = function() {
-    throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented');
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'index',
+            type: types_.LONG
+        }
+    ]);
+
+    if (!args.has.index) {
+        throw new WebAPIException(
+            WebAPIException.INVALID_VALUES_ERR,
+            'Invalid parameter: index is undefined'
+        );
+    }
+
+    var callArgs = {
+        index: args.index,
+        tensorsInfoId: this._id
+    };
+
+    var result = native_.callSync('MLTensorsInfoGetTensorType', callArgs);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObjectAndValidate(
+            result,
+            TensorsInfoGettersSettersValidExceptions,
+            AbortError
+        );
+    }
+    return native_.getResultObject(result);
 };
 
+var TensorsInfoSetTensorTypeValidExceptions = [
+    'AbortError',
+    'InvalidValuesError',
+    'NotSupportedError',
+    'TypeMismatchError'
+];
+
 TensorsInfo.prototype.setTensorType = function() {
-    throw new WebAPIException(WebAPIException.ABORT_ERR, 'Not implemented');
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'index',
+            type: types_.LONG
+        },
+        {
+            name: 'type',
+            type: types_.ENUM,
+            values: Object.values(TensorType)
+        }
+    ]);
+
+    var callArgs = {
+        index: args.index,
+        type: args.type,
+        tensorsInfoId: this._id
+    };
+
+    var result = native_.callSync('MLTensorsInfoSetTensorType', callArgs);
+
+    if (native_.isFailure(result)) {
+        throw native_.getErrorObjectAndValidate(
+            result,
+            TensorsInfoSetTensorTypeValidExceptions,
+            AbortError
+        );
+    }
 };
 
 TensorsInfo.prototype.getTensorSize = function() {
index 301333e..4250a13 100644 (file)
@@ -77,6 +77,13 @@ MlInstance::MlInstance() : pipeline_manager_{this} {
   REGISTER_METHOD(MLTensorsInfoCountGetter);
   REGISTER_METHOD(MLTensorsInfoAddTensorInfo);
   REGISTER_METHOD(MLTensorsInfoCreate);
+  REGISTER_METHOD(MLTensorsInfoGetDimensions);
+  REGISTER_METHOD(MLTensorsInfoSetDimensions);
+  REGISTER_METHOD(MLTensorsInfoGetTensorName);
+  REGISTER_METHOD(MLTensorsInfoSetTensorName);
+  REGISTER_METHOD(MLTensorsInfoGetTensorType);
+  REGISTER_METHOD(MLTensorsInfoSetTensorType);
+
   // Common ML API end
 
   // Single API begin
@@ -152,6 +159,57 @@ void MlInstance::MLTensorsInfoCountGetter(const picojson::value& args, picojson:
   ReportSuccess(val, out);
 }
 
+PlatformResult GetDimensionsFromJsonArray(picojson::array& dim,
+                                          unsigned int dimensions[ML_TENSOR_RANK_LIMIT]) {
+  ScopeLogger();
+  bool foundValidValue = false;
+  unsigned int validDimensions[ML_TENSOR_RANK_LIMIT];
+  for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) {
+    validDimensions[i] = 1;
+  }
+  int dimSize = ML_TENSOR_RANK_LIMIT;
+  if (dim.size() <= ML_TENSOR_RANK_LIMIT) {
+    dimSize = dim.size();
+  } else {
+    LoggerD("Provided dimensions array is bigger than supported");
+  }
+
+  for (int i = dimSize - 1; i >= 0; i--) {
+    auto& d = dim[i];
+    if (!d.is<double>()) {
+      LoggerE("dimensions array contains an invalid value: %s", d.serialize().c_str());
+      return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+                            "dimensions array contains an invalid value");
+    }
+
+    int v = static_cast<int>(d.get<double>());
+    if (v <= 0) {
+      // dimensions with zeros at the end are valid
+      // 0 after valid value is not accepted
+      if (foundValidValue || (v < 0)) {
+        LoggerE("dimensions array contains non-positive value: %d", v);
+        return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+                              "dimensions array contains non-positive value");
+      }
+      continue;
+    }
+
+    foundValidValue = true;
+    validDimensions[i] = static_cast<unsigned int>(v);
+  }
+
+  if (!foundValidValue) {
+    LoggerE("No valid values found in dimensions array");
+    return PlatformResult(ErrorCode::INVALID_VALUES_ERR,
+                          "dimensions array contains invalid values");
+  }
+
+  for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) {
+    dimensions[i] = validDimensions[i];
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 void MlInstance::MLTensorsInfoAddTensorInfo(const picojson::value& args, picojson::object& out) {
   ScopeLogger("args: %s", args.serialize().c_str());
   CHECK_ARGS(args, kTensorsInfoId, double, out);
@@ -184,35 +242,194 @@ void MlInstance::MLTensorsInfoAddTensorInfo(const picojson::value& args, picojso
     LoggerD("name: %s", name.c_str());
   }
 
-  unsigned int dimensions[ML_TENSOR_RANK_LIMIT] = {1, 1, 1, 1};
-
-  // CHECK_ARGS has already validated type of kDimensions
+  unsigned int dimensions[ML_TENSOR_RANK_LIMIT] = {};
   auto dim = args.get(kDimensions).get<picojson::array>();
-  int i = 0;
-  for (const auto& d : dim) {
-    if (i >= ML_TENSOR_RANK_LIMIT) {
-      LoggerD("Provided dimensions array is bigger than supported");
+  result = GetDimensionsFromJsonArray(dim, dimensions);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+
+  result = tensorsInfo->AddTensorInfo(name, tensorTypeEnum, dimensions);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+void MlInstance::MLTensorsInfoGetDimensions(const picojson::value& args, picojson::object& out) {
+  ScopeLogger("args: %s", args.serialize().c_str());
+  CHECK_ARGS(args, kTensorsInfoId, double, out);
+  CHECK_ARGS(args, kIndex, double, out);
+
+  int tensorsInfoId = static_cast<int>(args.get(kTensorsInfoId).get<double>());
+  TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId);
+  if (nullptr == tensorsInfo) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out,
+                      ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId));
+    return;
+  }
+  int index = static_cast<int>(args.get(kIndex).get<double>());
+  unsigned int dim[ML_TENSOR_RANK_LIMIT];
+  PlatformResult result = tensorsInfo->NativeGetTensorDimensions(index, dim);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+  picojson::array array = picojson::array{};
+  for (int i = 0; i < ML_TENSOR_RANK_LIMIT; i++) {
+    if (0 == dim[i]) {
       break;
     }
+    array.push_back(picojson::value{static_cast<double>(dim[i])});
+  }
+  picojson::value val = picojson::value{array};
+  ReportSuccess(val, out);
+}
 
-    if (!d.is<double>()) {
-      LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR,
-                                       "dimensions array contains an invalid value"),
-                        &out,
-                        ("dimensions array contains an invalid value: %s", d.serialize().c_str()));
-      return;
-    }
+void MlInstance::MLTensorsInfoSetDimensions(const picojson::value& args, picojson::object& out) {
+  ScopeLogger("args: %s", args.serialize().c_str());
+  CHECK_ARGS(args, kTensorsInfoId, double, out);
+  CHECK_ARGS(args, kIndex, double, out);
+  CHECK_ARGS(args, kDimensions, picojson::array, out);
 
-    dimensions[i] = static_cast<unsigned int>(d.get<double>());
-    i++;
+  int tensorsInfoId = static_cast<int>(args.get(kTensorsInfoId).get<double>());
+  TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId);
+  if (nullptr == tensorsInfo) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out,
+                      ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId));
+    return;
   }
 
-  result = tensorsInfo->AddTensorInfo(name, tensorTypeEnum, dimensions);
+  unsigned int dimensions[ML_TENSOR_RANK_LIMIT] = {};
+  auto dim = args.get(kDimensions).get<picojson::array>();
+  PlatformResult result = GetDimensionsFromJsonArray(dim, dimensions);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+
+  int index = static_cast<int>(args.get(kIndex).get<double>());
+  result = tensorsInfo->NativeSetTensorDimensions(index, dimensions);
   if (!result) {
     LogAndReportError(result, &out);
     return;
   }
+  ReportSuccess(out);
+}
 
+void MlInstance::MLTensorsInfoGetTensorName(const picojson::value& args, picojson::object& out) {
+  ScopeLogger("args: %s", args.serialize().c_str());
+  CHECK_ARGS(args, kTensorsInfoId, double, out);
+  CHECK_ARGS(args, kIndex, double, out);
+
+  int tensorsInfoId = static_cast<int>(args.get(kTensorsInfoId).get<double>());
+  TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId);
+  if (nullptr == tensorsInfo) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out,
+                      ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId));
+    return;
+  }
+  int index = static_cast<int>(args.get(kIndex).get<double>());
+  std::string name;
+  PlatformResult result = tensorsInfo->NativeGetTensorName(index, &name);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+  picojson::value val = picojson::value{name};
+  ReportSuccess(val, out);
+}
+
+void MlInstance::MLTensorsInfoSetTensorName(const picojson::value& args, picojson::object& out) {
+  ScopeLogger("args: %s", args.serialize().c_str());
+  CHECK_ARGS(args, kTensorsInfoId, double, out);
+  CHECK_ARGS(args, kIndex, double, out);
+  CHECK_ARGS(args, kName, std::string, out);
+
+  int tensorsInfoId = static_cast<int>(args.get(kTensorsInfoId).get<double>());
+  TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId);
+  if (nullptr == tensorsInfo) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out,
+                      ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId));
+    return;
+  }
+
+  int index = static_cast<int>(args.get(kIndex).get<double>());
+  const std::string& name = args.get(kName).get<std::string>();
+  PlatformResult result = tensorsInfo->NativeSetTensorName(index, name);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+  ReportSuccess(out);
+}
+
+void MlInstance::MLTensorsInfoGetTensorType(const picojson::value& args, picojson::object& out) {
+  ScopeLogger("args: %s", args.serialize().c_str());
+  CHECK_ARGS(args, kTensorsInfoId, double, out);
+  CHECK_ARGS(args, kIndex, double, out);
+
+  int tensorsInfoId = static_cast<int>(args.get(kTensorsInfoId).get<double>());
+  TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId);
+  if (nullptr == tensorsInfo) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out,
+                      ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId));
+    return;
+  }
+
+  int index = static_cast<int>(args.get(kIndex).get<double>());
+  ml_tensor_type_e tensorTypeEnum = ML_TENSOR_TYPE_UNKNOWN;
+  PlatformResult result = tensorsInfo->NativeGetTensorType(index, &tensorTypeEnum);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+  std::string tensorTypeString;
+  result = types::TensorTypeEnum.getName(tensorTypeEnum, &tensorTypeString);
+  if (!result) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Error getting name of TensorType"),
+                      &out,
+                      ("TensorTypeEnum.getName() failed, error: %s", result.message().c_str()));
+    return;
+  }
+
+  picojson::value val = picojson::value{tensorTypeString};
+  ReportSuccess(val, out);
+}
+
+void MlInstance::MLTensorsInfoSetTensorType(const picojson::value& args, picojson::object& out) {
+  ScopeLogger("args: %s", args.serialize().c_str());
+  CHECK_ARGS(args, kTensorsInfoId, double, out);
+  CHECK_ARGS(args, kIndex, double, out);
+  CHECK_ARGS(args, kType, std::string, out);
+
+  int tensorsInfoId = static_cast<int>(args.get(kTensorsInfoId).get<double>());
+  TensorsInfo* tensorsInfo = GetTensorsInfoManager().GetTensorsInfo(tensorsInfoId);
+  if (nullptr == tensorsInfo) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Internal TensorsInfo error"), &out,
+                      ("Could not find TensorsInfo handle with given id: %d", tensorsInfoId));
+    return;
+  }
+
+  const std::string& tensorType = args.get(kType).get<std::string>();
+  ml_tensor_type_e tensorTypeEnum = ML_TENSOR_TYPE_UNKNOWN;
+  PlatformResult result = types::TensorTypeEnum.getValue(tensorType, &tensorTypeEnum);
+  if (!result) {
+    LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Error getting value of TensorType"),
+                      &out,
+                      ("TensorTypeEnum.getValue() failed, error: %s", result.message().c_str()));
+    return;
+  }
+
+  int index = static_cast<int>(args.get(kIndex).get<double>());
+  result = tensorsInfo->NativeSetTensorType(index, tensorTypeEnum);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
   ReportSuccess(out);
 }
 // Common ML API end
index f8141a9..a461bec 100644 (file)
@@ -40,6 +40,12 @@ class MlInstance : public common::ParsedInstance {
   void MLTensorsInfoCountGetter(const picojson::value& args, picojson::object& out);
   void MLTensorsInfoCreate(const picojson::value& args, picojson::object& out);
   void MLTensorsInfoAddTensorInfo(const picojson::value& args, picojson::object& out);
+  void MLTensorsInfoGetDimensions(const picojson::value& args, picojson::object& out);
+  void MLTensorsInfoSetDimensions(const picojson::value& args, picojson::object& out);
+  void MLTensorsInfoGetTensorName(const picojson::value& args, picojson::object& out);
+  void MLTensorsInfoSetTensorName(const picojson::value& args, picojson::object& out);
+  void MLTensorsInfoGetTensorType(const picojson::value& args, picojson::object& out);
+  void MLTensorsInfoSetTensorType(const picojson::value& args, picojson::object& out);
 
   TensorsInfoManager tensors_info_manager_;
   // Common ML API end