Imported Upstream version 1.8.0
[platform/core/ml/nnfw.git] / compiler / locomotiv / src / Node / MatMul.test.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "NodeExecution.h"
18
19 #include "locomotiv/NodeData.h"
20 #include "NodeDataImpl.h"
21 #include "NodeDomain.h"
22
23 #include <nncc/core/ADT/tensor/Shape.h>
24 #include <nncc/core/ADT/tensor/Buffer.h>
25 #include <nncc/core/ADT/tensor/Overlay.h>
26 #include <nncc/core/ADT/tensor/LexicalLayout.h>
27 #include "nncc/core/ADT/tensor/IndexEnumerator.h"
28
29 #include <gtest/gtest.h>
30
31 namespace
32 {
33 using nncc::core::ADT::tensor::Shape;
34 using nncc::core::ADT::tensor::LexicalLayout;
35 using nncc::core::ADT::tensor::make_buffer;
36 using nncc::core::ADT::tensor::make_overlay;
37
38 template <typename T>
39 void run_test(const T *lhs, const T *rhs, const T *expected_output, const Shape &lhs_shape,
40               const Shape &rhs_shape, const Shape &out_shape, loco::DataType expected_datatype)
41 {
42   auto g = loco::make_graph();
43   // Fill lhs MatrixEncode
44   auto lhs_enc = g->nodes()->create<loco::MatrixEncode>();
45   {
46     auto lhs_enc_buf = make_buffer<T, LexicalLayout>(lhs_shape);
47     auto lhs_overlay = make_overlay<T, LexicalLayout>(lhs_shape, const_cast<T *>(lhs));
48     for (nncc::core::ADT::tensor::IndexEnumerator e{lhs_shape}; e.valid(); e.advance())
49     {
50       const auto &ind = e.current();
51       lhs_enc_buf.at(ind) = lhs_overlay.at(ind);
52     }
53
54     auto enc_data = locomotiv::make_data(lhs_enc_buf);
55     locomotiv::annot_data(lhs_enc, std::move(enc_data));
56     locomotiv::annot_domain(lhs_enc, loco::Domain::Matrix);
57   }
58   // Fill rhs MatrixEncode
59   auto rhs_enc = g->nodes()->create<loco::MatrixEncode>();
60   {
61     auto rhs_enc_buf = make_buffer<T, LexicalLayout>(rhs_shape);
62     auto rhs_overlay = make_overlay<T, LexicalLayout>(rhs_shape, const_cast<T *>(rhs));
63     for (nncc::core::ADT::tensor::IndexEnumerator e{rhs_shape}; e.valid(); e.advance())
64     {
65       const auto &ind = e.current();
66       rhs_enc_buf.at(ind) = rhs_overlay.at(ind);
67     }
68
69     auto enc_data = locomotiv::make_data(rhs_enc_buf);
70     locomotiv::annot_data(rhs_enc, std::move(enc_data));
71     locomotiv::annot_domain(rhs_enc, loco::Domain::Matrix);
72   }
73
74   // build MatMul
75   auto mat_mul = g->nodes()->create<loco::MatMul>();
76   mat_mul->lhs(lhs_enc);
77   mat_mul->rhs(rhs_enc);
78
79   // run interpreter
80   locomotiv::NodeExecution::get().run(mat_mul);
81
82   // get result of calculation
83   auto mat_mul_result = locomotiv::annot_data(mat_mul);
84
85   // check the result
86   ASSERT_NE(mat_mul_result, nullptr);
87   ASSERT_TRUE(mat_mul_result->dtype() == expected_datatype);
88   ASSERT_TRUE(*(mat_mul_result->shape()) == out_shape);
89
90   auto out_overlay = make_overlay<T, LexicalLayout>(out_shape, const_cast<T *>(expected_output));
91   for (nncc::core::ADT::tensor::IndexEnumerator e{out_shape}; e.valid(); e.advance())
92   {
93     const auto &ind = e.current();
94     if (expected_datatype == loco::DataType::FLOAT32)
95       ASSERT_FLOAT_EQ(out_overlay.at(ind), mat_mul_result->as_f32_bufptr()->at(ind));
96     else if (expected_datatype == loco::DataType::S32)
97       ASSERT_EQ(out_overlay.at(ind), mat_mul_result->as_s32_bufptr()->at(ind));
98     else
99       throw std::runtime_error("NYI for these DataTypes");
100   }
101
102   ASSERT_EQ(loco::Domain::Matrix, locomotiv::annot_domain(mat_mul));
103 }
104
105 } // namespace
106
107 // clang-format off
108 /* from the code below:
109
110 import numpy as np
111
112 a = [[-0.48850584,  1.4292705,  -1.3424522],
113      [1.7021934,  -0.39246717,  0.6248314]]
114
115 b = [[-0.0830195,  0.21088193, -0.11781317],
116      [0.07755677, 1.6337638,   1.0792778],
117      [-1.6922939, -1.5437212,   0.96667504]]
118
119 print(np.array(a) @ np.array(b))
120 */
121 TEST(NodeExecution_MatMul, f32_2x3_3x3)
122 {
123   using nncc::core::ADT::tensor::Shape;
124
125   const float lhs[] =
126   {
127     -0.48850584,  1.4292705,  -1.3424522,
128      1.7021934,  -0.39246717,  0.6248314
129   };
130
131   const float rhs[] =
132   {
133     -0.0830195,  0.21088193, -0.11781317,
134      0.07755677, 1.6337638,   1.0792778,
135     -1.6922939, -1.5437212,   0.96667504
136   };
137
138   const float out[] =
139   {
140     2.42322878,  4.30444527,  0.30241731,
141     -1.2291521,  -1.2468023,  -0.02011299
142   };
143
144   run_test<float>(lhs, rhs, out, Shape{2, 3}, Shape{3, 3}, Shape{2, 3}, loco::DataType::FLOAT32);
145
146   SUCCEED();
147 }
148
149 /* from the code below:
150
151 import numpy as np
152
153 a = np.random.randint(10000, size=(4, 2))
154
155 b = np.random.randint(10000, size=(2, 6))
156
157 print(a)
158 print(b)
159 print(np.array(a) @ np.array(b))
160 */
161 TEST(NodeExecution_MatMul, s32_4x2_2x6)
162 {
163   using nncc::core::ADT::tensor::Shape;
164
165   const int32_t lhs[] =
166   {
167     6392, 4993,
168       54, 9037,
169     3947, 5820,
170     5800, 4181
171   };
172
173   const int32_t rhs[] =
174   {
175     2694, 8376, 8090, 1285, 7492, 1652,
176     5427, 8798, 7634, 2229, 5439, 6999
177   };
178
179   const int32_t out[] =
180   {
181     44317059, 97467806, 89827842, 19343117, 75045791, 45505591,
182     49189275, 79959830, 69425318, 20212863, 49556811, 63339171,
183     42218358, 84264432, 76361110, 18044675, 61225904, 47254624,
184     38315487, 85365238, 78839754, 16772449, 66194059, 38844419
185   };
186
187   run_test<int32_t>(lhs, rhs, out, Shape{4, 2}, Shape{2, 6}, Shape{4, 6}, loco::DataType::S32);
188
189   SUCCEED();
190 }
191
192 // clang-format on