Align padding for transpose_conv2d to match spec

Increasing out pad values now leads to increasing pad.
Reference model changes, and test generator changes to
match specification definition

Change-Id: I4f3ebfbca5048354fb15bedc7ab640ff28ed853a
Signed-off-by: Eric Kunze <eric.kunze@arm.com>
Signed-off-by: Jeremy Johnson <jeremy.johnson@arm.com>
diff --git a/reference_model/src/ops/tensor_ops.cc b/reference_model/src/ops/tensor_ops.cc
index 03cb9fb..ef6dfa7 100644
--- a/reference_model/src/ops/tensor_ops.cc
+++ b/reference_model/src/ops/tensor_ops.cc
@@ -1498,14 +1498,7 @@
         return 1;
     }
 
-    for (int32_t i : attribute->out_pad())
-    {
-        if (i < 0)
-        {
-            printNodeValidationError("OpTransposeConv2d: At least one pad is smaller than zero");
-            return 1;
-        }
-    }
+
 
     for (int32_t i : attribute->stride())
     {
@@ -1540,8 +1533,13 @@
     int32_t out_pad_left   = attribute->out_pad()[2];
     int32_t out_pad_right  = attribute->out_pad()[3];
 
-    int32_t H = (IH - 1) * stride_y - out_pad_top - out_pad_bottom + kernel_h;
-    int32_t W = (IW - 1) * stride_x - out_pad_left - out_pad_right + kernel_w;
+    for (size_t i = 0; i < attribute->out_pad().size(); i++)
+    {
+        ERROR_IF(attribute->out_pad()[i] <= -(weight->getShape()[(i / 2) + 1]), "OpTransposeConv2d: At least one out_pad value is larger than kernel size");
+    }
+
+    int32_t H = (IH - 1) * stride_y + out_pad_top + out_pad_bottom + kernel_h;
+    int32_t W = (IW - 1) * stride_x + out_pad_left + out_pad_right + kernel_w;
 
     if ((OH != H) || (OW != W))
     {
@@ -1632,8 +1630,8 @@
         {
             for (int iw = 0; iw < in_width; iw++)
             {
-                out_x_origin = iw * stride_w - out_pad_left;
-                out_y_origin = ih * stride_h - out_pad_top;
+                out_x_origin = iw * stride_w + out_pad_left;
+                out_y_origin = ih * stride_h + out_pad_top;
                 for (int ic = 0; ic < in_channels; ic++)
                 {
                     for (int fh = 0; fh < f_height; fh++)
diff --git a/verif/generator/tosa_arg_gen.py b/verif/generator/tosa_arg_gen.py
index 2596bec..ef84762 100644
--- a/verif/generator/tosa_arg_gen.py
+++ b/verif/generator/tosa_arg_gen.py
@@ -1111,10 +1111,15 @@
 
         # Generate comprehensive argument lists
         # - except for named errors, which use specific invalid value(s)
-        if error_name == ErrorIf.PadSmallerZero:
-            p_vals = [testGen.rng.choice(range(-5, 0))]
+        smallest_padding_size = -min(filter_shape[1], filter_shape[2]) + 1
+        if error_name == ErrorIf.PadLargerEqualKernel:
+            max_filter_size = -max(filter_shape[1], filter_shape[2])
+            p_vals = [testGen.rng.choice(range(max_filter_size - 10, max_filter_size))]
         else:
-            p_vals = [x for x in range(0, testGen.args.max_conv_padding + 1)]
+            p_vals = [
+                x
+                for x in range(smallest_padding_size, testGen.args.max_conv_padding + 1)
+            ]
         paddings = {x for x in itertools.product(*([p_vals] * 4))}
         if error_name == ErrorIf.StrideSmallerOne:
             # Can't use stride=0, as it is used to derive output shape, as a divisor
@@ -1128,7 +1133,12 @@
             if max(ifm_shape) < 64:
                 bigPadding = 9
                 paddings.update(
-                    {x for x in itertools.product(*([[0, bigPadding]] * 4))}
+                    {
+                        x
+                        for x in itertools.product(
+                            *([[smallest_padding_size, bigPadding]] * 4)
+                        )
+                    }
                 )
             bigStride = 8
             strides.update({x for x in itertools.product(*([[1, bigStride]] * 2))})
@@ -1150,8 +1160,8 @@
             for p in sorted(list(paddings)):
                 if n % sparsity == 0:
                     # Determine the output shape
-                    oh = (ifm_shape[1] - 1) * s[0] - p[0] - p[1] + filter_shape[1]
-                    ow = (ifm_shape[2] - 1) * s[1] - p[2] - p[3] + filter_shape[2]
+                    oh = (ifm_shape[1] - 1) * s[0] + p[0] + p[1] + filter_shape[1]
+                    ow = (ifm_shape[2] - 1) * s[1] + p[2] + p[3] + filter_shape[2]
                     os = [ifm_shape[0], oh, ow, filter_shape[0]]
                     arg_list.append(
                         (
diff --git a/verif/generator/tosa_error_if.py b/verif/generator/tosa_error_if.py
index e4e60b7..f9a00f9 100644
--- a/verif/generator/tosa_error_if.py
+++ b/verif/generator/tosa_error_if.py
@@ -1261,15 +1261,28 @@
 
         if check:
             pad = kwargs["pad"]
-            kernel = kwargs["kernel"]
-            if min(pad) > 0 and min(kernel) > 1:
+            op = kwargs["op"]
+            if op["op"] == Op.TRANSPOSE_CONV2D:
+                # transpose_conv2d
+                kernel = kwargs["weight_shape"][1:-1]
                 if (
-                    pad[0] >= kernel[0]
-                    or pad[1] >= kernel[0]
-                    or pad[2] >= kernel[1]
-                    or pad[3] >= kernel[1]
+                    pad[0] <= -kernel[0]
+                    or pad[1] <= -kernel[0]
+                    or pad[2] <= -kernel[1]
+                    or pad[3] <= -kernel[1]
                 ):
                     error_result = True
+            else:
+                # pooling op
+                kernel = kwargs["kernel"]
+                if min(pad) > 0 and min(kernel) > 1:
+                    if (
+                        pad[0] >= kernel[0]
+                        or pad[1] >= kernel[0]
+                        or pad[2] >= kernel[1]
+                        or pad[3] >= kernel[1]
+                    ):
+                        error_result = True
 
         info_dict = {
             "error_name": error_name,
@@ -1400,12 +1413,22 @@
         return info_dict
 
     @staticmethod
-    def checkConvParams(weight_shape, stride, pad, dilation):
+    def checkConvParams(op, weight_shape, stride, pad, dilation):
+        if op == Op.TRANSPOSE_CONV2D:
+            pad_ok = (
+                pad[0] > -weight_shape[1]
+                and pad[1] > -weight_shape[1]
+                and pad[2] > -weight_shape[2]
+                and pad[3] > -weight_shape[2]
+            )
+        else:
+            pad_ok = min(pad) >= 0
+
         return (
             # Check kernel sizes
             min(weight_shape[1:-1]) >= 1
             and min(stride) >= 1
-            and min(pad) >= 0
+            and pad_ok
             and (dilation is None or min(dilation) >= 1)
         )
 
@@ -1437,8 +1460,8 @@
                     if op["op"] == Op.TRANSPOSE_CONV2D:
                         dims_correct.append(
                             (input_shape[index + 1] - 1) * stride[index]
-                            - pad[pad_offset]
-                            - pad[pad_offset + 1]
+                            + pad[pad_offset]
+                            + pad[pad_offset + 1]
                             + weight_shape[index + kernel_offset]
                         )
                     else:
@@ -1457,7 +1480,7 @@
 
             # ensure parameters are valid
             params_valid = TosaErrorValidator.checkConvParams(
-                weight_shape, stride, pad, dilation
+                op["op"], weight_shape, stride, pad, dilation
             )
 
             if params_valid and output_shape[1:-1] != dims_correct:
@@ -1507,7 +1530,7 @@
 
             # ensure parameters are valid
             params_valid = TosaErrorValidator.checkConvParams(
-                weight_shape, stride, pad, dilation
+                op["op"], weight_shape, stride, pad, dilation
             )
             if params_valid and max(remainders) > 0:
                 error_result = True
diff --git a/verif/generator/tosa_test_gen.py b/verif/generator/tosa_test_gen.py
index 53d38dd..ce3f81f 100644
--- a/verif/generator/tosa_test_gen.py
+++ b/verif/generator/tosa_test_gen.py
@@ -2605,7 +2605,7 @@
                 TosaErrorValidator.evWrongOutputList,
                 TosaErrorValidator.evInputZeroPointNotZero,
                 TosaErrorValidator.evWeightZeroPointNotZero,
-                TosaErrorValidator.evPadSmallerZero,
+                TosaErrorValidator.evPadLargerEqualKernel,
                 TosaErrorValidator.evStrideSmallerOne,
                 TosaErrorValidator.evWrongRank,
                 TosaErrorValidator.evConvOutputShapeMismatch,