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 private:
97 void DoRun() override;
98};
99
100template <class T>
102 : TestCase(name)
103{
104}
105
106template <class T>
110
111template <class T>
112void
114{
115 // test multiplication of matrices (MatrixArray containing only 1 matrix)
117 MatrixArray<T> m2 = MatrixArray<T>(m1.GetNumCols(), m1.GetNumRows());
118 for (size_t i = 0; i < m1.GetNumRows(); ++i)
119 {
120 for (size_t j = 0; j < m1.GetNumCols(); ++j)
121 {
122 m1(i, j) = 1;
123 m2(j, i) = 1;
124 }
125 }
126 MatrixArray<T> m3 = m1 * m2;
127 NS_LOG_INFO("m1:" << m1);
128 NS_LOG_INFO("m2:" << m2);
129 NS_LOG_INFO("m3 = m1 * m2:" << m3);
131 m1.GetNumRows(),
132 "The number of rows in resulting matrix is not correct");
134 m2.GetNumCols(),
135 "The number of cols in resulting matrix is not correct");
137 m3.GetNumCols(),
138 "The number of rows and cols should be equal");
139 for (size_t i = 0; i < m3.GetNumCols(); ++i)
140 {
141 for (size_t j = 0; j < m3.GetNumRows(); ++j)
142 {
143 NS_TEST_ASSERT_MSG_EQ(std::real(m3(i, j)),
144 m1.GetNumCols(),
145 "The element value should be " << m1.GetNumCols());
146 }
147 }
148
149 // multiplication with a scalar value
150 MatrixArray<T> m4 = m3 * (static_cast<T>(5.0));
151 for (size_t i = 0; i < m4.GetNumCols(); ++i)
152 {
153 for (size_t j = 0; j < m4.GetNumRows(); ++j)
154 {
155 NS_TEST_ASSERT_MSG_EQ(m3(i, j) * (static_cast<T>(5.0)),
156 m4(i, j),
157 "The values are not equal");
158 }
159 }
160 NS_LOG_INFO("m4 = m3 * 5:" << m4);
161
162 // test multiplication of arrays of matrices
163 MatrixArray<T> m5 = MatrixArray<T>(2, 3, 2);
165 for (size_t p = 0; p < m5.GetNumPages(); ++p)
166 {
167 for (size_t i = 0; i < m5.GetNumRows(); ++i)
168 {
169 for (size_t j = 0; j < m5.GetNumCols(); ++j)
170 {
171 m5(i, j, p) = 1;
172 m6(j, i, p) = 1;
173 }
174 }
175 }
176 MatrixArray<T> m7 = m5 * m6;
178 m5.GetNumRows(),
179 "The number of rows in resulting matrix is not correct");
181 m6.GetNumCols(),
182 "The number of cols in resulting matrix is not correct");
184 m7.GetNumCols(),
185 "The number of rows and cols should be equal");
186
187 for (size_t p = 0; p < m7.GetNumPages(); ++p)
188 {
189 for (size_t i = 0; i < m7.GetNumCols(); ++i)
190 {
191 for (size_t j = 0; j < m7.GetNumRows(); ++j)
192 {
193 NS_TEST_ASSERT_MSG_EQ(std::real(m7(i, j, p)),
194 m5.GetNumCols(),
195 "The element value should be " << m5.GetNumCols());
196 }
197 }
198 }
199 // test ostream operator
200 NS_LOG_INFO("m5:" << m5);
201 NS_LOG_INFO("m6:" << m6);
202 NS_LOG_INFO("m7 = m5 * m6:" << m7);
203
204 // test transpose function
205 MatrixArray<T> m8 = m5.Transpose();
206 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
207 NS_LOG_INFO("m8 = m5.Transpose ()" << m8);
208
209 // test transpose using initialization arrays
210 std::valarray<int> a{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};
211 std::valarray<int> b{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4};
212 std::valarray<T> aCasted(a.size());
213 std::valarray<T> bCasted(b.size());
214 for (size_t i = 0; i < a.size(); ++i)
215 {
216 aCasted[i] = static_cast<T>(a[i]);
217 }
218 for (size_t i = 0; i < b.size(); ++i)
219 {
220 bCasted[i] = static_cast<T>(b[i]);
221 }
222 m5 = MatrixArray<T>(3, 5, 1, aCasted);
223 m6 = MatrixArray<T>(5, 3, 1, bCasted);
224 m8 = m5.Transpose();
225 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
226 NS_LOG_INFO("m5 (3, 5, 1):" << m5);
227 NS_LOG_INFO("m6 (5, 3, 1):" << m6);
228 NS_LOG_INFO("m8 (5, 3, 1) = m5.Transpose ()" << m8);
229
230 // test 1D array creation, i.e. vector and transposing it
231 MatrixArray<T> m9 = MatrixArray<T>(std::vector<T>({0, 1, 2, 3, 4, 5, 6, 7}));
232 NS_TEST_ASSERT_MSG_EQ((m9.GetNumRows() == 8) && (m9.GetNumCols() == 1) &&
233 (m9.GetNumPages() == 1),
234 true,
235 "Creation of vector is not correct.");
236
237 NS_LOG_INFO("Vector:" << m9);
238 NS_LOG_INFO("Vector after transposing:" << m9.Transpose());
239
240 // Test basic operators
241 MatrixArray<T> m10 =
243 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
244 m10 -= m9;
245 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
246 m10 += m9;
247 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
248 m10 = m9;
249 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
250 m10 = m9 + m9;
251 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
252 m10 = m10 - m9;
253 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
254
255 // test multiplication by using an initialization matrixArray
256 // matrix dimensions in each page are 2x3, 3x2, and the resulting matrix per page is a square
257 // matrix 2x2
258 a = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5};
259 b = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
260 std::valarray<int> c{2, 3, 4, 6, 2, 3, 4, 6};
261 aCasted = std::valarray<T>(a.size());
262 bCasted = std::valarray<T>(b.size());
263 std::valarray<T> cCasted = std::valarray<T>(c.size());
264
265 for (size_t i = 0; i < a.size(); ++i)
266 {
267 aCasted[i] = static_cast<T>(a[i]);
268 }
269 for (size_t i = 0; i < b.size(); ++i)
270 {
271 bCasted[i] = static_cast<T>(b[i]);
272 }
273 for (size_t i = 0; i < c.size(); ++i)
274 {
275 cCasted[i] = static_cast<T>(c[i]);
276 }
277 MatrixArray<T> m11 = MatrixArray<T>(2, 3, 2, aCasted);
278 MatrixArray<T> m12 = MatrixArray<T>(3, 2, 2, bCasted);
279 MatrixArray<T> m13 = m11 * m12;
280 MatrixArray<T> m14 = MatrixArray<T>(2, 2, 2, cCasted);
282 m14.GetNumCols(),
283 "The number of columns is not as expected.");
285 m14.GetNumRows(),
286 "The number of rows is not as expected.");
287 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
288 NS_LOG_INFO("m11 (2,3,2):" << m11);
289 NS_LOG_INFO("m12 (3,2,2):" << m12);
290 NS_LOG_INFO("m13 = m11 * m12:" << m13);
291
292 // test multiplication by using an initialization matrixArray
293 // matrices have different number of elements per page
294 // matrix dimensions in each page are 4x3, 3x2, and the resulting matrix
295 // dimensions are 4x2
296 a = std::valarray<int>(
297 {0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5});
298 b = std::valarray<int>({0, 1, 0, 1, 0, 1, 0, 10, 0, 10, 0, 10});
299 c = std::valarray<int>({2, 3, 2, 3, 4, 6, 4, 6, 20, 30, 20, 30, 40, 60, 40, 60});
300 aCasted = std::valarray<T>(a.size());
301 bCasted = std::valarray<T>(b.size());
302 cCasted = std::valarray<T>(c.size());
303
304 for (size_t i = 0; i < a.size(); ++i)
305 {
306 aCasted[i] = static_cast<T>(a[i]);
307 }
308 for (size_t i = 0; i < b.size(); ++i)
309 {
310 bCasted[i] = static_cast<T>(b[i]);
311 }
312 for (size_t i = 0; i < c.size(); ++i)
313 {
314 cCasted[i] = static_cast<T>(c[i]);
315 }
316
317 m11 = MatrixArray<T>(4, 3, 2, aCasted);
318 m12 = MatrixArray<T>(3, 2, 2, bCasted);
319 m13 = m11 * m12;
320 m14 = MatrixArray<T>(4, 2, 2, cCasted);
322 m14.GetNumCols(),
323 "The number of columns is not as expected.");
325 m14.GetNumRows(),
326 "The number of rows is not as expected.");
327 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
328 NS_LOG_INFO("m11 (4,3,2):" << m11);
329 NS_LOG_INFO("m12 (3,2,2):" << m12);
330 NS_LOG_INFO("m13 = m11 * m12:" << m13);
331
332 // test multiplication by using an initialization matrixArray
333 // matrices have different number of elements per page
334 // matrix dimensions in each page are 1x3, 3x2, and the resulting matrix has
335 // dimensions 1x2
336 a = std::valarray<int>({5, 4, 5, 5, 4, 5});
337 b = std::valarray<int>({0, 1, 0, 1, 0, 1, 1, 2, 3, 10, 100, 1000});
338 c = std::valarray<int>({4, 10, 28, 5450});
339 aCasted = std::valarray<T>(a.size());
340 bCasted = std::valarray<T>(b.size());
341 cCasted = std::valarray<T>(c.size());
342
343 for (size_t i = 0; i < a.size(); ++i)
344 {
345 aCasted[i] = static_cast<T>(a[i]);
346 }
347 for (size_t i = 0; i < b.size(); ++i)
348 {
349 bCasted[i] = static_cast<T>(b[i]);
350 }
351 for (size_t i = 0; i < c.size(); ++i)
352 {
353 cCasted[i] = static_cast<T>(c[i]);
354 }
355
356 m11 = MatrixArray<T>(1, 3, 2, aCasted);
357 m12 = MatrixArray<T>(3, 2, 2, bCasted);
358 m13 = m11 * m12;
359 m14 = MatrixArray<T>(1, 2, 2, cCasted);
361 m14.GetNumCols(),
362 "The number of columns is not as expected.");
364 m14.GetNumRows(),
365 "The number of rows is not as expected.");
366 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
367 NS_LOG_INFO("m11 (1,3,2):" << m11);
368 NS_LOG_INFO("m12 (3,2,2):" << m12);
369 NS_LOG_INFO("m13 = m11 * m12:" << m13);
370
371 // test MultiplyByLeftAndRightMatrix
372 std::valarray<int> d{1, 1, 1};
373 std::valarray<int> e{1, 1};
374 std::valarray<int> f{1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3};
375 std::valarray<int> g{12, 12};
376 std::valarray<T> dCasted(d.size());
377 std::valarray<T> eCasted(e.size());
378 std::valarray<T> fCasted(f.size());
379 std::valarray<T> gCasted(g.size());
380 for (size_t i = 0; i < d.size(); ++i)
381 {
382 dCasted[i] = static_cast<T>(d[i]);
383 }
384 for (size_t i = 0; i < e.size(); ++i)
385 {
386 eCasted[i] = static_cast<T>(e[i]);
387 }
388 for (size_t i = 0; i < f.size(); ++i)
389 {
390 fCasted[i] = static_cast<T>(f[i]);
391 }
392 for (size_t i = 0; i < g.size(); ++i)
393 {
394 gCasted[i] = static_cast<T>(g[i]);
395 }
396 MatrixArray<T> m15 = MatrixArray<T>(1, 3, dCasted);
397 MatrixArray<T> m16 = MatrixArray<T>(2, 1, eCasted);
398 MatrixArray<T> m17 = MatrixArray<T>(3, 2, 2, fCasted);
399 MatrixArray<T> m18 = MatrixArray<T>(1, 1, 2, gCasted);
401 NS_TEST_ASSERT_MSG_EQ(m19, m18, "The matrices should be equal.");
402
403 // test MultiplyByLeftAndRightMatrix
404 std::valarray<int> h{1, 3, 2, 2, 4, 0};
405 std::valarray<int> j{2, 2, 3, 4, 1, 3, 0, 5};
406 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};
407 std::valarray<int> l{144, 132, 128, 104, 144, 132, 128, 104};
408 std::valarray<T> hCasted(h.size());
409 std::valarray<T> jCasted(j.size());
410 std::valarray<T> kCasted(k.size());
411 std::valarray<T> lCasted(l.size());
412 for (size_t i = 0; i < h.size(); ++i)
413 {
414 hCasted[i] = static_cast<T>(h[i]);
415 }
416 for (size_t i = 0; i < j.size(); ++i)
417 {
418 jCasted[i] = static_cast<T>(j[i]);
419 }
420 for (size_t i = 0; i < k.size(); ++i)
421 {
422 kCasted[i] = static_cast<T>(k[i]);
423 }
424 for (size_t i = 0; i < l.size(); ++i)
425 {
426 lCasted[i] = static_cast<T>(l[i]);
427 }
428 MatrixArray<T> m20 = MatrixArray<T>(2, 3, hCasted);
429 MatrixArray<T> m21 = MatrixArray<T>(4, 2, jCasted);
430 MatrixArray<T> m22 = MatrixArray<T>(3, 4, 2, kCasted);
431 MatrixArray<T> m23 = MatrixArray<T>(2, 2, 2, lCasted);
433 NS_TEST_ASSERT_MSG_EQ(m24, m23, "The matrices should be equal.");
434 NS_LOG_INFO("m20:" << m20);
435 NS_LOG_INFO("m21:" << m21);
436 NS_LOG_INFO("m22:" << m22);
437 NS_LOG_INFO("m24 = m20 * m22 * m21" << m24);
438
439 // test initialization with moving
440 size_t lCastedSize = lCasted.size();
441 NS_LOG_INFO("size() of lCasted before move: " << lCasted.size());
442 MatrixArray<T> m25 = MatrixArray<T>(2, 2, 2, std::move(lCasted));
443 NS_LOG_INFO("m25.GetSize ()" << m25.GetSize());
444 NS_TEST_ASSERT_MSG_EQ(lCastedSize, m25.GetSize(), "The number of elements are not equal.");
445
446 size_t hCastedSize = hCasted.size();
447 NS_LOG_INFO("size() of hCasted before move: " << hCasted.size());
448 MatrixArray<T> m26 = MatrixArray<T>(2, 3, std::move(hCasted));
449 NS_LOG_INFO("m26.GetSize ()" << m26.GetSize());
450 NS_TEST_ASSERT_MSG_EQ(hCastedSize, m26.GetSize(), "The number of elements are not equal.");
451
452 size_t jCastedSize = jCasted.size();
453 NS_LOG_INFO("size() of jCasted before move: " << jCasted.size());
454 MatrixArray<T> m27 = MatrixArray<T>(std::move(jCasted));
455 NS_LOG_INFO("m27.GetSize ()" << m27.GetSize());
456 NS_TEST_ASSERT_MSG_EQ(jCastedSize, m27.GetSize(), "The number of elements are not equal.");
457
458 // test determinant
459 {
460 std::vector<std::pair<std::valarray<int>, T>> detTestCases{
461 // right-wraparound
462 {{1, 0, 7, 4, 2, 0, 6, 5, 3}, 62},
463 // left-wraparound
464 {{1, 4, 6, 0, 2, 5, 7, 0, 3}, 62},
465 // identity rank 3
466 {{1, 0, 0, 0, 1, 0, 0, 0, 1}, 1},
467 // identity rank 4
468 {{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, 1},
469 // permutation matrix rank 4
470 {{0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0}, -1},
471 // positive det matrix rank 2
472 {{36, -5, -5, 43}, 1523},
473 // single value matrix rank 1
474 {{1}, 1},
475 };
476 for (const auto& [detVal, detRef] : detTestCases)
477 {
478 std::valarray<T> detCast(detVal.size());
479 CastStdValarray(detVal, detCast);
480 auto side = sqrt(detVal.size());
481 MatrixArray<T> detMat = MatrixArray<T>(side, side, std::move(detCast));
483 static_cast<T>(detRef),
484 "The determinants are not equal.");
485 }
486 }
487 // clang-format off
488 std::valarray<int> multiPageMatrixValues{
489 // page 0: identity matrix
490 1, 0, 0,
491 0, 1, 0,
492 0, 0, 1,
493 // page 1: permutation matrix
494 0, 0, 1,
495 0, 1, 0,
496 1, 0, 0,
497 // page 2: random matrix
498 1, 4, 6,
499 0, 2, 5,
500 7, 0, 3,
501 // page 3: upper triangular
502 5, -9, 2,
503 0, -4, -10,
504 0, 0, -3,
505 // page 4: lower triangular
506 -7, 0, 0,
507 -1, -9, 0,
508 -5, 6, -5,
509 // page 5: zero diagonal
510 0, 1, 2,
511 1, 0, 1,
512 2, 1, 0,
513 // page 6: zero bidiagonal
514 0, 1, 0,
515 1, 0, 1,
516 0, 1, 0
517 };
518 // clang-format on
519 std::valarray<T> castMultiPageMatrixValues(multiPageMatrixValues.size());
520 CastStdValarray(multiPageMatrixValues, castMultiPageMatrixValues);
521 MatrixArray<T> multiPageMatrix = MatrixArray<T>(3,
522 3,
523 multiPageMatrixValues.size() / 9,
524 std::move(castMultiPageMatrixValues));
525 // test the determinant in a multi-page MatrixArray
526 std::vector<int> determinants = {1, -1, 62, 60, -315, 4, 0};
527 auto det = multiPageMatrix.Determinant();
528 for (size_t page = 0; page < multiPageMatrix.GetNumPages(); page++)
529 {
530 NS_TEST_ASSERT_MSG_EQ(det(page),
531 static_cast<T>(determinants[page]),
532 "The determinants from the page " << std::to_string(page)
533 << " are not equal.");
534 }
535
536 // test Frobenius norm in a multi-page MatrixArray
537 std::vector<double> fnorms = {sqrt(3), sqrt(3), 11.8322, 15.3297, 14.7309, 3.4641, 2};
538 auto frob = multiPageMatrix.FrobeniusNorm();
539 for (size_t page = 0; page < multiPageMatrix.GetNumPages(); page++)
540 {
541 NS_TEST_ASSERT_MSG_EQ_TOL(std::abs(frob(page)),
542 std::abs(static_cast<T>(fnorms[page])),
543 0.0001,
544 "The Frobenius norm from the page " << std::to_string(page)
545 << " are not equal.");
546 }
547
548 // test page copying
549 for (size_t noOfCopies = 1; noOfCopies < 4; noOfCopies++)
550 {
551 auto copies = m27.MakeNCopies(noOfCopies);
552 NS_TEST_ASSERT_MSG_EQ(copies.GetNumPages(),
553 noOfCopies,
554 "Creating " << std::to_string(noOfCopies) << " copies failed.");
555 NS_TEST_ASSERT_MSG_EQ(copies.GetNumRows(),
556 m27.GetNumRows(),
557 "The copy doesn't have the same number of rows as the original.");
558 NS_TEST_ASSERT_MSG_EQ(copies.GetNumCols(),
559 m27.GetNumCols(),
560 "The copy doesn't have the same number of columns as the original.");
561 for (size_t page = 0; page < copies.GetNumPages(); page++)
562 {
563 T diff{};
564 for (size_t row = 0; row < copies.GetNumRows(); row++)
565 {
566 for (size_t col = 0; col < copies.GetNumCols(); col++)
567 {
568 diff += m27(row, col, 0) - copies(row, col, page);
569 }
570 }
571 NS_TEST_ASSERT_MSG_EQ(diff, T{}, "Mismatch in copied values.");
572 }
573 }
574
575 // test page 1 and 0 extraction
576 std::vector<MatrixArray<T>> pages{multiPageMatrix.ExtractPage(1),
577 multiPageMatrix.ExtractPage(0)};
578
579 // test page 1 and 0 joining
580 auto jointPagesMatrix = MatrixArray<T>::JoinPages(pages);
581 NS_TEST_ASSERT_MSG_EQ(jointPagesMatrix.GetNumPages(), 2, "Mismatch in number of join pages.");
582 for (size_t page = 0; page < jointPagesMatrix.GetNumPages(); page++)
583 {
584 T diff{};
585 for (size_t row = 0; row < jointPagesMatrix.GetNumRows(); row++)
586 {
587 for (size_t col = 0; col < jointPagesMatrix.GetNumCols(); col++)
588 {
589 diff += multiPageMatrix(row, col, 1 - page) - jointPagesMatrix(row, col, page);
590 }
591 }
592 NS_TEST_ASSERT_MSG_EQ(diff, T{}, "Mismatching pages.");
593 }
594
595 // test identity matrix
596 auto identityRank3Reference = multiPageMatrix.ExtractPage(0);
597 auto identityRank3 = MatrixArray<T>::IdentityMatrix(3);
598 NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
599
600 identityRank3 = MatrixArray<T>::IdentityMatrix(3, 10).ExtractPage(9);
601 NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
602
603 identityRank3 = MatrixArray<T>::IdentityMatrix(identityRank3Reference);
604 NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
605}
606
607/**
608 * @ingroup matrixArray-tests
609 * Test for testing functions that apply to MatrixArrays that use complex numbers,
610 * such as HermitianTranspose that is only defined for complex type
611 */
613{
614 public:
615 /** Constructor*/
617 /**
618 * Constructor
619 *
620 * @param [in] name reference name
621 */
622 ComplexMatrixArrayTestCase(const std::string& name);
623 /** Destructor*/
625
626 private:
627 void DoRun() override;
628};
629
631 : TestCase("ComplexMatrixArrayTestCase")
632{
633}
634
636 : TestCase(name)
637{
638}
639
643
644void
646{
647 std::valarray<std::complex<double>> complexValarray1 = {
648 {1, 1},
649 {2, 2},
650 {3, 3},
651 {4, 4},
652 {5, 5},
653 {6, 6},
654 {-1, 1},
655 {-2, 2},
656 {-3, 3},
657 {-4, 4},
658 {-5, 5},
659 {-6, 6},
660 };
661 std::valarray<std::complex<double>> complexValarray2 = {
662 {1, -1},
663 {4, -4},
664 {2, -2},
665 {5, -5},
666 {3, -3},
667 {6, -6},
668 {-1, -1},
669 {-4, -4},
670 {-2, -2},
671 {-5, -5},
672 {-3, -3},
673 {-6, -6},
674 };
675 ComplexMatrixArray m1 = ComplexMatrixArray(3, 2, 2, complexValarray1);
676 ComplexMatrixArray m2 = ComplexMatrixArray(2, 3, 2, complexValarray2);
677 ComplexMatrixArray m3 = m1.HermitianTranspose();
678 NS_LOG_INFO("m1 (3, 2, 2):" << m1);
679 NS_LOG_INFO("m2 (2, 3, 2):" << m2);
680 NS_LOG_INFO("m3 (2, 3, 2):" << m3);
681 NS_TEST_ASSERT_MSG_EQ(m2, m3, "m2 and m3 matrices should be equal");
682}
683
684/**
685 * @ingroup matrixArray-tests
686 * MatrixArray test suite
687 */
689{
690 public:
691 /** Constructor. */
693};
694
696 : TestSuite("matrix-array-test")
697{
698 AddTestCase(new MatrixArrayTestCase<double>("Test MatrixArray<double>"));
700 new MatrixArrayTestCase<std::complex<double>>("Test MatrixArray<std::complex<double>>"));
701 AddTestCase(new MatrixArrayTestCase<int>("Test MatrixArray<int>"));
702 AddTestCase(new ComplexMatrixArrayTestCase("Test ComplexMatrixArray"));
703}
704
705/**
706 * @ingroup matrixArray-tests
707 * MatrixArrayTestSuite instance variable.
708 */
710
711} // namespace tests
712} // 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.
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
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:194
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
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:133
#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:553
#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:326
const double m1
First component modulus, 232 - 209.
Definition rng-stream.cc:48
const double m2
Second component modulus, 232 - 22853.
Definition rng-stream.cc:51
Namespace for test files, TestCases and TestSuites.
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.