Main Compliance testing support for LOG and ACTIVATIONs

Increase exp2 allowed range to account for denormals.
Minor adjustments to verify to match spec updates for pseudo code.
Set ranges of activation function inputs to match spec.

Signed-off-by: Jeremy Johnson <jeremy.johnson@arm.com>
Change-Id: I6fcf665932ac2c9080e284b865da8f7746801f59
diff --git a/reference_model/src/generate/generate_utils.cc b/reference_model/src/generate/generate_utils.cc
index 5546269..d2168c9 100644
--- a/reference_model/src/generate/generate_utils.cc
+++ b/reference_model/src/generate/generate_utils.cc
@@ -43,11 +43,14 @@
                                  { Op::Op_ARGMAX, "ARGMAX" },
                                  { Op::Op_AVG_POOL2D, "AVG_POOL2D" },
                                  { Op::Op_CEIL, "CEIL" },
+                                 { Op::Op_CLAMP, "CLAMP" },
                                  { Op::Op_CONV2D, "CONV2D" },
+                                 { Op::Op_ERF, "ERF" },
                                  { Op::Op_EXP, "EXP" },
                                  { Op::Op_FLOOR, "FLOOR" },
                                  { Op::Op_FULLY_CONNECTED, "FULLY_CONNECTED" },
                                  { Op::Op_IDENTITY, "IDENTITY" },
+                                 { Op::Op_LOG, "LOG" },
                                  { Op::Op_MATMUL, "MATMUL" },
                                  { Op::Op_MAXIMUM, "MAXIMUM" },
                                  { Op::Op_MAX_POOL2D, "MAX_POOL2D" },
@@ -61,7 +64,9 @@
                                  { Op::Op_REDUCE_MAX, "REDUCE_MAX" },
                                  { Op::Op_REDUCE_MIN, "REDUCE_MIN" },
                                  { Op::Op_REDUCE_SUM, "REDUCE_SUM" },
+                                 { Op::Op_SIGMOID, "SIGMOID" },
                                  { Op::Op_SUB, "SUB" },
+                                 { Op::Op_TANH, "TANH" },
                              })
 
 }    // namespace tosa
