A Discrete-Event Network Simulator
API
matrix-array-test-suite.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Biljana Bojovic <bbojovic@cttc.es>
18 */
19
20#include "ns3/log.h"
21#include "ns3/matrix-array.h"
22#include "ns3/test.h"
23
31namespace ns3
32{
33
34namespace tests
35{
36
37NS_LOG_COMPONENT_DEFINE("MatrixArrayTest");
38
43template <class T>
45{
46 public:
47 MatrixArrayTestCase<T>() = default;
53 MatrixArrayTestCase<T>(const std::string name);
54
56 ~MatrixArrayTestCase<T>() override;
79
80 protected:
81 private:
82 void DoRun() override;
83};
84
85template <class T>
87 : TestCase(name)
88{
89}
90
91template <class T>
93{
94}
95
96template <class T>
97void
99{
100 // test multiplication of matrices (MatrixArray containing only 1 matrix)
102 MatrixArray<T> m2 = MatrixArray<T>(m1.GetNumCols(), m1.GetNumRows());
103 for (auto i = 0; i < m1.GetNumRows(); ++i)
104 {
105 for (auto j = 0; j < m1.GetNumCols(); ++j)
106 {
107 m1(i, j) = 1;
108 m2(j, i) = 1;
109 }
110 }
111 MatrixArray<T> m3 = m1 * m2;
112 NS_LOG_INFO("m1:" << m1);
113 NS_LOG_INFO("m2:" << m2);
114 NS_LOG_INFO("m3 = m1 * m2:" << m3);
116 m1.GetNumRows(),
117 "The number of rows in resulting matrix is not correct");
119 m2.GetNumCols(),
120 "The number of cols in resulting matrix is not correct");
122 m3.GetNumCols(),
123 "The number of rows and cols should be equal");
124 for (auto i = 0; i < m3.GetNumCols(); ++i)
125 {
126 for (auto j = 0; j < m3.GetNumRows(); ++j)
127 {
128 NS_TEST_ASSERT_MSG_EQ(std::real(m3(i, j)),
129 m1.GetNumCols(),
130 "The element value should be " << m1.GetNumCols());
131 }
132 }
133
134 // multiplication with a scalar value
135 MatrixArray<T> m4 = m3 * (static_cast<T>(5.0));
136 for (auto i = 0; i < m4.GetNumCols(); ++i)
137 {
138 for (auto j = 0; j < m4.GetNumRows(); ++j)
139 {
140 NS_TEST_ASSERT_MSG_EQ(m3(i, j) * (static_cast<T>(5.0)),
141 m4(i, j),
142 "The values are not equal");
143 }
144 }
145 NS_LOG_INFO("m4 = m3 * 5:" << m4);
146
147 // test multiplication of arrays of matrices
148 MatrixArray<T> m5 = MatrixArray<T>(2, 3, 2);
150 for (auto p = 0; p < m5.GetNumPages(); ++p)
151 {
152 for (auto i = 0; i < m5.GetNumRows(); ++i)
153 {
154 for (auto j = 0; j < m5.GetNumCols(); ++j)
155 {
156 m5(i, j, p) = 1;
157 m6(j, i, p) = 1;
158 }
159 }
160 }
161 MatrixArray<T> m7 = m5 * m6;
163 m5.GetNumRows(),
164 "The number of rows in resulting matrix is not correct");
166 m6.GetNumCols(),
167 "The number of cols in resulting matrix is not correct");
169 m7.GetNumCols(),
170 "The number of rows and cols should be equal");
171
172 for (auto p = 0; p < m7.GetNumPages(); ++p)
173 {
174 for (auto i = 0; i < m7.GetNumCols(); ++i)
175 {
176 for (auto j = 0; j < m7.GetNumRows(); ++j)
177 {
178 NS_TEST_ASSERT_MSG_EQ(std::real(m7(i, j, p)),
179 m5.GetNumCols(),
180 "The element value should be " << m5.GetNumCols());
181 }
182 }
183 }
184 // test ostream operator
185 NS_LOG_INFO("m5:" << m5);
186 NS_LOG_INFO("m6:" << m6);
187 NS_LOG_INFO("m7 = m5 * m6:" << m7);
188
189 // test transpose function
190 MatrixArray<T> m8 = m5.Transpose();
191 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
192 NS_LOG_INFO("m8 = m5.Transpose ()" << m8);
193
194 // test 1D array creation, i.e. vector and transposing it
195 MatrixArray<T> m9 = MatrixArray<T>(std::vector<T>({0, 1, 2, 3, 4, 5, 6, 7}));
196 NS_TEST_ASSERT_MSG_EQ((m9.GetNumRows() == 8) && (m9.GetNumCols() == 1) &&
197 (m9.GetNumPages() == 1),
198 true,
199 "Creation of vector is not correct.");
200
201 NS_LOG_INFO("Vector:" << m9);
202 NS_LOG_INFO("Vector after transposing:" << m9.Transpose());
203
204 // Test basic operators
205 MatrixArray<T> m10 =
207 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
208 m10 -= m9;
209 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
210 m10 += m9;
211 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
212 m10 = m9;
213 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
214 m10 = m9 + m9;
215 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
216 m10 = m10 - m9;
217 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
218
219 // test multiplication by using an initialization matrixArray
220 std::valarray<int> a{0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5};
221 std::valarray<int> b{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
222 std::valarray<int> c{2, 3, 4, 6, 2, 3, 4, 6};
223 std::valarray<T> aCasted(a.size());
224 std::valarray<T> bCasted(b.size());
225 std::valarray<T> cCasted(c.size());
226
227 for (size_t i = 0; i < a.size(); ++i)
228 {
229 aCasted[i] = static_cast<T>(a[i]);
230 }
231 for (size_t i = 0; i < b.size(); ++i)
232 {
233 bCasted[i] = static_cast<T>(b[i]);
234 }
235 for (size_t i = 0; i < c.size(); ++i)
236 {
237 cCasted[i] = static_cast<T>(c[i]);
238 }
239 MatrixArray<T> m11 = MatrixArray<T>(2, 3, 2, aCasted);
240 MatrixArray<T> m12 = MatrixArray<T>(3, 2, 2, bCasted);
241 MatrixArray<T> m13 = m11 * m12;
242 MatrixArray<T> m14 = MatrixArray<T>(2, 2, 2, cCasted);
244 m14.GetNumCols(),
245 "The number of columns is not as expected.");
247 m14.GetNumRows(),
248 "The number of rows is not as expected.");
249 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
250 NS_LOG_INFO("m11:" << m11);
251 NS_LOG_INFO("m12:" << m12);
252 NS_LOG_INFO("m13 = matrixArrayA * matrixArrayB:" << m13);
253
254 // test MultiplyByLeftAndRightMatrix
255 std::valarray<int> d{1, 1, 1};
256 std::valarray<int> e{1, 1};
257 std::valarray<int> f{1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3};
258 std::valarray<int> g{12, 12};
259 std::valarray<T> dCasted(d.size());
260 std::valarray<T> eCasted(e.size());
261 std::valarray<T> fCasted(f.size());
262 std::valarray<T> gCasted(g.size());
263 for (size_t i = 0; i < d.size(); ++i)
264 {
265 dCasted[i] = static_cast<T>(d[i]);
266 }
267 for (size_t i = 0; i < e.size(); ++i)
268 {
269 eCasted[i] = static_cast<T>(e[i]);
270 }
271 for (size_t i = 0; i < f.size(); ++i)
272 {
273 fCasted[i] = static_cast<T>(f[i]);
274 }
275 for (size_t i = 0; i < g.size(); ++i)
276 {
277 gCasted[i] = static_cast<T>(g[i]);
278 }
279 MatrixArray<T> m15 = MatrixArray<T>(1, 3, dCasted);
280 MatrixArray<T> m16 = MatrixArray<T>(2, 1, eCasted);
281 MatrixArray<T> m17 = MatrixArray<T>(3, 2, 2, fCasted);
282 MatrixArray<T> m18 = MatrixArray<T>(1, 1, 2, gCasted);
284 NS_TEST_ASSERT_MSG_EQ(m19, m18, "The matrices should be equal.");
285
286 // test MultiplyByLeftAndRightMatrix
287 std::valarray<int> h{1, 3, 2, 2, 4, 0};
288 std::valarray<int> j{2, 2, 3, 4, 1, 3, 0, 5};
289 std::valarray<int> k{1, 2, 0, 0, 2, 3, 4, 1, 2, 3, 4, 1, 1, 2, 0, 0, 2, 3, 4, 1, 2, 3, 4, 1};
290 std::valarray<int> l{144, 132, 128, 104, 144, 132, 128, 104};
291 std::valarray<T> hCasted(h.size());
292 std::valarray<T> jCasted(j.size());
293 std::valarray<T> kCasted(k.size());
294 std::valarray<T> lCasted(l.size());
295 for (size_t i = 0; i < h.size(); ++i)
296 {
297 hCasted[i] = static_cast<T>(h[i]);
298 }
299 for (size_t i = 0; i < j.size(); ++i)
300 {
301 jCasted[i] = static_cast<T>(j[i]);
302 }
303 for (size_t i = 0; i < k.size(); ++i)
304 {
305 kCasted[i] = static_cast<T>(k[i]);
306 }
307 for (size_t i = 0; i < l.size(); ++i)
308 {
309 lCasted[i] = static_cast<T>(l[i]);
310 }
311 MatrixArray<T> m20 = MatrixArray<T>(2, 3, hCasted);
312 MatrixArray<T> m21 = MatrixArray<T>(4, 2, jCasted);
313 MatrixArray<T> m22 = MatrixArray<T>(3, 4, 2, kCasted);
314 MatrixArray<T> m23 = MatrixArray<T>(2, 2, 2, lCasted);
316 NS_TEST_ASSERT_MSG_EQ(m24, m23, "The matrices should be equal.");
317 NS_LOG_INFO("m20:" << m20);
318 NS_LOG_INFO("m21:" << m21);
319 NS_LOG_INFO("m22:" << m22);
320 NS_LOG_INFO("m24 = m20 * m22 * m21" << m24);
321
322 // test initialization with moving
323 NS_LOG_INFO("size() of lCasted before move: " << lCasted.size());
324 MatrixArray<T> m25 = MatrixArray<T>(2, 2, 2, std::move(lCasted));
325 NS_LOG_INFO("size() of lCasted after move: " << lCasted.size());
326 NS_LOG_INFO("m25.GetSize ()" << m25.GetSize());
327 NS_TEST_ASSERT_MSG_EQ(lCasted.size(), 0, "The size of lCasted should be 0.");
328
329 NS_LOG_INFO("size() of hCasted before move: " << hCasted.size());
330 MatrixArray<T> m26 = MatrixArray<T>(2, 3, std::move(hCasted));
331 NS_LOG_INFO("size() of hCasted after move: " << hCasted.size());
332 NS_LOG_INFO("m26.GetSize ()" << m26.GetSize());
333 NS_TEST_ASSERT_MSG_EQ(hCasted.size(), 0, "The size of hCasted should be 0.");
334
335 NS_LOG_INFO("size() of jCasted before move: " << jCasted.size());
336 MatrixArray<T> m27 = MatrixArray<T>(std::move(jCasted));
337 NS_LOG_INFO("size() of jCasted after move: " << jCasted.size());
338 NS_LOG_INFO("m27.GetSize ()" << m27.GetSize());
339 NS_TEST_ASSERT_MSG_EQ(hCasted.size(), 0, "The size of jCasted should be 0.");
340}
341
347{
348 public:
351};
352
354 : TestSuite("matrix-array-test")
355{
356 AddTestCase(new MatrixArrayTestCase<double>("Test MatrixArray<double>"));
358 new MatrixArrayTestCase<std::complex<double>>("Test MatrixArray<std::complex<double>>"));
359 AddTestCase(new MatrixArrayTestCase<int>("Test MatrixArray<int>"));
360}
361
367
368} // namespace tests
369} // namespace ns3
double f(double x, void *params)
Definition: 80211b.c:71
MatrixArray class inherits ValArray class and provides additional interfaces to ValArray which enable...
Definition: matrix-array.h:83
MatrixArray< T > Transpose() const
This operator interprets the 3D array as an array of matrices, and performs a linear algebra operatio...
MatrixArray< T > MultiplyByLeftAndRightMatrix(const MatrixArray< T > &lMatrix, const MatrixArray< T > &rMatrix) const
Multiply each matrix in the array by the left and the right matrix.
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
uint16_t GetNumRows() const
Definition: val-array.h:382
uint16_t GetNumCols() const
Definition: val-array.h:389
const std::valarray< T > & GetValues() const
Returns underlying values.
Definition: val-array.h:563
size_t GetSize() const
Definition: val-array.h:403
uint16_t GetNumPages() const
Definition: val-array.h:396
MatrixArray test for testing constructors.
MatrixArrayTestCase< T > & operator=(const MatrixArrayTestCase< T > &)=default
Copy assignment operator.
MatrixArrayTestCase< T > & operator=(MatrixArrayTestCase< T > &&)=default
Move assignment operator.
void DoRun() override
Implementation to actually run this TestCase.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:144
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition: test.h:564
const double m1
First component modulus, 232 - 209.
Definition: rng-stream.cc:60
const double m2
Second component modulus, 232 - 22853.
Definition: rng-stream.cc:63
static MatrixArrayTestSuite g_matrixArrayTestSuite
MatrixArrayTestSuite instance variable.
Every class exported by the ns3 library is enclosed in the ns3 namespace.