mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
psdFilter_test.cpp
Go to the documentation of this file.
1/** \file psdFilter_test.cpp
2 * \brief Tests PSD-filter construction and filtering.
3 */
4#include "../../catch2/catch.hpp"
5
6#include <vector>
7#include <Eigen/Dense>
8
9#define MX_NO_ERROR_REPORTS
10
16
17#ifdef MXLIB_BUILD_COVERAGE
18constexpr int psdFilterTrials = 100;
19constexpr double psdFilterTol = 0.09;
20#else
21constexpr int psdFilterTrials = 10000;
22constexpr double psdFilterTol = 0.02;
23#endif
24
25/** compiling psdFilter
26 *
27 * Verify compilation and initilization of the 3 ranks for psdFilter.
28 *
29 */
30/**
31 * \ingroup psdFilter_unit_tests
32 */
33TEST_CASE( "compiling psdFilter", "[sigproc::psdFilter]" )
34{
35 GIVEN( "a psdFilter, sqrt pointer" )
36 {
37 WHEN( "rank==1" )
38 {
39 mx::sigproc::psdFilter<double, 1> psdF;
40
41 std::vector<double> psdSqrt( 1024, 1 );
42
43 int rv = psdF.psdSqrt( &psdSqrt, 1 );
44
45 REQUIRE( rv == 0 );
46 REQUIRE( psdF.rows() == 1024 );
47 REQUIRE( psdF.cols() == 1 );
48 REQUIRE( psdF.planes() == 1 );
49
50 psdF.clear();
51 REQUIRE( psdF.rows() == 0 );
52 REQUIRE( psdF.cols() == 0 );
53 REQUIRE( psdF.planes() == 0 );
54 }
55 WHEN( "rank==2" )
56 {
57 mx::sigproc::psdFilter<double, 2> psdF;
58
59 Eigen::Array<double, -1, -1> psdSqrt;
60 psdSqrt.resize( 256, 256 );
61 psdSqrt.setConstant( 1 );
62
63 int rv = psdF.psdSqrt( &psdSqrt, 1, 1 );
64
65 REQUIRE( rv == 0 );
66 REQUIRE( psdF.rows() == 256 );
67 REQUIRE( psdF.cols() == 256 );
68 REQUIRE( psdF.planes() == 1 );
69
70 psdF.clear();
71 REQUIRE( psdF.rows() == 0 );
72 REQUIRE( psdF.cols() == 0 );
73 REQUIRE( psdF.planes() == 0 );
74 }
75 WHEN( "rank==3" )
76 {
77 mx::sigproc::psdFilter<double, 3> psdF;
78
80 psdSqrt.resize( 128, 128, 256 );
81 // psdSqrt.setConstant(1);
82
83 int rv = psdF.psdSqrt( &psdSqrt, 1, 1, 1 );
84
85 REQUIRE( rv == 0 );
86 REQUIRE( psdF.rows() == 128 );
87 REQUIRE( psdF.cols() == 128 );
88 REQUIRE( psdF.planes() == 256 );
89
90 psdF.clear();
91 REQUIRE( psdF.rows() == 0 );
92 REQUIRE( psdF.cols() == 0 );
93 REQUIRE( psdF.planes() == 0 );
94 }
95 }
96
97 GIVEN( "a psdFilter, sqrt reference" )
98 {
99 WHEN( "rank==1" )
100 {
101 mx::sigproc::psdFilter<double, 1> psdF;
102
103 std::vector<double> psdSqrt( 1024, 1 );
104
105 int rv = psdF.psdSqrt( psdSqrt, 1 );
106
107 REQUIRE( rv == 0 );
108 REQUIRE( psdF.rows() == 1024 );
109 REQUIRE( psdF.cols() == 1 );
110 REQUIRE( psdF.planes() == 1 );
111
112 psdF.clear();
113 REQUIRE( psdF.rows() == 0 );
114 REQUIRE( psdF.cols() == 0 );
115 REQUIRE( psdF.planes() == 0 );
116 }
117 WHEN( "rank==2" )
118 {
119 mx::sigproc::psdFilter<double, 2> psdF;
120
121 Eigen::Array<double, -1, -1> psdSqrt;
122 psdSqrt.resize( 256, 256 );
123 psdSqrt.setConstant( 1 );
124
125 int rv = psdF.psdSqrt( psdSqrt, 1, 1 );
126
127 REQUIRE( rv == 0 );
128 REQUIRE( psdF.rows() == 256 );
129 REQUIRE( psdF.cols() == 256 );
130 REQUIRE( psdF.planes() == 1 );
131
132 psdF.clear();
133 REQUIRE( psdF.rows() == 0 );
134 REQUIRE( psdF.cols() == 0 );
135 REQUIRE( psdF.planes() == 0 );
136 }
137 WHEN( "rank==3" )
138 {
139 mx::sigproc::psdFilter<double, 3> psdF;
140
142 psdSqrt.resize( 128, 128, 256 );
143 // psdSqrt.setConstant(1);
144
145 int rv = psdF.psdSqrt( psdSqrt, 1, 1, 1 );
146
147 REQUIRE( rv == 0 );
148 REQUIRE( psdF.rows() == 128 );
149 REQUIRE( psdF.cols() == 128 );
150 REQUIRE( psdF.planes() == 256 );
151
152 psdF.clear();
153 REQUIRE( psdF.rows() == 0 );
154 REQUIRE( psdF.cols() == 0 );
155 REQUIRE( psdF.planes() == 0 );
156 }
157 }
158
159 GIVEN( "a psdFilter, psd reference" )
160 {
161 WHEN( "rank==1" )
162 {
163 mx::sigproc::psdFilter<double, 1> psdF;
164
165 std::vector<double> psd( 1024, 1 );
166
167 int rv = psdF.psd( psd, 1.0 );
168
169 REQUIRE( rv == 0 );
170 REQUIRE( psdF.rows() == 1024 );
171 REQUIRE( psdF.cols() == 1 );
172 REQUIRE( psdF.planes() == 1 );
173
174 psdF.clear();
175 REQUIRE( psdF.rows() == 0 );
176 REQUIRE( psdF.cols() == 0 );
177 REQUIRE( psdF.planes() == 0 );
178 }
179 WHEN( "rank==2" )
180 {
181 mx::sigproc::psdFilter<double, 2> psdF;
182
183 Eigen::Array<double, -1, -1> psd;
184 psd.resize( 256, 256 );
185 psd.setConstant( 1 );
186
187 int rv = psdF.psd( psd, 1.0, 1.0 );
188
189 REQUIRE( rv == 0 );
190 REQUIRE( psdF.rows() == 256 );
191 REQUIRE( psdF.cols() == 256 );
192 REQUIRE( psdF.planes() == 1 );
193
194 psdF.clear();
195 REQUIRE( psdF.rows() == 0 );
196 REQUIRE( psdF.cols() == 0 );
197 REQUIRE( psdF.planes() == 0 );
198 }
199 WHEN( "rank==3" )
200 {
201 mx::sigproc::psdFilter<double, 3> psdF;
202
204 psd.resize( 128, 128, 256 );
205 // psdSqrt.setConstant(1);
206
207 int rv = psdF.psd( psd, 1, 1, 1 );
208
209 REQUIRE( rv == 0 );
210 REQUIRE( psdF.rows() == 128 );
211 REQUIRE( psdF.cols() == 128 );
212 REQUIRE( psdF.planes() == 256 );
213
214 psdF.clear();
215 REQUIRE( psdF.rows() == 0 );
216 REQUIRE( psdF.cols() == 0 );
217 REQUIRE( psdF.planes() == 0 );
218 }
219 }
220}
221
222/** Verify filtering and noise normalization
223 * Conducts random noise tests, verifying that the resultant rms is within 2% of expected value on average over many
224 * trials. Results are usually better than 1%, but 2% makes sure we don't get false failures.
225 *
226 */
227/**
228 * \ingroup psdFilter_unit_tests
229 */
230TEST_CASE( "filtering with psdFilter", "[sigproc::psdFilter]" )
231{
232 GIVEN( "a rank 1 psd" )
233 {
234 WHEN( "alpha=-2.5, df Nyquist matched to array size, var=1" )
235 {
236 mx::sigproc::psdFilter<double, 1> psdF;
237
238 std::vector<double> f( 2049 ), psd( 2049 );
239
240 for( size_t n = 0; n < psd.size(); ++n )
241 f[n] = n * 1.0 / 4096.;
242
243 for( size_t n = 1; n < psd.size(); ++n )
244 psd[n] = pow( f[n], -2.5 );
245 psd[0] = psd[1];
246
247 mx::sigproc::normPSD( psd, f, 1.0, -1e5, 1e5 );
248
249 std::vector<double> f2s, psd2s;
251 mx::sigproc::augment1SidedPSD( psd2s, psd );
252
253 double df = f2s[1] - f2s[0];
254 // mx::sigproc::normPSD(psd2s, f2s, 1.0, -1e5, 1e5);
255 int rv = psdF.psd( psd2s, df );
256
257 REQUIRE( rv == 0 );
258 REQUIRE( psdF.rows() == 2. * psd.size() - 2 );
259 REQUIRE( psdF.cols() == 1 );
260 REQUIRE( psdF.planes() == 1 );
261
262 std::vector<double> noise( psdF.rows() );
263
264 mx::math::normDistT<double> normVar( false );
265 normVar.seed( 0x50D00001 );
266
267 double avgRms = 0;
268
269 for( int k = 0; k < psdFilterTrials; ++k )
270 {
271 for( size_t n = 0; n < noise.size(); ++n )
272 noise[n] = normVar;
273 psdF( noise );
274 avgRms += ( mx::math::vectorVariance( noise, 0.0 ) );
275 }
276
277 avgRms = sqrt( avgRms / psdFilterTrials );
278
279 REQUIRE_THAT( avgRms, Catch::Matchers::WithinAbs( 1.0, psdFilterTol ) );
280 }
281 WHEN( "alpha=-1.5, df arbitrary, var = 2.2" )
282 {
283 mx::sigproc::psdFilter<double, 1> psdF;
284
285 std::vector<double> f( 1025 ), psd( 1025 );
286
287 for( size_t n = 0; n < psd.size(); ++n )
288 f[n] = n * 1.0 / 7000.;
289
290 for( size_t n = 1; n < psd.size(); ++n )
291 psd[n] = pow( f[n], -1.5 );
292 psd[0] = psd[1];
293
294 std::vector<double> f2s, psd2s;
296 mx::sigproc::augment1SidedPSD( psd2s, psd );
297
298 double df = f2s[1] - f2s[0];
299 mx::sigproc::normPSD( psd2s, f2s, 2.2, -1e5, 1e5 );
300
301 int rv = psdF.psd( psd2s, df );
302
303 REQUIRE( rv == 0 );
304 REQUIRE( psdF.rows() == 2. * psd.size() - 2 );
305 REQUIRE( psdF.cols() == 1 );
306 REQUIRE( psdF.planes() == 1 );
307
308 std::vector<double> noise( psdF.rows() );
309
310 mx::math::normDistT<double> normVar( false );
311 normVar.seed( 0x50D00002 );
312
313 double avgRms = 0;
314
315 for( int k = 0; k < psdFilterTrials; ++k )
316 {
317 for( size_t n = 0; n < noise.size(); ++n )
318 noise[n] = normVar;
319 psdF( noise );
320 avgRms += ( mx::math::vectorVariance( noise, 0.0 ) );
321 }
322
323 avgRms = sqrt( avgRms / psdFilterTrials );
324
325 REQUIRE_THAT( avgRms, Catch::Matchers::WithinAbs( sqrt( 2.2 ), psdFilterTol * sqrt( 2.2 ) ) );
326 }
327 }
328 GIVEN( "a rank 2 psd" )
329 {
330 WHEN( "alpha=-2.5, dk Nyquist matched to array size, var=1" )
331 {
332 mx::sigproc::psdFilter<double, 2> psdF;
333
334 Eigen::Array<double, -1, -1> k, psd;
335
336 k.resize( 64, 64 );
337 psd.resize( 64, 64 );
338
339 mx::sigproc::frequencyGrid( k, 1. / 128. );
340 for( int cc = 0; cc < psd.cols(); ++cc )
341 {
342 for( int rr = 0; rr < psd.rows(); ++rr )
343 {
344 if( k( rr, cc ) == 0 )
345 psd( rr, cc ) = 0;
346 else
347 psd( rr, cc ) = pow( k( rr, cc ), -2.5 );
348 }
349 }
350
351 double dk = k( 0, 1 ) - k( 0, 0 );
352
353 mx::sigproc::normPSD( psd, k, 1.0 );
354
355 int rv = psdF.psd( psd, dk, dk );
356
357 REQUIRE( rv == 0 );
358 REQUIRE( psdF.rows() == psd.rows() );
359 REQUIRE( psdF.cols() == psd.cols() );
360 REQUIRE( psdF.planes() == 1 );
361
362 Eigen::Array<double, -1, -1> noise( psdF.rows(), psdF.cols() );
363
364 mx::math::normDistT<double> normVar( false );
365 normVar.seed( 0x50D00003 );
366
367 double avgRms = 0;
368
369 for( int k = 0; k < psdFilterTrials; ++k )
370 {
371 for( int cc = 0; cc < psd.cols(); ++cc )
372 {
373 for( int rr = 0; rr < psd.rows(); ++rr )
374 {
375 noise( rr, cc ) = normVar;
376 }
377 }
378
379 psdF( noise );
380 avgRms += noise.square().sum(); //(mx::math::vectorVariance(noise,0.0));
381 }
382
383 avgRms = sqrt( avgRms / ( psd.rows() * psd.cols() ) / psdFilterTrials );
384
385 REQUIRE_THAT( avgRms, Catch::Matchers::WithinAbs( 1.0, psdFilterTol ) );
386 }
387 WHEN( "alpha=-1.5, dk arb, var=2.2" )
388 {
389 mx::sigproc::psdFilter<double, 2> psdF;
390
391 Eigen::Array<double, -1, -1> k, psd;
392
393 k.resize( 64, 64 );
394 psd.resize( 64, 64 );
395
396 mx::sigproc::frequencyGrid( k, 1. / 302. );
397 for( int cc = 0; cc < psd.cols(); ++cc )
398 {
399 for( int rr = 0; rr < psd.rows(); ++rr )
400 {
401 if( k( rr, cc ) == 0 )
402 psd( rr, cc ) = 0;
403 else
404 psd( rr, cc ) = pow( k( rr, cc ), -1.5 );
405 }
406 }
407
408 double dk = k( 0, 1 ) - k( 0, 0 );
409
410 mx::sigproc::normPSD( psd, k, 2.2 );
411
412 int rv = psdF.psd( psd, dk, dk );
413
414 REQUIRE( rv == 0 );
415 REQUIRE( psdF.rows() == psd.rows() );
416 REQUIRE( psdF.cols() == psd.cols() );
417 REQUIRE( psdF.planes() == 1 );
418
419 Eigen::Array<double, -1, -1> noise( psdF.rows(), psdF.cols() );
420
421 mx::math::normDistT<double> normVar( false );
422 normVar.seed( 0x50D00004 );
423
424 double avgRms = 0;
425
426 for( int k = 0; k < psdFilterTrials; ++k )
427 {
428 for( int cc = 0; cc < psd.cols(); ++cc )
429 {
430 for( int rr = 0; rr < psd.rows(); ++rr )
431 {
432 noise( rr, cc ) = normVar;
433 }
434 }
435
436 psdF( noise );
437 avgRms += noise.square().sum(); //(mx::math::vectorVariance(noise,0.0));
438 }
439
440 avgRms = sqrt( avgRms / ( psd.rows() * psd.cols() ) / psdFilterTrials );
441
442 REQUIRE_THAT( avgRms, Catch::Matchers::WithinAbs( sqrt( 2.2 ), psdFilterTol * sqrt( 2.2 ) ) );
443 }
444 }
445 GIVEN( "a rank 3 psd" )
446 {
447 WHEN( "k-alpha=-2.5, f-alph=-2.5, dk Nyquist matched to array size, df Nyquist matched to array size, var=1" )
448 {
449 mx::sigproc::psdFilter<double, 3> psdF;
450
451 Eigen::Array<double, -1, -1> k, psdk;
452 std::vector<double> f, f2s, psd2s;
453
455
456 k.resize( 32, 32 );
457 f.resize( 33 );
458
459 mx::sigproc::frequencyGrid( k, 1. / 64. );
460 psdk.resize( k.rows(), k.cols() );
461 for( int cc = 0; cc < psdk.cols(); ++cc )
462 {
463 for( int rr = 0; rr < psdk.rows(); ++rr )
464 {
465 if( k( rr, cc ) == 0 )
466 psdk( rr, cc ) = 0;
467 else
468 psdk( rr, cc ) = pow( k( rr, cc ), -2.5 );
469 }
470 }
471 mx::sigproc::normPSD( psdk, k, 1.0 );
472
473 for( size_t n = 0; n < f.size(); ++n )
474 f[n] = n * 1.0 / 64.;
476 psd2s.resize( f2s.size() );
477 for( size_t n = 0; n < psd2s.size(); ++n )
478 psd2s[n] = pow( fabs( f2s[n] ), -2.5 );
479 psd2s[0] = psd2s[1];
480
481 psd.resize( k.rows(), k.cols(), f2s.size() );
482
483 for( int cc = 0; cc < psd.cols(); ++cc )
484 {
485 for( int rr = 0; rr < psd.rows(); ++rr )
486 {
487 if( k( rr, cc ) == 0 )
488 psd.pixel( rr, cc ).setZero();
489 else
490 {
491 double p = psdk( rr, cc );
492 mx::sigproc::normPSD( psd2s, f2s, p, -1e5, 1e5 );
493
494 for( int pp = 0; pp < psd.planes(); ++pp )
495 psd.image( pp )( rr, cc ) = psd2s[pp];
496 }
497 }
498 }
499
500 double dk = k( 0, 1 ) - k( 0, 0 );
501 double df = f[1] - f[0];
502
503 int rv = psdF.psd( psd, dk, dk, df );
504
505 REQUIRE( rv == 0 );
506 REQUIRE( psdF.rows() == psd.rows() );
507 REQUIRE( psdF.cols() == psd.cols() );
508 REQUIRE( psdF.planes() == psd.planes() );
509
510 mx::improc::eigenCube<double> noise( psdF.rows(), psdF.cols(), psdF.planes() );
511
512 mx::math::normDistT<double> normVar( false );
513 normVar.seed( 0x50D00005 );
514
515 double avgRms = 0;
516
517 for( int k = 0; k < psdFilterTrials; ++k )
518 {
519 for( int pp = 0; pp < psd.planes(); ++pp )
520 {
521 for( int cc = 0; cc < psd.cols(); ++cc )
522 {
523 for( int rr = 0; rr < psd.rows(); ++rr )
524 {
525 noise.image( pp )( rr, cc ) = normVar;
526 }
527 }
528 }
529
530 psdF( noise );
531 for( int pp = 0; pp < noise.planes(); ++pp )
532 avgRms += noise.image( pp ).square().sum();
533 }
534
535 avgRms = sqrt( avgRms / ( psd.rows() * psd.cols() * psd.planes() ) / psdFilterTrials );
536
537 REQUIRE_THAT( avgRms, Catch::Matchers::WithinAbs( 1.0, psdFilterTol ) );
538 }
539 WHEN( "k-alpha=-3.5, f-alph=-1.5, dk arb, df arb, var=2" )
540 {
541 mx::sigproc::psdFilter<double, 3> psdF;
542
543 Eigen::Array<double, -1, -1> k, psdk;
544 std::vector<double> f, f2s, psd2s;
545
547
548 k.resize( 32, 32 );
549 f.resize( 33 );
550
551 mx::sigproc::frequencyGrid( k, 1. / 640. );
552 psdk.resize( k.rows(), k.cols() );
553 for( int cc = 0; cc < psdk.cols(); ++cc )
554 {
555 for( int rr = 0; rr < psdk.rows(); ++rr )
556 {
557 if( k( rr, cc ) == 0 )
558 psdk( rr, cc ) = 0;
559 else
560 psdk( rr, cc ) = pow( k( rr, cc ), -3.5 );
561 }
562 }
563 mx::sigproc::normPSD( psdk, k, 2.0 );
564
565 for( size_t n = 0; n < f.size(); ++n )
566 f[n] = n * 1.0 / 78.;
568 psd2s.resize( f2s.size() );
569 for( size_t n = 0; n < psd2s.size(); ++n )
570 psd2s[n] = pow( fabs( f2s[n] ), -1.5 );
571 psd2s[0] = psd2s[1];
572
573 psd.resize( k.rows(), k.cols(), f2s.size() );
574
575 for( int cc = 0; cc < psd.cols(); ++cc )
576 {
577 for( int rr = 0; rr < psd.rows(); ++rr )
578 {
579 if( k( rr, cc ) == 0 )
580 psd.pixel( rr, cc ).setZero();
581 else
582 {
583 double p = psdk( rr, cc );
584 mx::sigproc::normPSD( psd2s, f2s, p, -1e5, 1e5 );
585
586 for( int pp = 0; pp < psd.planes(); ++pp )
587 psd.image( pp )( rr, cc ) = psd2s[pp];
588 }
589 }
590 }
591
592 double dk = k( 0, 1 ) - k( 0, 0 );
593 double df = f[1] - f[0];
594
595 int rv = psdF.psd( psd, dk, dk, df );
596
597 REQUIRE( rv == 0 );
598 REQUIRE( psdF.rows() == psd.rows() );
599 REQUIRE( psdF.cols() == psd.cols() );
600 REQUIRE( psdF.planes() == psd.planes() );
601
602 mx::improc::eigenCube<double> noise( psdF.rows(), psdF.cols(), psdF.planes() );
603
604 mx::math::normDistT<double> normVar( false );
605 normVar.seed( 0x50D00006 );
606
607 double avgRms = 0;
608
609 for( int k = 0; k < psdFilterTrials; ++k )
610 {
611 for( int pp = 0; pp < psd.planes(); ++pp )
612 {
613 for( int cc = 0; cc < psd.cols(); ++cc )
614 {
615 for( int rr = 0; rr < psd.rows(); ++rr )
616 {
617 noise.image( pp )( rr, cc ) = normVar;
618 }
619 }
620 }
621
622 psdF( noise );
623 for( int pp = 0; pp < noise.planes(); ++pp )
624 avgRms += noise.image( pp ).square().sum();
625 }
626
627 avgRms = sqrt( avgRms / ( psd.rows() * psd.cols() * psd.planes() ) / psdFilterTrials );
628
629 REQUIRE_THAT( avgRms, Catch::Matchers::WithinAbs( sqrt( 2.0 ), psdFilterTol * sqrt( 2 ) ) );
630 }
631 }
632}
An image cube with an Eigen-like API.
Definition eigenCube.hpp:33
Eigen::Map< Eigen::Array< dataT, Eigen::Dynamic, Eigen::Dynamic >, Eigen::Unaligned, Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > > pixel(Index i, Index j)
Returns an Eigen::Eigen::Map-ed vector of the pixels at the given coordinate.
Eigen::Map< Eigen::Array< dataT, Eigen::Dynamic, Eigen::Dynamic > > image(Index n)
Returns a 2D Eigen::Eigen::Map pointed at the specified image.
void seed(typename ranengT::result_type seedval)
Set the seed of the random engine.
Definition randomT.hpp:96
An image cube with an Eigen API.
TEST_CASE("compiling psdFilter", "[sigproc::psdFilter]")
void augment1SidedPSD(vectorTout &psdTwoSided, vectorTin &psdOneSided, bool addZeroFreq=false, typename vectorTin::value_type scale=0.5)
Augment a 1-sided PSD to standard 2-sided FFT form.
Definition psdUtils.hpp:827
void augment1SidedPSDFreq(std::vector< T > &freqTwoSided, std::vector< T > &freqOneSided)
Augment a 1-sided frequency scale to standard FFT form.
Definition psdUtils.hpp:885
int normPSD(std::vector< floatT > &psd, std::vector< floatT > &f, floatParamT normT, floatT fmin=std::numeric_limits< floatT >::min(), floatT fmax=std::numeric_limits< floatT >::max())
Normalize a 1-D PSD to have a given variance.
Definition psdUtils.hpp:448
int frequencyGrid(std::vector< realT > &vec, realParamT dt, bool fftOrder=true)
Create a 1-D frequency grid.
Definition psdUtils.hpp:258
randomT< realT, std::mt19937_64, std::normal_distribution< realT > > normDistT
Alias for a standard normal random variate.
Definition randomT.hpp:316
valueT vectorVariance(const valueT *vec, size_t sz, valueT mean)
Calculate the variance of a vector relative to a supplied mean value.
Declares and defines a class for filtering with PSDs.
Tools for working with PSDs.
Defines a random number type.
Header for the std::vector utilities.