diff --git a/reference_model/src/verify/verify_abs_error.cc b/reference_model/src/verify/verify_abs_error.cc
index 1afa7fd..b43da08 100644
--- a/reference_model/src/verify/verify_abs_error.cc
+++ b/reference_model/src/verify/verify_abs_error.cc
@@ -32,7 +32,7 @@
 
     for (size_t i = 0; i < T; ++i)
     {
-        double errBound = ref[i] * exp2(-AccPrecision<float>::normal_frac) * bnd[i];
+        double errBound = std::abs(ref[i]) * exp2(-AccPrecision<float>::normal_frac) * bnd[i];
         bool valid      = tosaCheckFloatBound(imp[i], ref[i], errBound);
         if (!valid)
         {
diff --git a/reference_model/src/verify/verify_ulp.cc b/reference_model/src/verify/verify_ulp.cc
index b333810..6e78b96 100644
--- a/reference_model/src/verify/verify_ulp.cc
+++ b/reference_model/src/verify/verify_ulp.cc
@@ -30,15 +30,8 @@
     double errorBound = 0.0;
     if (std::isfinite(referenceValue) && std::abs(referenceValue) != 0.0)
     {
-        // Make the sign of the reference value positive
-        // and adjust the test value appropriately.
-        if (referenceValue < 0)
-        {
-            referenceValue = -referenceValue;
-            testValue      = -testValue;
-        }
         // Find the exponent of the reference value.
-        int32_t referenceExponent = ilog2(referenceValue);
+        int32_t referenceExponent = ilog2(std::abs(referenceValue));
 
         // Work out the values magnitude - by raising 2 to the power of the
         // exponent and taking the normalized minimum for denormal values
diff --git a/reference_model/src/verify/verify_utils.cc b/reference_model/src/verify/verify_utils.cc
index 414f7d7..9aa6ba2 100644
--- a/reference_model/src/verify/verify_utils.cc
+++ b/reference_model/src/verify/verify_utils.cc
@@ -170,7 +170,11 @@
 // Like const_exp2 but for use during runtime
 double exp2(int32_t n)
 {
-    TOSA_REF_REQUIRE(-1022 <= n && n <= 1023, " Invalid exponent value (%d) in exp2", n);
+    if (n < -1075)
+    {
+        return 0.0;    // smaller than smallest denormal
+    }
+    TOSA_REF_REQUIRE(n <= 1023, " Invalid exponent value (%d) in exp2", n);
     return const_exp2(n);
 }
 
@@ -212,6 +216,9 @@
         return false;
     }
 
+    // Check the errorBound
+    TOSA_REF_REQUIRE(errorBound >= 0.f, " Invalid error bound (%g)", errorBound);
+
     // Make the sign of the reference value positive
     // and adjust the test value appropriately.
     if (referenceValue < 0)
@@ -219,10 +226,6 @@
         referenceValue = -referenceValue;
         testValue      = -testValue;
     }
-    if (errorBound < 0)
-    {
-        errorBound = -errorBound;
-    }
 
     // At this point we are ready to calculate the ULP bounds for the reference value.
     double referenceMin, referenceMax;
diff --git a/verif/conformance/tosa_main_profile_ops_info.json b/verif/conformance/tosa_main_profile_ops_info.json
index 87b14c2..35d72e8 100644
--- a/verif/conformance/tosa_main_profile_ops_info.json
+++ b/verif/conformance/tosa_main_profile_ops_info.json
@@ -403,6 +403,7 @@
         "profile": [
             "tosa-mi"
         ],
+        "support_for": [ "lazy_data_gen" ],
         "generation": {
             "standard": {
                 "generator_args": [
@@ -414,7 +415,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-max,max",
                         "--tensor-dim-range",
                         "20,64",
                         "--target-rank",
@@ -432,7 +433,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-max,max",
                         "--tensor-dim-range",
                         "1,20",
                         "--target-rank",
@@ -444,7 +445,7 @@
                         "--target-dtype",
                         "fp32",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-max,max",
                         "--target-shape",
                         "1,2,1,65536",
                         "--target-shape",
@@ -1369,6 +1370,7 @@
         "profile": [
             "tosa-mi"
         ],
+        "support_for": [ "lazy_data_gen" ],
         "generation": {
             "standard": {
                 "generator_args": [
@@ -1382,7 +1384,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-max,max",
                         "--tensor-dim-range",
                         "15,64",
                         "--target-rank",
@@ -1398,7 +1400,7 @@
                         "--target-dtype",
                         "fp32",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-max,max",
                         "--tensor-dim-range",
                         "1,15",
                         "--target-rank",
@@ -1412,7 +1414,7 @@
                         "--target-dtype",
                         "fp16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-max,max",
                         "--target-shape",
                         "1,65530,1,2",
                         "--target-shape",
@@ -2748,6 +2750,7 @@
         "profile": [
             "tosa-mi"
         ],
+        "support_for": [ "lazy_data_gen" ],
         "generation": {
             "standard": {
                 "generator_args": [
@@ -2759,7 +2762,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-16.0,16.0",
                         "--tensor-dim-range",
                         "16,64",
                         "--target-rank",
@@ -2777,7 +2780,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-16.0,16.0",
                         "--tensor-dim-range",
                         "1,19",
                         "--target-rank",
@@ -2789,7 +2792,7 @@
                         "--target-dtype",
                         "fp32",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-16.0,16.0",
                         "--target-shape",
                         "1,2,65538,2,1",
                         "--target-shape",
@@ -2946,6 +2949,7 @@
         "profile": [
             "tosa-mi"
         ],
+        "support_for": [ "lazy_data_gen" ],
         "generation": {
             "standard": {
                 "generator_args": [
@@ -2957,7 +2961,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-8.0,8.0",
                         "--tensor-dim-range",
                         "18,60",
                         "--target-rank",
@@ -2975,7 +2979,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-8.0,8.0",
                         "--tensor-dim-range",
                         "1,24",
                         "--target-rank",
@@ -2987,7 +2991,7 @@
                         "--target-dtype",
                         "fp32",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-8.0,8.0",
                         "--target-shape",
                         "1,65535,2,1,1",
                         "--target-shape",
@@ -3011,6 +3015,7 @@
         "profile": [
             "tosa-mi"
         ],
+        "support_for": [ "lazy_data_gen" ],
         "generation": {
             "standard": {
                 "generator_args": [
@@ -3022,7 +3027,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-4.0,4.0",
                         "--tensor-dim-range",
                         "18,60",
                         "--target-rank",
@@ -3040,7 +3045,7 @@
                         "--target-dtype",
                         "bf16",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-4.0,4.0",
                         "--tensor-dim-range",
                         "1,24",
                         "--target-rank",
@@ -3052,7 +3057,7 @@
                         "--target-dtype",
                         "fp32",
                         "--fp-values-range",
-                        "-2.0,2.0",
+                        "-4.0,4.0",
                         "--target-shape",
                         "1,65535,2,1,1",
                         "--target-shape",
diff --git a/verif/generator/tosa_test_gen.py b/verif/generator/tosa_test_gen.py
index 9f65fd4..04093b8 100644
--- a/verif/generator/tosa_test_gen.py
+++ b/verif/generator/tosa_test_gen.py
@@ -405,13 +405,9 @@
 
         self.ser.addOperator(op["op"], input_list, output_list, attr)
 
-        if op["op"] in (Op.LOG,):
-            # TODO - add compliance support LOG
-            compliance = None
-        else:
-            compliance = self.tensorComplianceMetaData(
-                op, a.dtype, args_dict, result_tensor, error_name
-            )
+        compliance = self.tensorComplianceMetaData(
+            op, a.dtype, args_dict, result_tensor, error_name
+        )
         return TosaTestGen.BuildInfo(result_tensor, compliance)
 
     def build_binary_broadcast(
@@ -1241,8 +1237,13 @@
 
         return TosaTestGen.BuildInfo(result_tensor, compliance)
 
-    def build_clamp(self, op, a, validator_fcns=None, error_name=None):
-        result_tens = OutputShaper.unaryOp(self.ser, self.rng, a, error_name)
+    def build_clamp(
+        self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None
+    ):
+        assert len(inputs) == 1
+        a = inputs[0]
+
+        result_tensor = OutputShaper.unaryOp(self.ser, self.rng, a, error_name)
 
         v = [self.getRandNumberDType(a.dtype), self.getRandNumberDType(a.dtype)]
 
@@ -1258,7 +1259,7 @@
 
         # Invalidate Input/Output list for error if checks.
         input_list = [a.name]
-        output_list = [result_tens.name]
+        output_list = [result_tensor.name]
         pCount, cCount = op["operands"]
         num_operands = pCount + cCount
         input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList(
@@ -1273,10 +1274,10 @@
             max_val=max_val,
             min_val=min_val,
             input_shape=a.shape,
-            output_shape=result_tens.shape,
+            output_shape=result_tensor.shape,
             input_dtype=a.dtype,
-            output_dtype=result_tens.dtype,
-            result_tensors=[result_tens],
+            output_dtype=result_tensor.dtype,
+            result_tensors=[result_tensor],
             input_list=input_list,
             output_list=output_list,
             num_operands=num_operands,
@@ -1295,7 +1296,12 @@
             attr.ClampAttribute(self.ser.builder, min_val, max_val, 0, 0)
 
         self.ser.addOperator(op["op"], input_list, output_list, attr)
-        return result_tens
+
+        compliance = self.tensorComplianceMetaData(
+            op, a.dtype, args_dict, result_tensor, error_name
+        )
+
+        return TosaTestGen.BuildInfo(result_tensor, compliance)
 
     def build_leaky_relu(self, op, a, validator_fcns=None, error_name=None):
         result_tens = OutputShaper.unaryOp(self.ser, self.rng, a, error_name)
@@ -1313,12 +1319,17 @@
         self.ser.addOperator(op["op"], [a.name], [result_tens.name])
         return result_tens
 
-    def build_sigmoid(self, op, a, validator_fcns=None, error_name=None):
-        result_tens = OutputShaper.unaryOp(self.ser, self.rng, a, error_name)
+    def build_activation(
+        self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None
+    ):
+        assert len(inputs) == 1
+        a = inputs[0]
+
+        result_tensor = OutputShaper.unaryOp(self.ser, self.rng, a, error_name)
 
         # Invalidate Input/Output list for error if checks.
         input_list = [a.name]
-        output_list = [result_tens.name]
+        output_list = [result_tensor.name]
         pCount, cCount = op["operands"]
         num_operands = pCount + cCount
         input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList(
@@ -1331,10 +1342,10 @@
             error_name,
             op=op,
             input_shape=a.shape,
-            output_shape=result_tens.shape,
+            output_shape=result_tensor.shape,
             input_dtype=a.dtype,
-            output_dtype=result_tens.dtype,
-            result_tensors=[result_tens],
+            output_dtype=result_tensor.dtype,
+            result_tensors=[result_tensor],
             input_list=input_list,
             output_list=output_list,
             num_operands=num_operands,
@@ -1342,69 +1353,12 @@
             return None
 
         self.ser.addOperator(op["op"], input_list, output_list)
-        return result_tens
 
-    def build_tanh(self, op, a, validator_fcns=None, error_name=None):
-        result_tens = OutputShaper.unaryOp(self.ser, self.rng, a, error_name)
-
-        # Invalidate Input/Output list for error if checks.
-        input_list = [a.name]
-        output_list = [result_tens.name]
-        pCount, cCount = op["operands"]
-        num_operands = pCount + cCount
-        input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList(
-            self, error_name, input_list, output_list
+        compliance = self.tensorComplianceMetaData(
+            op, a.dtype, args_dict, result_tensor, error_name
         )
 
-        if not TosaErrorValidator.evValidateErrorIfs(
-            self.ser,
-            validator_fcns,
-            error_name,
-            op=op,
-            input_shape=a.shape,
-            output_shape=result_tens.shape,
-            input_dtype=a.dtype,
-            output_dtype=result_tens.dtype,
-            result_tensors=[result_tens],
-            input_list=input_list,
-            output_list=output_list,
-            num_operands=num_operands,
-        ):
-            return None
-
-        self.ser.addOperator(op["op"], input_list, output_list)
-        return result_tens
-
-    def build_erf(self, op, a, validator_fcns=None, error_name=None):
-        result_tens = OutputShaper.unaryOp(self.ser, self.rng, a, error_name)
-
-        # Invalidate Input/Output list for error if checks.
-        input_list = [a.name]
-        output_list = [result_tens.name]
-        pCount, cCount = op["operands"]
-        num_operands = pCount + cCount
-        input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList(
-            self, error_name, input_list, output_list
-        )
-
-        if not TosaErrorValidator.evValidateErrorIfs(
-            self.ser,
-            validator_fcns,
-            error_name,
-            op=op,
-            input_shape=a.shape,
-            output_shape=result_tens.shape,
-            input_dtype=a.dtype,
-            output_dtype=result_tens.dtype,
-            result_tensors=[result_tens],
-            input_list=input_list,
-            output_list=output_list,
-            num_operands=num_operands,
-        ):
-            return None
-
-        self.ser.addOperator(op["op"], input_list, output_list)
-        return result_tens
+        return TosaTestGen.BuildInfo(result_tensor, compliance)
 
     def build_concat(
         self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None
@@ -3220,8 +3174,8 @@
             "build_fcn": (
                 build_clamp,
                 TosaTensorGen.tgBasic,
-                TosaTensorValuesGen.tvgDefault,
-                None,
+                TosaTensorValuesGen.tvgLazyGenDefault,
+                TosaArgGen.agNone,
             ),
             "types": TYPE_NARROW_INT_FP,
             "error_if_validators": (
@@ -3231,15 +3185,18 @@
                 TosaErrorValidator.evWrongInputList,
                 TosaErrorValidator.evWrongOutputList,
             ),
+            "data_gen": {
+                "fp": (gtu.DataGenType.PSEUDO_RANDOM,),
+            },
         },
         "sigmoid": {
             "op": Op.SIGMOID,
             "operands": (1, 0),
             "build_fcn": (
-                build_sigmoid,
+                build_activation,
                 TosaTensorGen.tgBasic,
-                TosaTensorValuesGen.tvgDefault,
-                None,
+                TosaTensorValuesGen.tvgLazyGenDefault,
+                TosaArgGen.agNone,
             ),
             "types": TYPE_FP,
             "error_if_validators": (
@@ -3248,15 +3205,19 @@
                 TosaErrorValidator.evWrongInputList,
                 TosaErrorValidator.evWrongOutputList,
             ),
+            "data_gen": {
+                "fp": (gtu.DataGenType.PSEUDO_RANDOM,),
+            },
+            "compliance": {"ulp": 5},
         },
         "tanh": {
             "op": Op.TANH,
             "operands": (1, 0),
             "build_fcn": (
-                build_tanh,
+                build_activation,
                 TosaTensorGen.tgBasic,
-                TosaTensorValuesGen.tvgDefault,
-                None,
+                TosaTensorValuesGen.tvgLazyGenDefault,
+                TosaArgGen.agNone,
             ),
             "types": TYPE_FP,
             "error_if_validators": (
@@ -3265,15 +3226,19 @@
                 TosaErrorValidator.evWrongInputList,
                 TosaErrorValidator.evWrongOutputList,
             ),
+            "data_gen": {
+                "fp": (gtu.DataGenType.PSEUDO_RANDOM,),
+            },
+            "compliance": {"ulp": 5},
         },
         "erf": {
             "op": Op.ERF,
             "operands": (1, 0),
             "build_fcn": (
-                build_erf,
+                build_activation,
                 TosaTensorGen.tgBasic,
-                TosaTensorValuesGen.tvgDefault,
-                None,
+                TosaTensorValuesGen.tvgLazyGenDefault,
+                TosaArgGen.agNone,
             ),
             "types": TYPE_FP,
             "error_if_validators": (
@@ -3282,6 +3247,10 @@
                 TosaErrorValidator.evWrongInputList,
                 TosaErrorValidator.evWrongOutputList,
             ),
+            "data_gen": {
+                "fp": (gtu.DataGenType.PSEUDO_RANDOM,),
+            },
+            "compliance": {"ulp": 5},
         },
         # Elementwise Binary Operators
         "add": {
@@ -3778,6 +3747,10 @@
                 TosaErrorValidator.evWrongInputList,
                 TosaErrorValidator.evWrongOutputList,
             ),
+            "data_gen": {
+                "fp": (gtu.DataGenType.PSEUDO_RANDOM,),
+            },
+            "compliance": {"ulp": 5},
         },
         "logical_not": {
             "op": Op.LOGICAL_NOT,