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