1 /*
2 * Copyright (c) 2020-2021 Arm Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24 #include "tests/validation/reference/Logical.h"
25 #include "src/core/KernelTypes.h"
26 #include "tests/framework/Asserts.h"
27
28 namespace arm_compute
29 {
30 namespace test
31 {
32 namespace validation
33 {
34 namespace reference
35 {
36 template <typename T>
logical_binary_op(arm_compute::LogicalOperation op,T src1,T src2)37 T logical_binary_op(arm_compute::LogicalOperation op, T src1, T src2)
38 {
39 switch(op)
40 {
41 case arm_compute::LogicalOperation::And:
42 return src1 && src2;
43 case arm_compute::LogicalOperation::Or:
44 return src1 || src2;
45 // The following operators are either invalid or not binary operator
46 case arm_compute::LogicalOperation::Not:
47 // fall through
48 case arm_compute::LogicalOperation::Unknown:
49 // fall through
50 default:
51 ARM_COMPUTE_ASSERT(true);
52 }
53 return T{};
54 }
55
56 template <size_t dim>
57 struct BroadcastUnroll
58 {
59 template <typename T>
unrollarm_compute::test::validation::reference::BroadcastUnroll60 static void unroll(arm_compute::LogicalOperation op, const SimpleTensor<T> &src1, const SimpleTensor<T> &src2, SimpleTensor<T> &dst,
61 Coordinates &id_src1, Coordinates &id_src2, Coordinates &id_dst)
62 {
63 const bool src1_is_broadcast = (src1.shape()[dim - 1] != dst.shape()[dim - 1]);
64 const bool src2_is_broadcast = (src2.shape()[dim - 1] != dst.shape()[dim - 1]);
65
66 id_src1.set(dim - 1, 0);
67 id_src2.set(dim - 1, 0);
68 id_dst.set(dim - 1, 0);
69 #if defined(_OPENMP)
70 #pragma omp parallel for
71 #endif /* _OPENMP */
72 for(size_t i = 0; i < dst.shape()[dim - 1]; ++i)
73 {
74 BroadcastUnroll < dim - 1 >::unroll(op, src1, src2, dst, id_src1, id_src2, id_dst);
75
76 id_src1[dim - 1] += !src1_is_broadcast;
77 id_src2[dim - 1] += !src2_is_broadcast;
78 ++id_dst[dim - 1];
79 }
80 }
81 };
82
83 template <>
84 struct BroadcastUnroll<0>
85 {
86 template <typename T>
unrollarm_compute::test::validation::reference::BroadcastUnroll87 static void unroll(arm_compute::LogicalOperation op, const SimpleTensor<T> &src1, const SimpleTensor<T> &src2, SimpleTensor<T> &dst,
88 Coordinates &id_src1, Coordinates &id_src2, Coordinates &id_dst)
89 {
90 dst[coord2index(dst.shape(), id_dst)] = logical_binary_op(op, src1[coord2index(src1.shape(), id_src1)], src2[coord2index(src2.shape(), id_src2)]);
91 }
92 };
93
94 template <typename T>
logical_or(const SimpleTensor<T> & src1,const SimpleTensor<T> & src2)95 SimpleTensor<T> logical_or(const SimpleTensor<T> &src1, const SimpleTensor<T> &src2)
96 {
97 Coordinates id_src1{};
98 Coordinates id_src2{};
99 Coordinates id_dst{};
100 SimpleTensor<T> dst{ TensorShape::broadcast_shape(src1.shape(), src2.shape()), src1.data_type() };
101
102 BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(arm_compute::LogicalOperation::Or, src1, src2, dst, id_src1, id_src2, id_dst);
103
104 return dst;
105 }
106
107 template <typename T>
logical_and(const SimpleTensor<T> & src1,const SimpleTensor<T> & src2)108 SimpleTensor<T> logical_and(const SimpleTensor<T> &src1, const SimpleTensor<T> &src2)
109 {
110 Coordinates id_src1{};
111 Coordinates id_src2{};
112 Coordinates id_dst{};
113 SimpleTensor<T> dst{ TensorShape::broadcast_shape(src1.shape(), src2.shape()), src1.data_type() };
114
115 BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(arm_compute::LogicalOperation::And, src1, src2, dst, id_src1, id_src2, id_dst);
116
117 return dst;
118 }
119
120 template <typename T>
logical_not(const SimpleTensor<T> & src)121 SimpleTensor<T> logical_not(const SimpleTensor<T> &src)
122 {
123 SimpleTensor<T> dst(src.shape(), src.data_type());
124 #if defined(_OPENMP)
125 #pragma omp parallel for
126 #endif /* _OPENMP */
127 for(int i = 0; i < src.num_elements(); ++i)
128 {
129 dst[i] = !src[i];
130 }
131
132 return dst;
133 }
134
135 template SimpleTensor<uint8_t> logical_or(const SimpleTensor<uint8_t> &src1, const SimpleTensor<uint8_t> &src2);
136 template SimpleTensor<uint8_t> logical_and(const SimpleTensor<uint8_t> &src1, const SimpleTensor<uint8_t> &src2);
137 template SimpleTensor<uint8_t> logical_not(const SimpleTensor<uint8_t> &src1);
138 } // namespace reference
139 } // namespace validation
140 } // namespace test
141 } // namespace arm_compute
142