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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Biljana Bojovic <bbojovic@cttc.es>
7 */
8
9#include "ns3/log.h"
10#include "ns3/matrix-array.h"
11#include "ns3/test.h"
12
13#include <algorithm>
14
15/**
16 * @defgroup matrixArray-tests MatrixArray tests
17 * @ingroup core-tests
18 * @ingroup Matrices
19 */
20
21/**
22 * @file
23 * @ingroup matrixArray-tests
24 * MatrixArray test suite
25 */
26namespace ns3
27{
28
29namespace tests
30{
31
32NS_LOG_COMPONENT_DEFINE("MatrixArrayTest");
33
34/**
35 * @brief Function casts an input valArray "in" (type IN) to an output valArray "out" (type T)
36 * @param in Input valarray to be casted
37 * @param out Output valarray to receive casted values
38 */
39template <typename IN, typename T>
40void
41CastStdValarray(const std::valarray<IN>& in, std::valarray<T>& out)
42{
43 // Ensure output valarray is the right size
44 if (out.size() != in.size())
45 {
46 out.resize(in.size());
47 }
48
49 // Perform the cast operation
50 std::transform(std::begin(in), std::end(in), std::begin(out), [](IN i) {
51 return static_cast<T>(i);
52 });
53}
54
55/**
56 * @ingroup matrixArray-tests
57 * MatrixArray test case for testing constructors, operators and other functions
58 */
59template <class T>
61{
62 public:
64 /**
65 * Constructor
66 *
67 * @param [in] name reference name
68 */
69 MatrixArrayTestCase(const std::string& name);
70
71 /** Destructor. */
72 ~MatrixArrayTestCase() override;
73 /**
74 * @brief Copy constructor.
75 * Instruct the compiler to generate the implicitly declared copy constructor
76 */
78 /**
79 * @brief Copy assignment operator.
80 * Instruct the compiler to generate the implicitly declared copy assignment operator.
81 * @return A reference to this MatrixArrayTestCase
82 */
84 /**
85 * @brief Move constructor.
86 * Instruct the compiler to generate the implicitly declared move constructor
87 */
89 /**
90 * @brief Move assignment operator.
91 * Instruct the compiler to generate the implicitly declared copy constructor
92 * @return A reference to this MatrixArrayTestCase
93 */
95
96 protected:
97 private:
98 void DoRun() override;
99};
100
101template <class T>
103 : TestCase(name)
104{
105}
106
107template <class T>
111
112template <class T>
113void
115{
116 // test multiplication of matrices (MatrixArray containing only 1 matrix)
118 MatrixArray<T> m2 = MatrixArray<T>(m1.GetNumCols(), m1.GetNumRows());
119 for (size_t i = 0; i < m1.GetNumRows(); ++i)
120 {
121 for (size_t j = 0; j < m1.GetNumCols(); ++j)
122 {
123 m1(i, j) = 1;
124 m2(j, i) = 1;
125 }
126 }
127 MatrixArray<T> m3 = m1 * m2;
128 NS_LOG_INFO("m1:" << m1);
129 NS_LOG_INFO("m2:" << m2);
130 NS_LOG_INFO("m3 = m1 * m2:" << m3);
132 m1.GetNumRows(),
133 "The number of rows in resulting matrix is not correct");
135 m2.GetNumCols(),
136 "The number of cols in resulting matrix is not correct");
138 m3.GetNumCols(),
139 "The number of rows and cols should be equal");
140 for (size_t i = 0; i < m3.GetNumCols(); ++i)
141 {
142 for (size_t j = 0; j < m3.GetNumRows(); ++j)
143 {
144 NS_TEST_ASSERT_MSG_EQ(std::real(m3(i, j)),
145 m1.GetNumCols(),
146 "The element value should be " << m1.GetNumCols());
147 }
148 }
149
150 // multiplication with a scalar value
151 MatrixArray<T> m4 = m3 * (static_cast<T>(5.0));
152 for (size_t i = 0; i < m4.GetNumCols(); ++i)
153 {
154 for (size_t j = 0; j < m4.GetNumRows(); ++j)
155 {
156 NS_TEST_ASSERT_MSG_EQ(m3(i, j) * (static_cast<T>(5.0)),
157 m4(i, j),
158 "The values are not equal");
159 }
160 }
161 NS_LOG_INFO("m4 = m3 * 5:" << m4);
162
163 // test multiplication of arrays of matrices
164 MatrixArray<T> m5 = MatrixArray<T>(2, 3, 2);
166 for (size_t p = 0; p < m5.GetNumPages(); ++p)
167 {
168 for (size_t i = 0; i < m5.GetNumRows(); ++i)
169 {
170 for (size_t j = 0; j < m5.GetNumCols(); ++j)
171 {
172 m5(i, j, p) = 1;
173 m6(j, i, p) = 1;
174 }
175 }
176 }
177 MatrixArray<T> m7 = m5 * m6;
179 m5.GetNumRows(),
180 "The number of rows in resulting matrix is not correct");
182 m6.GetNumCols(),
183 "The number of cols in resulting matrix is not correct");
185 m7.GetNumCols(),
186 "The number of rows and cols should be equal");
187
188 for (size_t p = 0; p < m7.GetNumPages(); ++p)
189 {
190 for (size_t i = 0; i < m7.GetNumCols(); ++i)
191 {
192 for (size_t j = 0; j < m7.GetNumRows(); ++j)
193 {
194 NS_TEST_ASSERT_MSG_EQ(std::real(m7(i, j, p)),
195 m5.GetNumCols(),
196 "The element value should be " << m5.GetNumCols());
197 }
198 }
199 }
200 // test ostream operator
201 NS_LOG_INFO("m5:" << m5);
202 NS_LOG_INFO("m6:" << m6);
203 NS_LOG_INFO("m7 = m5 * m6:" << m7);
204
205 // test transpose function
206 MatrixArray<T> m8 = m5.Transpose();
207 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
208 NS_LOG_INFO("m8 = m5.Transpose ()" << m8);
209
210 // test transpose using initialization arrays
211 std::valarray<int> a{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};
212 std::valarray<int> b{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4};
213 std::valarray<T> aCasted(a.size());
214 std::valarray<T> bCasted(b.size());
215 for (size_t i = 0; i < a.size(); ++i)
216 {
217 aCasted[i] = static_cast<T>(a[i]);
218 }
219 for (size_t i = 0; i < b.size(); ++i)
220 {
221 bCasted[i] = static_cast<T>(b[i]);
222 }
223 m5 = MatrixArray<T>(3, 5, 1, aCasted);
224 m6 = MatrixArray<T>(5, 3, 1, bCasted);
225 m8 = m5.Transpose();
226 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
227 NS_LOG_INFO("m5 (3, 5, 1):" << m5);
228 NS_LOG_INFO("m6 (5, 3, 1):" << m6);
229 NS_LOG_INFO("m8 (5, 3, 1) = m5.Transpose ()" << m8);
230
231 // test 1D array creation, i.e. vector and transposing it
232 MatrixArray<T> m9 = MatrixArray<T>(std::vector<T>({0, 1, 2, 3, 4, 5, 6, 7}));
233 NS_TEST_ASSERT_MSG_EQ((m9.GetNumRows() == 8) && (m9.GetNumCols() == 1) &&
234 (m9.GetNumPages() == 1),
235 true,
236 "Creation of vector is not correct.");
237
238 NS_LOG_INFO("Vector:" << m9);
239 NS_LOG_INFO("Vector after transposing:" << m9.Transpose());
240
241 // Test basic operators
242 MatrixArray<T> m10 =
244 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
245 m10 -= m9;
246 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
247 m10 += m9;
248 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
249 m10 = m9;
250 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
251 m10 = m9 + m9;
252 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
253 m10 = m10 - m9;
254 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
255
256 // test multiplication by using an initialization matrixArray
257 // matrix dimensions in each page are 2x3, 3x2, and the resulting matrix per page is a square
258 // matrix 2x2
259 a = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5};
260 b = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
261 std::valarray<int> c{2, 3, 4, 6, 2, 3, 4, 6};
262 aCasted = std::valarray<T>(a.size());
263 bCasted = std::valarray<T>(b.size());
264 std::valarray<T> cCasted = std::valarray<T>(c.size());
265
266 for (size_t i = 0; i < a.size(); ++i)
267 {
268 aCasted[i] = static_cast<T>(a[i]);
269 }
270 for (size_t i = 0; i < b.size(); ++i)
271 {
272 bCasted[i] = static_cast<T>(b[i]);
273 }
274 for (size_t i = 0; i < c.size(); ++i)
275 {
276 cCasted[i] = static_cast<T>(c[i]);
277 }
278 MatrixArray<T> m11 = MatrixArray<T>(2, 3, 2, aCasted);
279 MatrixArray<T> m12 = MatrixArray<T>(3, 2, 2, bCasted);
280 MatrixArray<T> m13 = m11 * m12;
281 MatrixArray<T> m14 = MatrixArray<T>(2, 2, 2, cCasted);
283 m14.GetNumCols(),
284 "The number of columns is not as expected.");
286 m14.GetNumRows(),
287 "The number of rows is not as expected.");
288 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
289 NS_LOG_INFO("m11 (2,3,2):" << m11);
290 NS_LOG_INFO("m12 (3,2,2):" << m12);
291 NS_LOG_INFO("m13 = m11 * m12:" << m13);
292
293 // test multiplication by using an initialization matrixArray
294 // matrices have different number of elements per page
295 // matrix dimensions in each page are 4x3, 3x2, and the resulting matrix
296 // dimensions are 4x2
297 a = std::valarray<int>(
298 {0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5});
299 b = std::valarray<int>({0, 1, 0, 1, 0, 1, 0, 10, 0, 10, 0, 10});
300 c = std::valarray<int>({2, 3, 2, 3, 4, 6, 4, 6, 20, 30, 20, 30, 40, 60, 40, 60});
301 aCasted = std::valarray<T>(a.size());
302 bCasted = std::valarray<T>(b.size());
303 cCasted = std::valarray<T>(c.size());
304
305 for (size_t i = 0; i < a.size(); ++i)
306 {
307 aCasted[i] = static_cast<T>(a[i]);
308 }
309 for (size_t i = 0; i < b.size(); ++i)
310 {
311 bCasted[i] = static_cast<T>(b[i]);
312 }
313 for (size_t i = 0; i < c.size(); ++i)
314 {
315 cCasted[i] = static_cast<T>(c[i]);
316 }
317
318 m11 = MatrixArray<T>(4, 3, 2, aCasted);
319 m12 = MatrixArray<T>(3, 2, 2, bCasted);
320 m13 = m11 * m12;
321 m14 = MatrixArray<T>(4, 2, 2, cCasted);
323 m14.GetNumCols(),
324 "The number of columns is not as expected.");
326 m14.GetNumRows(),
327 "The number of rows is not as expected.");
328 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
329 NS_LOG_INFO("m11 (4,3,2):" << m11);
330 NS_LOG_INFO("m12 (3,2,2):" << m12);
331 NS_LOG_INFO("m13 = m11 * m12:" << m13);
332
333 // test multiplication by using an initialization matrixArray
334 // matrices have different number of elements per page
335 // matrix dimensions in each page are 1x3, 3x2, and the resulting matrix has
336 // dimensions 1x2
337 a = std::valarray<int>({5, 4, 5, 5, 4, 5});
338 b = std::valarray<int>({0, 1, 0, 1, 0, 1, 1, 2, 3, 10, 100, 1000});
339 c = std::valarray<int>({4, 10, 28, 5450});
340 aCasted = std::valarray<T>(a.size());
341 bCasted = std::valarray<T>(b.size());
342 cCasted = std::valarray<T>(c.size());
343
344 for (size_t i = 0; i < a.size(); ++i)
345 {
346 aCasted[i] = static_cast<T>(a[i]);
347 }
348 for (size_t i = 0; i < b.size(); ++i)
349 {
350 bCasted[i] = static_cast<T>(b[i]);
351 }
352 for (size_t i = 0; i < c.size(); ++i)
353 {
354 cCasted[i] = static_cast<T>(c[i]);
355 }
356
357 m11 = MatrixArray<T>(1, 3, 2, aCasted);
358 m12 = MatrixArray<T>(3, 2, 2, bCasted);
359 m13 = m11 * m12;
360 m14 = MatrixArray<T>(1, 2, 2, cCasted);
362 m14.GetNumCols(),
363 "The number of columns is not as expected.");
365 m14.GetNumRows(),
366 "The number of rows is not as expected.");
367 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
368 NS_LOG_INFO("m11 (1,3,2):" << m11);
369 NS_LOG_INFO("m12 (3,2,2):" << m12);
370 NS_LOG_INFO("m13 = m11 * m12:" << m13);
371
372 // test MultiplyByLeftAndRightMatrix
373 std::valarray<int> d{1, 1, 1};
374 std::valarray<int> e{1, 1};
375 std::valarray<int> f{1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3};
376 std::valarray<int> g{12, 12};
377 std::valarray<T> dCasted(d.size());
378 std::valarray<T> eCasted(e.size());
379 std::valarray<T> fCasted(f.size());
380 std::valarray<T> gCasted(g.size());
381 for (size_t i = 0; i < d.size(); ++i)
382 {
383 dCasted[i] = static_cast<T>(d[i]);
384 }
385 for (size_t i = 0; i < e.size(); ++i)
386 {
387 eCasted[i] = static_cast<T>(e[i]);
388 }
389 for (size_t i = 0; i < f.size(); ++i)
390 {
391 fCasted[i] = static_cast<T>(f[i]);
392 }
393 for (size_t i = 0; i < g.size(); ++i)
394 {
395 gCasted[i] = static_cast<T>(g[i]);
396 }
397 MatrixArray<T> m15 = MatrixArray<T>(1, 3, dCasted);
398 MatrixArray<T> m16 = MatrixArray<T>(2, 1, eCasted);
399 MatrixArray<T> m17 = MatrixArray<T>(3, 2, 2, fCasted);
400 MatrixArray<T> m18 = MatrixArray<T>(1, 1, 2, gCasted);
402 NS_TEST_ASSERT_MSG_EQ(m19, m18, "The matrices should be equal.");
403
404 // test MultiplyByLeftAndRightMatrix
405 std::valarray<int> h{1, 3, 2, 2, 4, 0};
406 std::valarray<int> j{2, 2, 3, 4, 1, 3, 0, 5};
407 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};
408 std::valarray<int> l{144, 132, 128, 104, 144, 132, 128, 104};
409 std::valarray<T> hCasted(h.size());
410 std::valarray<T> jCasted(j.size());
411 std::valarray<T> kCasted(k.size());
412 std::valarray<T> lCasted(l.size());
413 for (size_t i = 0; i < h.size(); ++i)
414 {
415 hCasted[i] = static_cast<T>(h[i]);
416 }
417 for (size_t i = 0; i < j.size(); ++i)
418 {
419 jCasted[i] = static_cast<T>(j[i]);
420 }
421 for (size_t i = 0; i < k.size(); ++i)
422 {
423 kCasted[i] = static_cast<T>(k[i]);
424 }
425 for (size_t i = 0; i < l.size(); ++i)
426 {
427 lCasted[i] = static_cast<T>(l[i]);
428 }
429 MatrixArray<T> m20 = MatrixArray<T>(2, 3, hCasted);
430 MatrixArray<T> m21 = MatrixArray<T>(4, 2, jCasted);
431 MatrixArray<T> m22 = MatrixArray<T>(3, 4, 2, kCasted);
432 MatrixArray<T> m23 = MatrixArray<T>(2, 2, 2, lCasted);
434 NS_TEST_ASSERT_MSG_EQ(m24, m23, "The matrices should be equal.");
435 NS_LOG_INFO("m20:" << m20);
436 NS_LOG_INFO("m21:" << m21);
437 NS_LOG_INFO("m22:" << m22);
438 NS_LOG_INFO("m24 = m20 * m22 * m21" << m24);
439
440 // test initialization with moving
441 size_t lCastedSize = lCasted.size();
442 NS_LOG_INFO("size() of lCasted before move: " << lCasted.size());
443 MatrixArray<T> m25 = MatrixArray<T>(2, 2, 2, std::move(lCasted));
444 NS_LOG_INFO("m25.GetSize ()" << m25.GetSize());
445 NS_TEST_ASSERT_MSG_EQ(lCastedSize, m25.GetSize(), "The number of elements are not equal.");
446
447 size_t hCastedSize = hCasted.size();
448 NS_LOG_INFO("size() of hCasted before move: " << hCasted.size());
449 MatrixArray<T> m26 = MatrixArray<T>(2, 3, std::move(hCasted));
450 NS_LOG_INFO("m26.GetSize ()" << m26.GetSize());
451 NS_TEST_ASSERT_MSG_EQ(hCastedSize, m26.GetSize(), "The number of elements are not equal.");
452
453 size_t jCastedSize = jCasted.size();
454 NS_LOG_INFO("size() of jCasted before move: " << jCasted.size());
455 MatrixArray<T> m27 = MatrixArray<T>(std::move(jCasted));
456 NS_LOG_INFO("m27.GetSize ()" << m27.GetSize());
457 NS_TEST_ASSERT_MSG_EQ(jCastedSize, m27.GetSize(), "The number of elements are not equal.");
458
459 // test determinant
460 {
461 std::vector<std::pair<std::valarray<int>, T>> detTestCases{
462 // right-wraparound
463 {{1, 0, 7, 4, 2, 0, 6, 5, 3}, 62},
464 // left-wraparound
465 {{1, 4, 6, 0, 2, 5, 7, 0, 3}, 62},
466 // identity rank 3
467 {{1, 0, 0, 0, 1, 0, 0, 0, 1}, 1},
468 // identity rank 4
469 {{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, 1},
470 // permutation matrix rank 4
471 {{0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0}, -1},
472 // positive det matrix rank 2
473 {{36, -5, -5, 43}, 1523},
474 // single value matrix rank 1
475 {{1}, 1},
476 };
477 for (const auto& [detVal, detRef] : detTestCases)
478 {
479 std::valarray<T> detCast(detVal.size());
480 CastStdValarray(detVal, detCast);
481 auto side = sqrt(detVal.size());
482 MatrixArray<T> detMat = MatrixArray<T>(side, side, std::move(detCast));
484 static_cast<T>(detRef),
485 "The determinants are not equal.");
486 }
487 }
488 // clang-format off
489 std::valarray<int> multiPageMatrixValues{
490 // page 0: identity matrix
491 1, 0, 0,
492 0, 1, 0,
493 0, 0, 1,
494 // page 1: permutation matrix
495 0, 0, 1,
496 0, 1, 0,
497 1, 0, 0,
498 // page 2: random matrix
499 1, 4, 6,
500 0, 2, 5,
501 7, 0, 3,
502 // page 3: upper triangular
503 5, -9, 2,
504 0, -4, -10,
505 0, 0, -3,
506 // page 4: lower triangular
507 -7, 0, 0,
508 -1, -9, 0,
509 -5, 6, -5,
510 // page 5: zero diagonal
511 0, 1, 2,
512 1, 0, 1,
513 2, 1, 0,
514 // page 6: zero bidiagonal
515 0, 1, 0,
516 1, 0, 1,
517 0, 1, 0
518 };
519 // clang-format on
520 std::valarray<T> castMultiPageMatrixValues(multiPageMatrixValues.size());
521 CastStdValarray(multiPageMatrixValues, castMultiPageMatrixValues);
522 MatrixArray<T> multiPageMatrix = MatrixArray<T>(3,
523 3,
524 multiPageMatrixValues.size() / 9,
525 std::move(castMultiPageMatrixValues));
526 // test the determinant in a multi-page MatrixArray
527 std::vector<int> determinants = {1, -1, 62, 60, -315, 4, 0};
528 auto det = multiPageMatrix.Determinant();
529 for (size_t page = 0; page < multiPageMatrix.GetNumPages(); page++)
530 {
531 NS_TEST_ASSERT_MSG_EQ(det(page),
532 static_cast<T>(determinants[page]),
533 "The determinants from the page " << std::to_string(page)
534 << " are not equal.");
535 }
536
537 // test Frobenius norm in a multi-page MatrixArray
538 std::vector<double> fnorms = {sqrt(3), sqrt(3), 11.8322, 15.3297, 14.7309, 3.4641, 2};
539 auto frob = multiPageMatrix.FrobeniusNorm();
540 for (size_t page = 0; page < multiPageMatrix.GetNumPages(); page++)
541 {
542 NS_TEST_ASSERT_MSG_EQ_TOL(std::abs(frob(page)),
543 std::abs(static_cast<T>(fnorms[page])),
544 0.0001,
545 "The Frobenius norm from the page " << std::to_string(page)
546 << " are not equal.");
547 }
548
549 // test page copying
550 for (size_t noOfCopies = 1; noOfCopies < 4; noOfCopies++)
551 {
552 auto copies = m27.MakeNCopies(noOfCopies);
553 NS_TEST_ASSERT_MSG_EQ(copies.GetNumPages(),
554 noOfCopies,
555 "Creating " << std::to_string(noOfCopies) << " copies failed.");
556 NS_TEST_ASSERT_MSG_EQ(copies.GetNumRows(),
557 m27.GetNumRows(),
558 "The copy doesn't have the same number of rows as the original.");
559 NS_TEST_ASSERT_MSG_EQ(copies.GetNumCols(),
560 m27.GetNumCols(),
561 "The copy doesn't have the same number of columns as the original.");
562 for (size_t page = 0; page < copies.GetNumPages(); page++)
563 {
564 T diff{};
565 for (size_t row = 0; row < copies.GetNumRows(); row++)
566 {
567 for (size_t col = 0; col < copies.GetNumCols(); col++)
568 {
569 diff += m27(row, col, 0) - copies(row, col, page);
570 }
571 }
572 NS_TEST_ASSERT_MSG_EQ(diff, T{}, "Mismatch in copied values.");
573 }
574 }
575
576 // test page 1 and 0 extraction
577 std::vector<MatrixArray<T>> pages{multiPageMatrix.ExtractPage(1),
578 multiPageMatrix.ExtractPage(0)};
579
580 // test page 1 and 0 joining
581 auto jointPagesMatrix = MatrixArray<T>::JoinPages(pages);
582 NS_TEST_ASSERT_MSG_EQ(jointPagesMatrix.GetNumPages(), 2, "Mismatch in number of join pages.");
583 for (size_t page = 0; page < jointPagesMatrix.GetNumPages(); page++)
584 {
585 T diff{};
586 for (size_t row = 0; row < jointPagesMatrix.GetNumRows(); row++)
587 {
588 for (size_t col = 0; col < jointPagesMatrix.GetNumCols(); col++)
589 {
590 diff += multiPageMatrix(row, col, 1 - page) - jointPagesMatrix(row, col, page);
591 }
592 }
593 NS_TEST_ASSERT_MSG_EQ(diff, T{}, "Mismatching pages.");
594 }
595
596 // test identity matrix
597 auto identityRank3Reference = multiPageMatrix.ExtractPage(0);
598 auto identityRank3 = MatrixArray<T>::IdentityMatrix(3);
599 NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
600
601 identityRank3 = MatrixArray<T>::IdentityMatrix(3, 10).ExtractPage(9);
602 NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
603
604 identityRank3 = MatrixArray<T>::IdentityMatrix(identityRank3Reference);
605 NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
606}
607
608/**
609 * @ingroup matrixArray-tests
610 * Test for testing functions that apply to MatrixArrays that use complex numbers,
611 * such as HermitianTranspose that is only defined for complex type
612 */
614{
615 public:
616 /** Constructor*/
618 /**
619 * Constructor
620 *
621 * @param [in] name reference name
622 */
623 ComplexMatrixArrayTestCase(const std::string& name);
624 /** Destructor*/
626
627 private:
628 void DoRun() override;
629};
630
632 : TestCase("ComplexMatrixArrayTestCase")
633{
634}
635
637 : TestCase(name)
638{
639}
640
644
645void
647{
648 std::valarray<std::complex<double>> complexValarray1 = {
649 {1, 1},
650 {2, 2},
651 {3, 3},
652 {4, 4},
653 {5, 5},
654 {6, 6},
655 {-1, 1},
656 {-2, 2},
657 {-3, 3},
658 {-4, 4},
659 {-5, 5},
660 {-6, 6},
661 };
662 std::valarray<std::complex<double>> complexValarray2 = {
663 {1, -1},
664 {4, -4},
665 {2, -2},
666 {5, -5},
667 {3, -3},
668 {6, -6},
669 {-1, -1},
670 {-4, -4},
671 {-2, -2},
672 {-5, -5},
673 {-3, -3},
674 {-6, -6},
675 };
676 ComplexMatrixArray m1 = ComplexMatrixArray(3, 2, 2, complexValarray1);
677 ComplexMatrixArray m2 = ComplexMatrixArray(2, 3, 2, complexValarray2);
678 ComplexMatrixArray m3 = m1.HermitianTranspose();
679 NS_LOG_INFO("m1 (3, 2, 2):" << m1);
680 NS_LOG_INFO("m2 (2, 3, 2):" << m2);
681 NS_LOG_INFO("m3 (2, 3, 2):" << m3);
682 NS_TEST_ASSERT_MSG_EQ(m2, m3, "m2 and m3 matrices should be equal");
683}
684
685/**
686 * @ingroup matrixArray-tests
687 * MatrixArray test suite
688 */
690{
691 public:
692 /** Constructor. */
694};
695
697 : TestSuite("matrix-array-test")
698{
699 AddTestCase(new MatrixArrayTestCase<double>("Test MatrixArray<double>"));
701 new MatrixArrayTestCase<std::complex<double>>("Test MatrixArray<std::complex<double>>"));
702 AddTestCase(new MatrixArrayTestCase<int>("Test MatrixArray<int>"));
703 AddTestCase(new ComplexMatrixArrayTestCase("Test ComplexMatrixArray"));
704}
705
706/**
707 * @ingroup matrixArray-tests
708 * MatrixArrayTestSuite instance variable.
709 */
711
712} // namespace tests
713} // namespace ns3
MatrixArray class inherits ValArray class and provides additional interfaces to ValArray which enable...
MatrixArray Determinant() const
This operator calculates a vector o determinants, one for each page.
static MatrixArray< T > IdentityMatrix(const size_t size, const size_t pages=1)
Function produces an identity MatrixArray with the specified size.
static MatrixArray< T > JoinPages(const std::vector< MatrixArray< T > > &pages)
Function joins multiple pages into a single MatrixArray.
MatrixArray Transpose() const
This operator interprets the 3D array as an array of matrices, and performs a linear algebra operatio...
MatrixArray< T > MakeNCopies(size_t nCopies) const
Function that copies the current 1-page matrix into a new matrix with n copies of the original matrix...
MatrixArray< T > ExtractPage(size_t page) const
Function extracts a page from a MatrixArray.
MatrixArray MultiplyByLeftAndRightMatrix(const MatrixArray< T > &lMatrix, const MatrixArray< T > &rMatrix) const
Multiply each matrix in the array by the left and the right matrix.
MatrixArray FrobeniusNorm() const
This operator calculates a vector of Frobenius norm, one for each page.
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
const std::valarray< T > & GetValues() const
Returns underlying values.
Definition val-array.h:554
size_t GetNumPages() const
Definition val-array.h:387
size_t GetSize() const
Definition val-array.h:394
size_t GetNumRows() const
Definition val-array.h:373
size_t GetNumCols() const
Definition val-array.h:380
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:191
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
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:134
#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:554
#define NS_TEST_ASSERT_MSG_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report and...
Definition test.h:327
const double m1
First component modulus, 232 - 209.
Definition rng-stream.cc:49
const double m2
Second component modulus, 232 - 22853.
Definition rng-stream.cc:52
void CastStdValarray(const std::valarray< IN > &in, std::valarray< T > &out)
Function casts an input valArray "in" (type IN) to an output valArray "out" (type T)
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.