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