A Discrete-Event Network Simulator
API
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 
31 namespace ns3
32 {
33 
34 namespace tests
35 {
36 
37 NS_LOG_COMPONENT_DEFINE("MatrixArrayTest");
38 
43 template <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 
85 template <class T>
87  : TestCase(name)
88 {
89 }
90 
91 template <class T>
93 {
94 }
95 
96 template <class T>
97 void
99 {
100  // test multiplication of matrices (MatrixArray containing only 1 matrix)
102  MatrixArray<T> m2 = MatrixArray<T>(m1.GetNumCols(), m1.GetNumRows());
103  for (auto i = 0; i < m1.GetNumRows(); ++i)
104  {
105  for (auto 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 (auto i = 0; i < m3.GetNumCols(); ++i)
125  {
126  for (auto 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 (auto i = 0; i < m4.GetNumCols(); ++i)
137  {
138  for (auto 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 (auto p = 0; p < m5.GetNumPages(); ++p)
151  {
152  for (auto i = 0; i < m5.GetNumRows(); ++i)
153  {
154  for (auto 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 (auto p = 0; p < m7.GetNumPages(); ++p)
173  {
174  for (auto i = 0; i < m7.GetNumCols(); ++i)
175  {
176  for (auto 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 1D array creation, i.e. vector and transposing it
195  MatrixArray<T> m9 = MatrixArray<T>(std::vector<T>({0, 1, 2, 3, 4, 5, 6, 7}));
196  NS_TEST_ASSERT_MSG_EQ((m9.GetNumRows() == 8) && (m9.GetNumCols() == 1) &&
197  (m9.GetNumPages() == 1),
198  true,
199  "Creation of vector is not correct.");
200 
201  NS_LOG_INFO("Vector:" << m9);
202  NS_LOG_INFO("Vector after transposing:" << m9.Transpose());
203 
204  // Test basic operators
205  MatrixArray<T> m10 =
206  MatrixArray<T>(m9.GetNumRows(), m9.GetNumCols(), m9.GetNumPages(), m9.GetValues());
207  NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
208  m10 -= m9;
209  NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
210  m10 += m9;
211  NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
212  m10 = m9;
213  NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
214  m10 = m9 + m9;
215  NS_TEST_ASSERT_MSG_NE(m10, m9, "m10 and m9 should not be equal");
216  m10 = m10 - m9;
217  NS_TEST_ASSERT_MSG_EQ(m10, m9, "m10 and m9 should be equal");
218 
219  // test multiplication by using an initialization matrixArray
220  std::valarray<int> a{0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5};
221  std::valarray<int> b{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
222  std::valarray<int> c{2, 3, 4, 6, 2, 3, 4, 6};
223  std::valarray<T> aCasted(a.size());
224  std::valarray<T> bCasted(b.size());
225  std::valarray<T> cCasted(c.size());
226 
227  for (size_t i = 0; i < a.size(); ++i)
228  {
229  aCasted[i] = static_cast<T>(a[i]);
230  }
231  for (size_t i = 0; i < b.size(); ++i)
232  {
233  bCasted[i] = static_cast<T>(b[i]);
234  }
235  for (size_t i = 0; i < c.size(); ++i)
236  {
237  cCasted[i] = static_cast<T>(c[i]);
238  }
239  MatrixArray<T> m11 = MatrixArray<T>(2, 3, 2, aCasted);
240  MatrixArray<T> m12 = MatrixArray<T>(3, 2, 2, bCasted);
241  MatrixArray<T> m13 = m11 * m12;
242  MatrixArray<T> m14 = MatrixArray<T>(2, 2, 2, cCasted);
244  m14.GetNumCols(),
245  "The number of columns is not as expected.");
247  m14.GetNumRows(),
248  "The number of rows is not as expected.");
249  NS_TEST_ASSERT_MSG_EQ(m13, m14, "The values are not equal.");
250  NS_LOG_INFO("m11:" << m11);
251  NS_LOG_INFO("m12:" << m12);
252  NS_LOG_INFO("m13 = matrixArrayA * matrixArrayB:" << m13);
253 
254  // test MultiplyByLeftAndRightMatrix
255  std::valarray<int> d{1, 1, 1};
256  std::valarray<int> e{1, 1};
257  std::valarray<int> f{1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3};
258  std::valarray<int> g{12, 12};
259  std::valarray<T> dCasted(d.size());
260  std::valarray<T> eCasted(e.size());
261  std::valarray<T> fCasted(f.size());
262  std::valarray<T> gCasted(g.size());
263  for (size_t i = 0; i < d.size(); ++i)
264  {
265  dCasted[i] = static_cast<T>(d[i]);
266  }
267  for (size_t i = 0; i < e.size(); ++i)
268  {
269  eCasted[i] = static_cast<T>(e[i]);
270  }
271  for (size_t i = 0; i < f.size(); ++i)
272  {
273  fCasted[i] = static_cast<T>(f[i]);
274  }
275  for (size_t i = 0; i < g.size(); ++i)
276  {
277  gCasted[i] = static_cast<T>(g[i]);
278  }
279  MatrixArray<T> m15 = MatrixArray<T>(1, 3, dCasted);
280  MatrixArray<T> m16 = MatrixArray<T>(2, 1, eCasted);
281  MatrixArray<T> m17 = MatrixArray<T>(3, 2, 2, fCasted);
282  MatrixArray<T> m18 = MatrixArray<T>(1, 1, 2, gCasted);
283  MatrixArray<T> m19 = m17.MultiplyByLeftAndRightMatrix(m15, m16);
284  NS_TEST_ASSERT_MSG_EQ(m19, m18, "The matrices should be equal.");
285 
286  // test MultiplyByLeftAndRightMatrix
287  std::valarray<int> h{1, 3, 2, 2, 4, 0};
288  std::valarray<int> j{2, 2, 3, 4, 1, 3, 0, 5};
289  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};
290  std::valarray<int> l{144, 132, 128, 104, 144, 132, 128, 104};
291  std::valarray<T> hCasted(h.size());
292  std::valarray<T> jCasted(j.size());
293  std::valarray<T> kCasted(k.size());
294  std::valarray<T> lCasted(l.size());
295  for (size_t i = 0; i < h.size(); ++i)
296  {
297  hCasted[i] = static_cast<T>(h[i]);
298  }
299  for (size_t i = 0; i < j.size(); ++i)
300  {
301  jCasted[i] = static_cast<T>(j[i]);
302  }
303  for (size_t i = 0; i < k.size(); ++i)
304  {
305  kCasted[i] = static_cast<T>(k[i]);
306  }
307  for (size_t i = 0; i < l.size(); ++i)
308  {
309  lCasted[i] = static_cast<T>(l[i]);
310  }
311  MatrixArray<T> m20 = MatrixArray<T>(2, 3, hCasted);
312  MatrixArray<T> m21 = MatrixArray<T>(4, 2, jCasted);
313  MatrixArray<T> m22 = MatrixArray<T>(3, 4, 2, kCasted);
314  MatrixArray<T> m23 = MatrixArray<T>(2, 2, 2, lCasted);
315  MatrixArray<T> m24 = m22.MultiplyByLeftAndRightMatrix(m20, m21);
316  NS_TEST_ASSERT_MSG_EQ(m24, m23, "The matrices should be equal.");
317  NS_LOG_INFO("m20:" << m20);
318  NS_LOG_INFO("m21:" << m21);
319  NS_LOG_INFO("m22:" << m22);
320  NS_LOG_INFO("m24 = m20 * m22 * m21" << m24);
321 
322  // test initialization with moving
323  NS_LOG_INFO("size() of lCasted before move: " << lCasted.size());
324  MatrixArray<T> m25 = MatrixArray<T>(2, 2, 2, std::move(lCasted));
325  NS_LOG_INFO("size() of lCasted after move: " << lCasted.size());
326  NS_LOG_INFO("m25.GetSize ()" << m25.GetSize());
327  NS_TEST_ASSERT_MSG_EQ(lCasted.size(), 0, "The size of lCasted should be 0.");
328 
329  NS_LOG_INFO("size() of hCasted before move: " << hCasted.size());
330  MatrixArray<T> m26 = MatrixArray<T>(2, 3, std::move(hCasted));
331  NS_LOG_INFO("size() of hCasted after move: " << hCasted.size());
332  NS_LOG_INFO("m26.GetSize ()" << m26.GetSize());
333  NS_TEST_ASSERT_MSG_EQ(hCasted.size(), 0, "The size of hCasted should be 0.");
334 
335  NS_LOG_INFO("size() of jCasted before move: " << jCasted.size());
336  MatrixArray<T> m27 = MatrixArray<T>(std::move(jCasted));
337  NS_LOG_INFO("size() of jCasted after move: " << jCasted.size());
338  NS_LOG_INFO("m27.GetSize ()" << m27.GetSize());
339  NS_TEST_ASSERT_MSG_EQ(hCasted.size(), 0, "The size of jCasted should be 0.");
340 }
341 
347 {
348  public:
351 };
352 
354  : TestSuite("matrix-array-test")
355 {
356  AddTestCase(new MatrixArrayTestCase<double>("Test MatrixArray<double>"));
357  AddTestCase(
358  new MatrixArrayTestCase<std::complex<double>>("Test MatrixArray<std::complex<double>>"));
359  AddTestCase(new MatrixArrayTestCase<int>("Test MatrixArray<int>"));
360 }
361 
367 
368 } // namespace tests
369 } // namespace ns3
double f(double x, void *params)
Definition: 80211b.c:71
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:305
A suite of tests to run.
Definition: test.h:1256
uint16_t GetNumRows() const
Definition: val-array.h:382
uint16_t GetNumCols() const
Definition: val-array.h:389
const std::valarray< T > & GetValues() const
Returns underlying values.
Definition: val-array.h:563
size_t GetSize() const
Definition: val-array.h:403
uint16_t GetNumPages() const
Definition: val-array.h:396
MatrixArray test for testing constructors.
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.