A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
24/**
25 * \defgroup matrixArray-tests MatrixArray tests
26 * \ingroup core-tests
27 * \ingroup Matrices
28 */
29
30/**
31 * \file
32 * \ingroup matrixArray-tests
33 * MatrixArray test suite
34 */
35namespace ns3
36{
37
38namespace tests
39{
40
41NS_LOG_COMPONENT_DEFINE("MatrixArrayTest");
42
43/**
44 * \ingroup matrixArray-tests
45 * MatrixArray test case for testing constructors, operators and other functions
46 */
47template <class T>
49{
50 public:
52 /**
53 * Constructor
54 *
55 * \param [in] name reference name
56 */
57 MatrixArrayTestCase(const std::string& name);
58
59 /** Destructor. */
60 ~MatrixArrayTestCase() override;
61 /**
62 * \brief Copy constructor.
63 * Instruct the compiler to generate the implicitly declared copy constructor
64 */
66 /**
67 * \brief Copy assignment operator.
68 * Instruct the compiler to generate the implicitly declared copy assignment operator.
69 * \return A reference to this MatrixArrayTestCase
70 */
72 /**
73 * \brief Move constructor.
74 * Instruct the compiler to generate the implicitly declared move constructor
75 */
77 /**
78 * \brief Move assignment operator.
79 * Instruct the compiler to generate the implicitly declared copy constructor
80 * \return A reference to this MatrixArrayTestCase
81 */
83
84 protected:
85 private:
86 void DoRun() override;
87};
88
89template <class T>
91 : TestCase(name)
92{
93}
94
95template <class T>
97{
98}
99
100template <class T>
101void
103{
104 // test multiplication of matrices (MatrixArray containing only 1 matrix)
106 MatrixArray<T> m2 = MatrixArray<T>(m1.GetNumCols(), m1.GetNumRows());
107 for (size_t i = 0; i < m1.GetNumRows(); ++i)
108 {
109 for (size_t j = 0; j < m1.GetNumCols(); ++j)
110 {
111 m1(i, j) = 1;
112 m2(j, i) = 1;
113 }
114 }
115 MatrixArray<T> m3 = m1 * m2;
116 NS_LOG_INFO("m1:" << m1);
117 NS_LOG_INFO("m2:" << m2);
118 NS_LOG_INFO("m3 = m1 * m2:" << m3);
120 m1.GetNumRows(),
121 "The number of rows in resulting matrix is not correct");
123 m2.GetNumCols(),
124 "The number of cols in resulting matrix is not correct");
126 m3.GetNumCols(),
127 "The number of rows and cols should be equal");
128 for (size_t i = 0; i < m3.GetNumCols(); ++i)
129 {
130 for (size_t j = 0; j < m3.GetNumRows(); ++j)
131 {
132 NS_TEST_ASSERT_MSG_EQ(std::real(m3(i, j)),
133 m1.GetNumCols(),
134 "The element value should be " << m1.GetNumCols());
135 }
136 }
137
138 // multiplication with a scalar value
139 MatrixArray<T> m4 = m3 * (static_cast<T>(5.0));
140 for (size_t i = 0; i < m4.GetNumCols(); ++i)
141 {
142 for (size_t j = 0; j < m4.GetNumRows(); ++j)
143 {
144 NS_TEST_ASSERT_MSG_EQ(m3(i, j) * (static_cast<T>(5.0)),
145 m4(i, j),
146 "The values are not equal");
147 }
148 }
149 NS_LOG_INFO("m4 = m3 * 5:" << m4);
150
151 // test multiplication of arrays of matrices
152 MatrixArray<T> m5 = MatrixArray<T>(2, 3, 2);
154 for (size_t p = 0; p < m5.GetNumPages(); ++p)
155 {
156 for (size_t i = 0; i < m5.GetNumRows(); ++i)
157 {
158 for (size_t j = 0; j < m5.GetNumCols(); ++j)
159 {
160 m5(i, j, p) = 1;
161 m6(j, i, p) = 1;
162 }
163 }
164 }
165 MatrixArray<T> m7 = m5 * m6;
167 m5.GetNumRows(),
168 "The number of rows in resulting matrix is not correct");
170 m6.GetNumCols(),
171 "The number of cols in resulting matrix is not correct");
173 m7.GetNumCols(),
174 "The number of rows and cols should be equal");
175
176 for (size_t p = 0; p < m7.GetNumPages(); ++p)
177 {
178 for (size_t i = 0; i < m7.GetNumCols(); ++i)
179 {
180 for (size_t j = 0; j < m7.GetNumRows(); ++j)
181 {
182 NS_TEST_ASSERT_MSG_EQ(std::real(m7(i, j, p)),
183 m5.GetNumCols(),
184 "The element value should be " << m5.GetNumCols());
185 }
186 }
187 }
188 // test ostream operator
189 NS_LOG_INFO("m5:" << m5);
190 NS_LOG_INFO("m6:" << m6);
191 NS_LOG_INFO("m7 = m5 * m6:" << m7);
192
193 // test transpose function
194 MatrixArray<T> m8 = m5.Transpose();
195 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
196 NS_LOG_INFO("m8 = m5.Transpose ()" << m8);
197
198 // test transpose using initialization arrays
199 std::valarray<int> a{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};
200 std::valarray<int> b{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4};
201 std::valarray<T> aCasted(a.size());
202 std::valarray<T> bCasted(b.size());
203 for (size_t i = 0; i < a.size(); ++i)
204 {
205 aCasted[i] = static_cast<T>(a[i]);
206 }
207 for (size_t i = 0; i < b.size(); ++i)
208 {
209 bCasted[i] = static_cast<T>(b[i]);
210 }
211 m5 = MatrixArray<T>(3, 5, 1, aCasted);
212 m6 = MatrixArray<T>(5, 3, 1, bCasted);
213 m8 = m5.Transpose();
214 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
215 NS_LOG_INFO("m5 (3, 5, 1):" << m5);
216 NS_LOG_INFO("m6 (5, 3, 1):" << m6);
217 NS_LOG_INFO("m8 (5, 3, 1) = m5.Transpose ()" << m8);
218
219 // test 1D array creation, i.e. vector and transposing it
220 MatrixArray<T> m9 = MatrixArray<T>(std::vector<T>({0, 1, 2, 3, 4, 5, 6, 7}));
221 NS_TEST_ASSERT_MSG_EQ((m9.GetNumRows() == 8) && (m9.GetNumCols() == 1) &&
222 (m9.GetNumPages() == 1),
223 true,
224 "Creation of vector is not correct.");
225
226 NS_LOG_INFO("Vector:" << m9);
227 NS_LOG_INFO("Vector after transposing:" << m9.Transpose());
228
229 // Test basic operators
230 MatrixArray<T> m10 =
232 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
233 m10 -= m9;
234 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
235 m10 += m9;
236 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
237 m10 = m9;
238 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
239 m10 = m9 + m9;
240 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
241 m10 = m10 - m9;
242 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
243
244 // test multiplication by using an initialization matrixArray
245 // matrix dimensions in each page are 2x3, 3x2, and the resulting matrix per page is a square
246 // matrix 2x2
247 a = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5};
248 b = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
249 std::valarray<int> c{2, 3, 4, 6, 2, 3, 4, 6};
250 aCasted = std::valarray<T>(a.size());
251 bCasted = std::valarray<T>(b.size());
252 std::valarray<T> cCasted = std::valarray<T>(c.size());
253
254 for (size_t i = 0; i < a.size(); ++i)
255 {
256 aCasted[i] = static_cast<T>(a[i]);
257 }
258 for (size_t i = 0; i < b.size(); ++i)
259 {
260 bCasted[i] = static_cast<T>(b[i]);
261 }
262 for (size_t i = 0; i < c.size(); ++i)
263 {
264 cCasted[i] = static_cast<T>(c[i]);
265 }
266 MatrixArray<T> m11 = MatrixArray<T>(2, 3, 2, aCasted);
267 MatrixArray<T> m12 = MatrixArray<T>(3, 2, 2, bCasted);
268 MatrixArray<T> m13 = m11 * m12;
269 MatrixArray<T> m14 = MatrixArray<T>(2, 2, 2, cCasted);
271 m14.GetNumCols(),
272 "The number of columns is not as expected.");
274 m14.GetNumRows(),
275 "The number of rows is not as expected.");
276 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
277 NS_LOG_INFO("m11 (2,3,2):" << m11);
278 NS_LOG_INFO("m12 (3,2,2):" << m12);
279 NS_LOG_INFO("m13 = m11 * m12:" << m13);
280
281 // test multiplication by using an initialization matrixArray
282 // matrices have different number of elements per page
283 // matrix dimensions in each page are 4x3, 3x2, and the resulting matrix
284 // dimensions are 4x2
285 a = std::valarray<int>(
286 {0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5});
287 b = std::valarray<int>({0, 1, 0, 1, 0, 1, 0, 10, 0, 10, 0, 10});
288 c = std::valarray<int>({2, 3, 2, 3, 4, 6, 4, 6, 20, 30, 20, 30, 40, 60, 40, 60});
289 aCasted = std::valarray<T>(a.size());
290 bCasted = std::valarray<T>(b.size());
291 cCasted = std::valarray<T>(c.size());
292
293 for (size_t i = 0; i < a.size(); ++i)
294 {
295 aCasted[i] = static_cast<T>(a[i]);
296 }
297 for (size_t i = 0; i < b.size(); ++i)
298 {
299 bCasted[i] = static_cast<T>(b[i]);
300 }
301 for (size_t i = 0; i < c.size(); ++i)
302 {
303 cCasted[i] = static_cast<T>(c[i]);
304 }
305
306 m11 = MatrixArray<T>(4, 3, 2, aCasted);
307 m12 = MatrixArray<T>(3, 2, 2, bCasted);
308 m13 = m11 * m12;
309 m14 = MatrixArray<T>(4, 2, 2, cCasted);
311 m14.GetNumCols(),
312 "The number of columns is not as expected.");
314 m14.GetNumRows(),
315 "The number of rows is not as expected.");
316 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
317 NS_LOG_INFO("m11 (4,3,2):" << m11);
318 NS_LOG_INFO("m12 (3,2,2):" << m12);
319 NS_LOG_INFO("m13 = m11 * m12:" << m13);
320
321 // test multiplication by using an initialization matrixArray
322 // matrices have different number of elements per page
323 // matrix dimensions in each page are 1x3, 3x2, and the resulting matrix has
324 // dimensions 1x2
325 a = std::valarray<int>({5, 4, 5, 5, 4, 5});
326 b = std::valarray<int>({0, 1, 0, 1, 0, 1, 1, 2, 3, 10, 100, 1000});
327 c = std::valarray<int>({4, 10, 28, 5450});
328 aCasted = std::valarray<T>(a.size());
329 bCasted = std::valarray<T>(b.size());
330 cCasted = std::valarray<T>(c.size());
331
332 for (size_t i = 0; i < a.size(); ++i)
333 {
334 aCasted[i] = static_cast<T>(a[i]);
335 }
336 for (size_t i = 0; i < b.size(); ++i)
337 {
338 bCasted[i] = static_cast<T>(b[i]);
339 }
340 for (size_t i = 0; i < c.size(); ++i)
341 {
342 cCasted[i] = static_cast<T>(c[i]);
343 }
344
345 m11 = MatrixArray<T>(1, 3, 2, aCasted);
346 m12 = MatrixArray<T>(3, 2, 2, bCasted);
347 m13 = m11 * m12;
348 m14 = MatrixArray<T>(1, 2, 2, cCasted);
350 m14.GetNumCols(),
351 "The number of columns is not as expected.");
353 m14.GetNumRows(),
354 "The number of rows is not as expected.");
355 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
356 NS_LOG_INFO("m11 (1,3,2):" << m11);
357 NS_LOG_INFO("m12 (3,2,2):" << m12);
358 NS_LOG_INFO("m13 = m11 * m12:" << m13);
359
360 // test MultiplyByLeftAndRightMatrix
361 std::valarray<int> d{1, 1, 1};
362 std::valarray<int> e{1, 1};
363 std::valarray<int> f{1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3};
364 std::valarray<int> g{12, 12};
365 std::valarray<T> dCasted(d.size());
366 std::valarray<T> eCasted(e.size());
367 std::valarray<T> fCasted(f.size());
368 std::valarray<T> gCasted(g.size());
369 for (size_t i = 0; i < d.size(); ++i)
370 {
371 dCasted[i] = static_cast<T>(d[i]);
372 }
373 for (size_t i = 0; i < e.size(); ++i)
374 {
375 eCasted[i] = static_cast<T>(e[i]);
376 }
377 for (size_t i = 0; i < f.size(); ++i)
378 {
379 fCasted[i] = static_cast<T>(f[i]);
380 }
381 for (size_t i = 0; i < g.size(); ++i)
382 {
383 gCasted[i] = static_cast<T>(g[i]);
384 }
385 MatrixArray<T> m15 = MatrixArray<T>(1, 3, dCasted);
386 MatrixArray<T> m16 = MatrixArray<T>(2, 1, eCasted);
387 MatrixArray<T> m17 = MatrixArray<T>(3, 2, 2, fCasted);
388 MatrixArray<T> m18 = MatrixArray<T>(1, 1, 2, gCasted);
390 NS_TEST_ASSERT_MSG_EQ(m19, m18, "The matrices should be equal.");
391
392 // test MultiplyByLeftAndRightMatrix
393 std::valarray<int> h{1, 3, 2, 2, 4, 0};
394 std::valarray<int> j{2, 2, 3, 4, 1, 3, 0, 5};
395 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};
396 std::valarray<int> l{144, 132, 128, 104, 144, 132, 128, 104};
397 std::valarray<T> hCasted(h.size());
398 std::valarray<T> jCasted(j.size());
399 std::valarray<T> kCasted(k.size());
400 std::valarray<T> lCasted(l.size());
401 for (size_t i = 0; i < h.size(); ++i)
402 {
403 hCasted[i] = static_cast<T>(h[i]);
404 }
405 for (size_t i = 0; i < j.size(); ++i)
406 {
407 jCasted[i] = static_cast<T>(j[i]);
408 }
409 for (size_t i = 0; i < k.size(); ++i)
410 {
411 kCasted[i] = static_cast<T>(k[i]);
412 }
413 for (size_t i = 0; i < l.size(); ++i)
414 {
415 lCasted[i] = static_cast<T>(l[i]);
416 }
417 MatrixArray<T> m20 = MatrixArray<T>(2, 3, hCasted);
418 MatrixArray<T> m21 = MatrixArray<T>(4, 2, jCasted);
419 MatrixArray<T> m22 = MatrixArray<T>(3, 4, 2, kCasted);
420 MatrixArray<T> m23 = MatrixArray<T>(2, 2, 2, lCasted);
422 NS_TEST_ASSERT_MSG_EQ(m24, m23, "The matrices should be equal.");
423 NS_LOG_INFO("m20:" << m20);
424 NS_LOG_INFO("m21:" << m21);
425 NS_LOG_INFO("m22:" << m22);
426 NS_LOG_INFO("m24 = m20 * m22 * m21" << m24);
427
428 // test initialization with moving
429 size_t lCastedSize = lCasted.size();
430 NS_LOG_INFO("size() of lCasted before move: " << lCasted.size());
431 MatrixArray<T> m25 = MatrixArray<T>(2, 2, 2, std::move(lCasted));
432 NS_LOG_INFO("m25.GetSize ()" << m25.GetSize());
433 NS_TEST_ASSERT_MSG_EQ(lCastedSize, m25.GetSize(), "The number of elements are not equal.");
434
435 size_t hCastedSize = hCasted.size();
436 NS_LOG_INFO("size() of hCasted before move: " << hCasted.size());
437 MatrixArray<T> m26 = MatrixArray<T>(2, 3, std::move(hCasted));
438 NS_LOG_INFO("m26.GetSize ()" << m26.GetSize());
439 NS_TEST_ASSERT_MSG_EQ(hCastedSize, m26.GetSize(), "The number of elements are not equal.");
440
441 size_t jCastedSize = jCasted.size();
442 NS_LOG_INFO("size() of jCasted before move: " << jCasted.size());
443 MatrixArray<T> m27 = MatrixArray<T>(std::move(jCasted));
444 NS_LOG_INFO("m27.GetSize ()" << m27.GetSize());
445 NS_TEST_ASSERT_MSG_EQ(jCastedSize, m27.GetSize(), "The number of elements are not equal.");
446}
447
448/**
449 * \ingroup matrixArray-tests
450 * Test for testing functions that apply to MatrixArrays that use complex numbers,
451 * such as HermitianTranspose that is only defined for complex type
452 */
454{
455 public:
456 /** Constructor*/
458 /**
459 * Constructor
460 *
461 * \param [in] name reference name
462 */
463 ComplexMatrixArrayTestCase(const std::string& name);
464 /** Destructor*/
466
467 private:
468 void DoRun() override;
469};
470
472 : TestCase("ComplexMatrixArrayTestCase")
473{
474}
475
477 : TestCase(name)
478{
479}
480
482{
483}
484
485void
487{
488 std::valarray<std::complex<double>> complexValarray1 = {
489 {1, 1},
490 {2, 2},
491 {3, 3},
492 {4, 4},
493 {5, 5},
494 {6, 6},
495 {-1, 1},
496 {-2, 2},
497 {-3, 3},
498 {-4, 4},
499 {-5, 5},
500 {-6, 6},
501 };
502 std::valarray<std::complex<double>> complexValarray2 = {
503 {1, -1},
504 {4, -4},
505 {2, -2},
506 {5, -5},
507 {3, -3},
508 {6, -6},
509 {-1, -1},
510 {-4, -4},
511 {-2, -2},
512 {-5, -5},
513 {-3, -3},
514 {-6, -6},
515 };
516 ComplexMatrixArray m1 = ComplexMatrixArray(3, 2, 2, complexValarray1);
517 ComplexMatrixArray m2 = ComplexMatrixArray(2, 3, 2, complexValarray2);
518 ComplexMatrixArray m3 = m1.HermitianTranspose();
519 NS_LOG_INFO("m1 (3, 2, 2):" << m1);
520 NS_LOG_INFO("m2 (2, 3, 2):" << m2);
521 NS_LOG_INFO("m3 (2, 3, 2):" << m3);
522 NS_TEST_ASSERT_MSG_EQ(m2, m3, "m2 and m3 matrices should be equal");
523}
524
525/**
526 * \ingroup matrixArray-tests
527 * MatrixArray test suite
528 */
530{
531 public:
532 /** Constructor. */
534};
535
537 : TestSuite("matrix-array-test")
538{
539 AddTestCase(new MatrixArrayTestCase<double>("Test MatrixArray<double>"));
541 new MatrixArrayTestCase<std::complex<double>>("Test MatrixArray<std::complex<double>>"));
542 AddTestCase(new MatrixArrayTestCase<int>("Test MatrixArray<int>"));
543 AddTestCase(new ComplexMatrixArrayTestCase("Test ComplexMatrixArray"));
544}
545
546/**
547 * \ingroup matrixArray-tests
548 * MatrixArrayTestSuite instance variable.
549 */
551
552} // namespace tests
553} // namespace ns3
MatrixArray class inherits ValArray class and provides additional interfaces to ValArray which enable...
Definition: matrix-array.h:83
MatrixArray Transpose() const
This operator interprets the 3D array as an array of matrices, and performs a linear algebra operatio...
MatrixArray 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:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
const std::valarray< T > & GetValues() const
Returns underlying values.
Definition: val-array.h:565
size_t GetNumPages() const
Definition: val-array.h:398
size_t GetSize() const
Definition: val-array.h:405
size_t GetNumRows() const
Definition: val-array.h:384
size_t GetNumCols() const
Definition: val-array.h:391
Test for testing functions that apply to MatrixArrays that use complex numbers, such as HermitianTran...
void DoRun() override
Implementation to actually run this TestCase.
MatrixArray test case for testing constructors, operators and other functions.
MatrixArrayTestCase(MatrixArrayTestCase< T > &&)=default
Move constructor.
MatrixArrayTestCase< T > & operator=(const MatrixArrayTestCase< T > &)=default
Copy assignment operator.
MatrixArrayTestCase(const MatrixArrayTestCase< T > &)=default
Copy constructor.
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
static MatrixArrayTestSuite g_matrixArrayTestSuite
MatrixArrayTestSuite instance variable.
#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:145
#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:565
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
Every class exported by the ns3 library is enclosed in the ns3 namespace.
MatrixArray< std::complex< double > > ComplexMatrixArray
Create an alias for MatrixArray using complex type.
Definition: matrix-array.h:247