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
31namespace ns3
32{
33
34namespace tests
35{
36
37NS_LOG_COMPONENT_DEFINE("MatrixArrayTest");
38
43template <class T>
45{
46 public:
47 MatrixArrayTestCase<T>() = default;
53 MatrixArrayTestCase<T>(const std::string& name);
54
56 ~MatrixArrayTestCase<T>() override;
79
80 protected:
81 private:
82 void DoRun() override;
83};
84
85template <class T>
87 : TestCase(name)
88{
89}
90
91template <class T>
93{
94}
95
96template <class T>
97void
99{
100 // test multiplication of matrices (MatrixArray containing only 1 matrix)
102 MatrixArray<T> m2 = MatrixArray<T>(m1.GetNumCols(), m1.GetNumRows());
103 for (size_t i = 0; i < m1.GetNumRows(); ++i)
104 {
105 for (size_t j = 0; j < m1.GetNumCols(); ++j)
106 {
107 m1(i, j) = 1;
108 m2(j, i) = 1;
109 }
110 }
111 MatrixArray<T> m3 = m1 * m2;
112 NS_LOG_INFO("m1:" << m1);
113 NS_LOG_INFO("m2:" << m2);
114 NS_LOG_INFO("m3 = m1 * m2:" << m3);
116 m1.GetNumRows(),
117 "The number of rows in resulting matrix is not correct");
119 m2.GetNumCols(),
120 "The number of cols in resulting matrix is not correct");
122 m3.GetNumCols(),
123 "The number of rows and cols should be equal");
124 for (size_t i = 0; i < m3.GetNumCols(); ++i)
125 {
126 for (size_t j = 0; j < m3.GetNumRows(); ++j)
127 {
128 NS_TEST_ASSERT_MSG_EQ(std::real(m3(i, j)),
129 m1.GetNumCols(),
130 "The element value should be " << m1.GetNumCols());
131 }
132 }
133
134 // multiplication with a scalar value
135 MatrixArray<T> m4 = m3 * (static_cast<T>(5.0));
136 for (size_t i = 0; i < m4.GetNumCols(); ++i)
137 {
138 for (size_t j = 0; j < m4.GetNumRows(); ++j)
139 {
140 NS_TEST_ASSERT_MSG_EQ(m3(i, j) * (static_cast<T>(5.0)),
141 m4(i, j),
142 "The values are not equal");
143 }
144 }
145 NS_LOG_INFO("m4 = m3 * 5:" << m4);
146
147 // test multiplication of arrays of matrices
148 MatrixArray<T> m5 = MatrixArray<T>(2, 3, 2);
150 for (size_t p = 0; p < m5.GetNumPages(); ++p)
151 {
152 for (size_t i = 0; i < m5.GetNumRows(); ++i)
153 {
154 for (size_t j = 0; j < m5.GetNumCols(); ++j)
155 {
156 m5(i, j, p) = 1;
157 m6(j, i, p) = 1;
158 }
159 }
160 }
161 MatrixArray<T> m7 = m5 * m6;
163 m5.GetNumRows(),
164 "The number of rows in resulting matrix is not correct");
166 m6.GetNumCols(),
167 "The number of cols in resulting matrix is not correct");
169 m7.GetNumCols(),
170 "The number of rows and cols should be equal");
171
172 for (size_t p = 0; p < m7.GetNumPages(); ++p)
173 {
174 for (size_t i = 0; i < m7.GetNumCols(); ++i)
175 {
176 for (size_t j = 0; j < m7.GetNumRows(); ++j)
177 {
178 NS_TEST_ASSERT_MSG_EQ(std::real(m7(i, j, p)),
179 m5.GetNumCols(),
180 "The element value should be " << m5.GetNumCols());
181 }
182 }
183 }
184 // test ostream operator
185 NS_LOG_INFO("m5:" << m5);
186 NS_LOG_INFO("m6:" << m6);
187 NS_LOG_INFO("m7 = m5 * m6:" << m7);
188
189 // test transpose function
190 MatrixArray<T> m8 = m5.Transpose();
191 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
192 NS_LOG_INFO("m8 = m5.Transpose ()" << m8);
193
194 // test transpose using initialization arrays
195 std::valarray<int> a{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};
196 std::valarray<int> b{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4};
197 std::valarray<T> aCasted(a.size());
198 std::valarray<T> bCasted(b.size());
199 for (size_t i = 0; i < a.size(); ++i)
200 {
201 aCasted[i] = static_cast<T>(a[i]);
202 }
203 for (size_t i = 0; i < b.size(); ++i)
204 {
205 bCasted[i] = static_cast<T>(b[i]);
206 }
207 m5 = MatrixArray<T>(3, 5, 1, aCasted);
208 m6 = MatrixArray<T>(5, 3, 1, bCasted);
209 m8 = m5.Transpose();
210 NS_TEST_ASSERT_MSG_EQ(m6, m8, "These two matrices should be equal");
211 NS_LOG_INFO("m5 (3, 5, 1):" << m5);
212 NS_LOG_INFO("m6 (5, 3, 1):" << m6);
213 NS_LOG_INFO("m8 (5, 3, 1) = m5.Transpose ()" << m8);
214
215 // test 1D array creation, i.e. vector and transposing it
216 MatrixArray<T> m9 = MatrixArray<T>(std::vector<T>({0, 1, 2, 3, 4, 5, 6, 7}));
217 NS_TEST_ASSERT_MSG_EQ((m9.GetNumRows() == 8) && (m9.GetNumCols() == 1) &&
218 (m9.GetNumPages() == 1),
219 true,
220 "Creation of vector is not correct.");
221
222 NS_LOG_INFO("Vector:" << m9);
223 NS_LOG_INFO("Vector after transposing:" << m9.Transpose());
224
225 // Test basic operators
226 MatrixArray<T> m10 =
228 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
229 m10 -= m9;
230 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
231 m10 += m9;
232 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
233 m10 = m9;
234 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
235 m10 = m9 + m9;
236 NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
237 m10 = m10 - m9;
238 NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
239
240 // test multiplication by using an initialization matrixArray
241 // matrix dimensions in each page are 2x3, 3x2, and the resulting matrix per page is a square
242 // matrix 2x2
243 a = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5};
244 b = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
245 std::valarray<int> c{2, 3, 4, 6, 2, 3, 4, 6};
246 aCasted = std::valarray<T>(a.size());
247 bCasted = std::valarray<T>(b.size());
248 std::valarray<T> cCasted = std::valarray<T>(c.size());
249
250 for (size_t i = 0; i < a.size(); ++i)
251 {
252 aCasted[i] = static_cast<T>(a[i]);
253 }
254 for (size_t i = 0; i < b.size(); ++i)
255 {
256 bCasted[i] = static_cast<T>(b[i]);
257 }
258 for (size_t i = 0; i < c.size(); ++i)
259 {
260 cCasted[i] = static_cast<T>(c[i]);
261 }
262 MatrixArray<T> m11 = MatrixArray<T>(2, 3, 2, aCasted);
263 MatrixArray<T> m12 = MatrixArray<T>(3, 2, 2, bCasted);
264 MatrixArray<T> m13 = m11 * m12;
265 MatrixArray<T> m14 = MatrixArray<T>(2, 2, 2, cCasted);
267 m14.GetNumCols(),
268 "The number of columns is not as expected.");
270 m14.GetNumRows(),
271 "The number of rows is not as expected.");
272 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
273 NS_LOG_INFO("m11 (2,3,2):" << m11);
274 NS_LOG_INFO("m12 (3,2,2):" << m12);
275 NS_LOG_INFO("m13 = m11 * m12:" << m13);
276
277 // test multiplication by using an initialization matrixArray
278 // matrices have different number of elements per page
279 // matrix dimensions in each page are 4x3, 3x2, and the resulting matrix
280 // dimensions are 4x2
281 a = std::valarray<int>(
282 {0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5});
283 b = std::valarray<int>({0, 1, 0, 1, 0, 1, 0, 10, 0, 10, 0, 10});
284 c = std::valarray<int>({2, 3, 2, 3, 4, 6, 4, 6, 20, 30, 20, 30, 40, 60, 40, 60});
285 aCasted = std::valarray<T>(a.size());
286 bCasted = std::valarray<T>(b.size());
287 cCasted = std::valarray<T>(c.size());
288
289 for (size_t i = 0; i < a.size(); ++i)
290 {
291 aCasted[i] = static_cast<T>(a[i]);
292 }
293 for (size_t i = 0; i < b.size(); ++i)
294 {
295 bCasted[i] = static_cast<T>(b[i]);
296 }
297 for (size_t i = 0; i < c.size(); ++i)
298 {
299 cCasted[i] = static_cast<T>(c[i]);
300 }
301
302 m11 = MatrixArray<T>(4, 3, 2, aCasted);
303 m12 = MatrixArray<T>(3, 2, 2, bCasted);
304 m13 = m11 * m12;
305 m14 = MatrixArray<T>(4, 2, 2, cCasted);
307 m14.GetNumCols(),
308 "The number of columns is not as expected.");
310 m14.GetNumRows(),
311 "The number of rows is not as expected.");
312 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
313 NS_LOG_INFO("m11 (4,3,2):" << m11);
314 NS_LOG_INFO("m12 (3,2,2):" << m12);
315 NS_LOG_INFO("m13 = m11 * m12:" << m13);
316
317 // test multiplication by using an initialization matrixArray
318 // matrices have different number of elements per page
319 // matrix dimensions in each page are 1x3, 3x2, and the resulting matrix has
320 // dimensions 1x2
321 a = std::valarray<int>({5, 4, 5, 5, 4, 5});
322 b = std::valarray<int>({0, 1, 0, 1, 0, 1, 1, 2, 3, 10, 100, 1000});
323 c = std::valarray<int>({4, 10, 28, 5450});
324 aCasted = std::valarray<T>(a.size());
325 bCasted = std::valarray<T>(b.size());
326 cCasted = std::valarray<T>(c.size());
327
328 for (size_t i = 0; i < a.size(); ++i)
329 {
330 aCasted[i] = static_cast<T>(a[i]);
331 }
332 for (size_t i = 0; i < b.size(); ++i)
333 {
334 bCasted[i] = static_cast<T>(b[i]);
335 }
336 for (size_t i = 0; i < c.size(); ++i)
337 {
338 cCasted[i] = static_cast<T>(c[i]);
339 }
340
341 m11 = MatrixArray<T>(1, 3, 2, aCasted);
342 m12 = MatrixArray<T>(3, 2, 2, bCasted);
343 m13 = m11 * m12;
344 m14 = MatrixArray<T>(1, 2, 2, cCasted);
346 m14.GetNumCols(),
347 "The number of columns is not as expected.");
349 m14.GetNumRows(),
350 "The number of rows is not as expected.");
351 NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
352 NS_LOG_INFO("m11 (1,3,2):" << m11);
353 NS_LOG_INFO("m12 (3,2,2):" << m12);
354 NS_LOG_INFO("m13 = m11 * m12:" << m13);
355
356 // test MultiplyByLeftAndRightMatrix
357 std::valarray<int> d{1, 1, 1};
358 std::valarray<int> e{1, 1};
359 std::valarray<int> f{1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3};
360 std::valarray<int> g{12, 12};
361 std::valarray<T> dCasted(d.size());
362 std::valarray<T> eCasted(e.size());
363 std::valarray<T> fCasted(f.size());
364 std::valarray<T> gCasted(g.size());
365 for (size_t i = 0; i < d.size(); ++i)
366 {
367 dCasted[i] = static_cast<T>(d[i]);
368 }
369 for (size_t i = 0; i < e.size(); ++i)
370 {
371 eCasted[i] = static_cast<T>(e[i]);
372 }
373 for (size_t i = 0; i < f.size(); ++i)
374 {
375 fCasted[i] = static_cast<T>(f[i]);
376 }
377 for (size_t i = 0; i < g.size(); ++i)
378 {
379 gCasted[i] = static_cast<T>(g[i]);
380 }
381 MatrixArray<T> m15 = MatrixArray<T>(1, 3, dCasted);
382 MatrixArray<T> m16 = MatrixArray<T>(2, 1, eCasted);
383 MatrixArray<T> m17 = MatrixArray<T>(3, 2, 2, fCasted);
384 MatrixArray<T> m18 = MatrixArray<T>(1, 1, 2, gCasted);
386 NS_TEST_ASSERT_MSG_EQ(m19, m18, "The matrices should be equal.");
387
388 // test MultiplyByLeftAndRightMatrix
389 std::valarray<int> h{1, 3, 2, 2, 4, 0};
390 std::valarray<int> j{2, 2, 3, 4, 1, 3, 0, 5};
391 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};
392 std::valarray<int> l{144, 132, 128, 104, 144, 132, 128, 104};
393 std::valarray<T> hCasted(h.size());
394 std::valarray<T> jCasted(j.size());
395 std::valarray<T> kCasted(k.size());
396 std::valarray<T> lCasted(l.size());
397 for (size_t i = 0; i < h.size(); ++i)
398 {
399 hCasted[i] = static_cast<T>(h[i]);
400 }
401 for (size_t i = 0; i < j.size(); ++i)
402 {
403 jCasted[i] = static_cast<T>(j[i]);
404 }
405 for (size_t i = 0; i < k.size(); ++i)
406 {
407 kCasted[i] = static_cast<T>(k[i]);
408 }
409 for (size_t i = 0; i < l.size(); ++i)
410 {
411 lCasted[i] = static_cast<T>(l[i]);
412 }
413 MatrixArray<T> m20 = MatrixArray<T>(2, 3, hCasted);
414 MatrixArray<T> m21 = MatrixArray<T>(4, 2, jCasted);
415 MatrixArray<T> m22 = MatrixArray<T>(3, 4, 2, kCasted);
416 MatrixArray<T> m23 = MatrixArray<T>(2, 2, 2, lCasted);
418 NS_TEST_ASSERT_MSG_EQ(m24, m23, "The matrices should be equal.");
419 NS_LOG_INFO("m20:" << m20);
420 NS_LOG_INFO("m21:" << m21);
421 NS_LOG_INFO("m22:" << m22);
422 NS_LOG_INFO("m24 = m20 * m22 * m21" << m24);
423
424 // test initialization with moving
425 size_t lCastedSize = lCasted.size();
426 NS_LOG_INFO("size() of lCasted before move: " << lCasted.size());
427 MatrixArray<T> m25 = MatrixArray<T>(2, 2, 2, std::move(lCasted));
428 NS_LOG_INFO("m25.GetSize ()" << m25.GetSize());
429 NS_TEST_ASSERT_MSG_EQ(lCastedSize, m25.GetSize(), "The number of elements are not equal.");
430
431 size_t hCastedSize = hCasted.size();
432 NS_LOG_INFO("size() of hCasted before move: " << hCasted.size());
433 MatrixArray<T> m26 = MatrixArray<T>(2, 3, std::move(hCasted));
434 NS_LOG_INFO("m26.GetSize ()" << m26.GetSize());
435 NS_TEST_ASSERT_MSG_EQ(hCastedSize, m26.GetSize(), "The number of elements are not equal.");
436
437 size_t jCastedSize = jCasted.size();
438 NS_LOG_INFO("size() of jCasted before move: " << jCasted.size());
439 MatrixArray<T> m27 = MatrixArray<T>(std::move(jCasted));
440 NS_LOG_INFO("m27.GetSize ()" << m27.GetSize());
441 NS_TEST_ASSERT_MSG_EQ(jCastedSize, m27.GetSize(), "The number of elements are not equal.");
442}
443
450{
451 public:
459 ComplexMatrixArrayTestCase(const std::string& name);
462
463 private:
464 void DoRun() override;
465};
466
468 : TestCase("ComplexMatrixArrayTestCase")
469{
470}
471
473 : TestCase(name)
474{
475}
476
478{
479}
480
481void
483{
484 std::valarray<std::complex<double>> complexValarray1 = {
485 {1, 1},
486 {2, 2},
487 {3, 3},
488 {4, 4},
489 {5, 5},
490 {6, 6},
491 {-1, 1},
492 {-2, 2},
493 {-3, 3},
494 {-4, 4},
495 {-5, 5},
496 {-6, 6},
497 };
498 std::valarray<std::complex<double>> complexValarray2 = {
499 {1, -1},
500 {4, -4},
501 {2, -2},
502 {5, -5},
503 {3, -3},
504 {6, -6},
505 {-1, -1},
506 {-4, -4},
507 {-2, -2},
508 {-5, -5},
509 {-3, -3},
510 {-6, -6},
511 };
512 ComplexMatrixArray m1 = ComplexMatrixArray(3, 2, 2, complexValarray1);
513 ComplexMatrixArray m2 = ComplexMatrixArray(2, 3, 2, complexValarray2);
514 ComplexMatrixArray m3 = m1.HermitianTranspose();
515 NS_LOG_INFO("m1 (3, 2, 2):" << m1);
516 NS_LOG_INFO("m2 (2, 3, 2):" << m2);
517 NS_LOG_INFO("m3 (2, 3, 2):" << m3);
518 NS_TEST_ASSERT_MSG_EQ(m2, m3, "m2 and m3 matrices should be equal");
519}
520
526{
527 public:
530};
531
533 : TestSuite("matrix-array-test")
534{
535 AddTestCase(new MatrixArrayTestCase<double>("Test MatrixArray<double>"));
537 new MatrixArrayTestCase<std::complex<double>>("Test MatrixArray<std::complex<double>>"));
538 AddTestCase(new MatrixArrayTestCase<int>("Test MatrixArray<int>"));
539 AddTestCase(new ComplexMatrixArrayTestCase("Test ComplexMatrixArray"));
540}
541
547
548} // namespace tests
549} // namespace ns3
double f(double x, void *params)
Definition: 80211b.c:70
MatrixArray class inherits ValArray class and provides additional interfaces to ValArray which enable...
Definition: matrix-array.h:83
MatrixArray< T > Transpose() const
This operator interprets the 3D array as an array of matrices, and performs a linear algebra operatio...
MatrixArray< T > MultiplyByLeftAndRightMatrix(const MatrixArray< T > &lMatrix, const MatrixArray< T > &rMatrix) const
Multiply each matrix in the array by the left and the right matrix.
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
const std::valarray< T > & GetValues() const
Returns underlying values.
Definition: val-array.h:560
size_t GetNumPages() const
Definition: val-array.h:393
size_t GetSize() const
Definition: val-array.h:400
size_t GetNumRows() const
Definition: val-array.h:379
size_t GetNumCols() const
Definition: val-array.h:386
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< T > & operator=(const MatrixArrayTestCase< T > &)=default
Copy assignment operator.
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
#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:144
#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:564
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
static MatrixArrayTestSuite g_matrixArrayTestSuite
MatrixArrayTestSuite instance variable.
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:265