2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "NodeExecution.h"
19 #include "locomotiv/NodeData.h"
20 #include "NodeDataImpl.h"
21 #include "NodeDomain.h"
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"
29 #include <gtest/gtest.h>
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;
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)
42 auto g = loco::make_graph();
43 // Fill lhs MatrixEncode
44 auto lhs_enc = g->nodes()->create<loco::MatrixEncode>();
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())
50 const auto &ind = e.current();
51 lhs_enc_buf.at(ind) = lhs_overlay.at(ind);
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);
58 // Fill rhs MatrixEncode
59 auto rhs_enc = g->nodes()->create<loco::MatrixEncode>();
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())
65 const auto &ind = e.current();
66 rhs_enc_buf.at(ind) = rhs_overlay.at(ind);
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);
75 auto mat_mul = g->nodes()->create<loco::MatMul>();
76 mat_mul->lhs(lhs_enc);
77 mat_mul->rhs(rhs_enc);
80 locomotiv::NodeExecution::get().run(mat_mul);
82 // get result of calculation
83 auto mat_mul_result = locomotiv::annot_data(mat_mul);
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);
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())
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));
99 throw std::runtime_error("NYI for these DataTypes");
102 ASSERT_EQ(loco::Domain::Matrix, locomotiv::annot_domain(mat_mul));
108 /* from the code below:
112 a = [[-0.48850584, 1.4292705, -1.3424522],
113 [1.7021934, -0.39246717, 0.6248314]]
115 b = [[-0.0830195, 0.21088193, -0.11781317],
116 [0.07755677, 1.6337638, 1.0792778],
117 [-1.6922939, -1.5437212, 0.96667504]]
119 print(np.array(a) @ np.array(b))
121 TEST(NodeExecution_MatMul, f32_2x3_3x3)
123 using nncc::core::ADT::tensor::Shape;
127 -0.48850584, 1.4292705, -1.3424522,
128 1.7021934, -0.39246717, 0.6248314
133 -0.0830195, 0.21088193, -0.11781317,
134 0.07755677, 1.6337638, 1.0792778,
135 -1.6922939, -1.5437212, 0.96667504
140 2.42322878, 4.30444527, 0.30241731,
141 -1.2291521, -1.2468023, -0.02011299
144 run_test<float>(lhs, rhs, out, Shape{2, 3}, Shape{3, 3}, Shape{2, 3}, loco::DataType::FLOAT32);
149 /* from the code below:
153 a = np.random.randint(10000, size=(4, 2))
155 b = np.random.randint(10000, size=(2, 6))
159 print(np.array(a) @ np.array(b))
161 TEST(NodeExecution_MatMul, s32_4x2_2x6)
163 using nncc::core::ADT::tensor::Shape;
165 const int32_t lhs[] =
173 const int32_t rhs[] =
175 2694, 8376, 8090, 1285, 7492, 1652,
176 5427, 8798, 7634, 2229, 5439, 6999
179 const int32_t out[] =
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
187 run_test<int32_t>(lhs, rhs, out, Shape{4, 2}, Shape{2, 6}, Shape{4, 6}, loco::DataType::S32);