C++ Library Extensions 2022.12.09
To help learn modern C++ programming
tpf_chrono_random.hpp
Go to the documentation of this file.
1
12#ifndef _TPF_CHRONO_RANDOM_HPP
13#define _TPF_CHRONO_RANDOM_HPP
14
15#ifndef NOMINMAX
16#define NOMINMAX
17#endif
18
19#ifdef _MSVC_LANG
20 #if _MSVC_LANG < 201703L
21 #error This libary requires C++17 Standard (Visual Studio 2017).
22 #endif
23#else
24
25 #if __cplusplus < 201703
26 #error This library requires C++17 Standard (GNU g++ version 8.0 or clang++ version 8.0 above)
27 #endif // end of __cplusplus
28
29#endif // end of _MSVC_LANG
30
31#include <tpf_types.hpp>
32#include <tpf_conversion.hpp>
33
34#include <chrono>
35#include <ratio>
36#include <random>
37#include <iostream>
38#include <sstream>
39#include <vector>
40#include <numeric>
41#include <algorithm>
42#include <execution>
43
44namespace tpf
45{
50 namespace chrono_random
51 {
52 using nano_t = std::nano;
53 using micro_t = std::micro;
54 using milli_t = std::milli;
55 using second_t = std::ratio<1>;
56 using minute_t = std::ratio<60>;
57 using hour_t = std::ratio<3600>;
58
59 template<typename TimeUnit>
60 using duration_t = std::chrono::duration<double, TimeUnit>;
61
68
69 using high_resolution_clock_t = std::chrono::high_resolution_clock;
70 using time_point_t = std::chrono::time_point<high_resolution_clock_t>;
72
73 inline unsigned int seed()
74 { return high_resolution_clock_t::now().time_since_epoch().count(); }
75
76 // used to initialize random engine
77 unsigned int get_current_tick()
78 {
79 using std::chrono::duration;
80 using std::chrono::duration_cast;
81
82 auto current =
83 duration_cast<std::chrono::milliseconds>(now().time_since_epoch());
84
85 return current.count();
86 }
87
88 // to convert time (in TimeUnit) to type double
89 template<typename TimeUnit>
91 const time_point_t& start_time,
92 const time_point_t& end_time)
93 {
94 using std::chrono::duration;
95 using std::chrono::duration_cast;
96
97 if constexpr(std::is_same_v<TimeUnit, second_t>)
98 {
99 auto period_of_time =
100 duration_cast<std::chrono::duration<double, second_t>>(end_time - start_time);
101 return period_of_time.count();
102 }
103 else
104 {
105 auto period_of_time =
106 duration_cast<std::chrono::duration<double, TimeUnit>>(end_time - start_time);
107
108 return period_of_time.count();
109 }
110 }
111
112 using random_engine_t = std::default_random_engine;
113
114 template<typename IntegralType,
115 typename Type = std::enable_if_t<types::is_integral_v<IntegralType>>>
117 std::uniform_int_distribution<IntegralType>;
118
119 template<typename RealType,
120 typename Type = std::enable_if_t<types::is_real_number_v<RealType>>>
122 std::uniform_real_distribution<RealType>;
123
125 {
126 private:
127 mutable high_resolution_clock_t m_clock;
128 mutable time_point_t m_start_time;
129
130 public:
131 stop_watch(): m_start_time{now()}
132 { }
133
134 void reset() const { this->m_start_time = now(); }
135
136 template<typename TimeUnit = milli_t>
137 auto elapsed(bool bReset = true) const
138 {
139 auto rlt = time_difference_in_unit<TimeUnit>(this->m_start_time, now());
140 if(bReset) reset();
141 return rlt;
142 }
143
144 template<typename TimeUnit = milli_t>
145 std::string elapsed_time(bool bReset = true, TimeUnit dummy_time = TimeUnit{}) const
146 {
147 std::ostringstream os;
148
149 os << time_difference_in_unit<TimeUnit>(this->m_start_time, now());
150
151 if constexpr(std::is_same_v<TimeUnit, nano_t>)
152 os << " nano-seconds";
153 else if constexpr(std::is_same_v<TimeUnit, micro_t>)
154 os << " micro-seconds";
155 else if constexpr(std::is_same_v<TimeUnit, milli_t>)
156 os << " milli-seconds";
157 else if constexpr(std::is_same_v<TimeUnit, second_t>)
158 os << " seconds";
159 else if constexpr(std::is_same_v<TimeUnit, minute_t>)
160 os << " minutes";
161 else if constexpr(std::is_same_v<TimeUnit, hour_t>)
162 os << " hours";
163
164 if(bReset) reset();
165 return os.str();
166 }
167 };
168
169 template<typename Type,
170 typename = std::enable_if_t<tpf::types::is_integral_v<Type>>>
172 {
173 private:
174
175 std::random_device m_rd;
176 std::mt19937 m_randomizer;
177 typename std::vector<Type>::iterator m_next;
178 std::vector<Type> m_array;
179
180 public:
181 // [start, end)
182 fair_dice(Type start, Type end, Type instance = 1):
183 m_array((end-start)*instance), m_rd{}, m_randomizer{ m_rd() }
184 {
185 auto diff = end - start;
186
187 for(size_t i = 0; i < m_array.size(); ++i )
188 m_array[i] = (i % diff) + start;
189
190 shuffle();
191 }
192
193 typename std::vector<Type>::iterator begin() { return this->m_array.begin(); };
194 typename std::vector<Type>::iterator end() { return this->m_array.end(); };
195 typename std::vector<Type>::iterator next() { return this->m_next; };
196
197 size_t size() { return m_array.size(); }
198
199 void shuffle()
200 {
201 std::shuffle(m_array.begin(), m_array.end(), m_randomizer);
202 this->m_next = m_array.begin();
203 }
204
206 {
207 if(this->m_next == m_array.end())
208 shuffle();
209
210 Type v = *this->m_next;
211 ++this->m_next;
212 return v;
213 }
214
215 const std::vector<Type>& array()
216 {
217 return this->m_array;
218 }
219 };
220
221 template<typename Type,
222 typename DistributionType, typename EngineType>
224 {
225 public:
226 using engine_type = EngineType;
227 using distribution_type = DistributionType;
228 private:
229 mutable Type m_range_start;
230 mutable Type m_range_end;
231 mutable engine_type m_engine;
232 mutable distribution_type m_distribution;
233
234 public:
235 random_t(Type range_start = Type{},
236 Type range_end = Type{100},
237 unsigned int seed = 0):
238 m_range_start{range_start},
239 m_range_end{range_end},
240 m_engine{seed == 0 ? get_current_tick(): seed},
241 m_distribution{range_start, range_end} {}
242
243 random_t(const random_t&) = default;
244 random_t& operator=(const random_t&) = default;
245
246 Type operator()() const
247 {
248 return m_distribution(m_engine);
249 }
250
251 template<typename SizeType>
252 auto clone(SizeType size) const;
253
254 template<typename SizeType>
255 auto clone_pair(SizeType size) const;
256 };
257
258 template<typename IntegralType,
259 typename Type = std::enable_if_t<types::is_integral_v<IntegralType>>>
260 using random_uniform_integer_t = random_t<IntegralType,
262
263 template<typename RealType,
264 typename Type = std::enable_if_t<types::is_real_number_v<RealType>>>
267
268 template<typename ValueType, typename RangeType1, typename RangeType2>
269 auto random_generator(RangeType1 range_start, RangeType2 range_end)
270 {
271 if constexpr(tpf::types::is_integral_v<ValueType>)
272 {
274 random_generator{(ValueType)range_start, (ValueType)range_end};
275
276 return random_generator;
277 }
278 else if constexpr(tpf::types::is_real_number_v<ValueType>)
279 {
281 random_generator{(ValueType)range_start, (ValueType)range_end};
282
283 return random_generator;
284 }
285 }
286
287 template<typename Type,
288 typename DistributionType, typename EngineType>
289 template<typename SizeType>
291 {
292 using random_type =
294
295 std::vector<random_type> randoms;
296 randoms.reserve((size_t)size);
297
298 auto generator =
299 random_generator<unsigned>((unsigned)1,
300 std::numeric_limits<unsigned>::max());
301
302 std::set<unsigned> seeds;
303 while(seeds.size() != (size_t)size)
304 {
305 seeds.insert(generator());
306 }
307
308 for(auto seed: seeds)
309 randoms.emplace_back(random_type{this->m_range_start,
310 this->m_range_end, seed});
311
312 return randoms;
313 }
314
315 template<typename Type,
316 typename DistributionType, typename EngineType>
317 template<typename SizeType>
319 {
320 using random_type =
322 using random_pair = std::pair<size_t, random_type>;
323
324 std::vector<random_pair> randoms;
325 randoms.reserve((size_t)size);
326
327 auto generator =
328 random_generator<unsigned>((unsigned)1,
329 std::numeric_limits<unsigned>::max());
330
331 std::set<unsigned> seeds;
332 while(seeds.size() != (size_t)size)
333 {
334 seeds.insert(generator());
335 }
336
337 size_t index{};
338
339 for(auto seed: seeds)
340 randoms.emplace_back(index++, random_type{this->m_range_start,
341 this->m_range_end, seed});
342
343 return randoms;
344 }
345
346 template<template<typename, typename...> class ContainerType,
347 typename Type, typename RType, typename... Types,
348 template<typename, typename...> class RandomGeneratorType, typename... RTypes>
349 void random_fill(ContainerType<Type, Types...>& container,
350 const RandomGeneratorType<RType, RTypes...>& random_generator)
351 {
352 if(container.empty())
353 return;
354
355 for(auto& e: container)
356 e = (Type)random_generator();
357 }
358
359 template<typename Type, std::size_t N, typename RandomGeneratorType>
360 void random_fill( Type(&container)[N], RandomGeneratorType const& random_generator)
361 {
362 for(auto& e: container)
363 e = (Type)random_generator();
364 }
365
366 template<typename Type, std::size_t M, std::size_t N, typename RandomGeneratorType>
367 void random_fill( Type(&container)[M][N], RandomGeneratorType const& random_generator)
368 {
369 using array_t = Type[M * N];
370 auto& array = (array_t&)container[0][0];
371
373 }
374
375 template<typename Type, std::size_t L, std::size_t M, std::size_t N, typename RandomGeneratorType>
376 void random_fill( Type(&container)[L][M][N], RandomGeneratorType const& random_generator)
377 {
378 using array_t = Type[L * M * N];
379 auto& array = (array_t&)container[0][0];
380
382 }
383
384 template<template<typename, std::size_t> class ContainerType,
385 typename Type, std::size_t N, typename RType,
386 template<typename, typename...> class RandomGeneratorType, typename... RTypes>
387 void random_fill(ContainerType<Type, N>& container,
388 const RandomGeneratorType<RType, RTypes...>& random_generator)
389 {
390 if(container.empty())
391 return;
392
393 for(auto& e: container)
394 e = (Type)random_generator();
395 }
396
397 template<template<typename, typename...> class ContainerType,
398 typename Type, typename... Types, typename RandomGeneratorType>
399 void random_fill(ContainerType<Type, Types...>& container,
400 RandomGeneratorType&& random_generator)
401 {
402 if(container.empty())
403 return;
404
405 for(auto& e: container)
406 e = (Type) random_generator();
407 }
408
409 template<template<typename, typename...> class ContainerType,
410 typename Type, typename... Types, typename RType,
411 template<typename, typename...> class RandomGeneratorType, typename... RTypes>
412 void random_parallel_fill(ContainerType<Type, Types...>& container,
413 const RandomGeneratorType<RType, RTypes...>& random_generator)
414 {
415 if(container.empty()) return;
416
417 size_t container_size = container.size();
418 size_t generator_size = std::thread::hardware_concurrency();
419 size_t span = container_size / generator_size;
420
421 if(span < 100)
422 {
423 random_fill(container, random_generator);
424 return;
425 }
426
427 if(container_size % generator_size ) ++generator_size;
428
429 auto generator_pairs =
430 random_generator.clone_pair(generator_size);
431
432 std::for_each(std::execution::par,
433 generator_pairs.begin(), generator_pairs.end(),
434 [&](auto& pair)
435 {
436 auto index_start = pair.first * span;
437 auto index_end = index_start + span;
438
439 if(index_end > container_size) index_end = container_size;
440
441 for(size_t i = index_start; i < index_end; ++i)
442 container[i] = (Type)pair.second();
443 });
444 }
445
446 template<typename Type, std::size_t N,
447 template<typename, typename...> class RandomGeneratorType, typename RType, typename... RTypes>
448 void random_parallel_fill( Type( &container )[N],
449 const RandomGeneratorType<RType, RTypes...>& random_generator)
450 {
451 size_t container_size = N;
452 size_t generator_size = std::thread::hardware_concurrency();
453 size_t span = container_size / generator_size;
454
455 if(span < 100)
456 {
457 random_fill(container, random_generator);
458 return;
459 }
460
461 if(container_size % generator_size ) ++generator_size;
462
463 auto generator_pairs =
464 random_generator.clone_pair(generator_size);
465
466 std::for_each(std::execution::par,
467 generator_pairs.begin(), generator_pairs.end(),
468 [&](auto& pair)
469 {
470 auto index_start = pair.first * span;
471 auto index_end = index_start + span;
472
473 if(index_end > container_size) index_end = container_size;
474
475 for(size_t i = index_start; i < index_end; ++i)
476 container[i] = (Type)pair.second();
477 });
478 }
479
480 template<typename Type, std::size_t M, std::size_t N,
481 template<typename, typename...> class RandomGeneratorType, typename RType, typename... RTypes>
482 void random_parallel_fill( Type( &container )[M][N],
483 const RandomGeneratorType<RType, RTypes...>& random_generator)
484 {
485 using array_t = Type[M * N];
486 auto& array = (array_t&)container[0][0];
487
489 }
490
491 template<typename Type, std::size_t L, std::size_t M, std::size_t N,
492 template<typename, typename...> class RandomGeneratorType, typename RType, typename... RTypes>
493 void random_parallel_fill( Type( &container )[L][M][N],
494 const RandomGeneratorType<RType, RTypes...>& random_generator)
495 {
496 using array_t = Type[L * M * N];
497 auto& array = (array_t&)container[0][0][0];
498
500 }
501
502
503 template<template<typename, std::size_t> class ContainerType,
504 typename Type, std::size_t N, typename RType,
505 template<typename, typename...> class RandomGeneratorType, typename... RTypes>
506 void random_parallel_fill(ContainerType<Type, N>& container,
507 const RandomGeneratorType<RType, RTypes...>& random_generator)
508 {
509 if(container.empty()) return;
510
511 size_t container_size = container.size();
512 size_t generator_size = std::thread::hardware_concurrency();
513 size_t span = container_size / generator_size;
514
515 if(span < 100)
516 {
517 random_fill(container, random_generator);
518 return;
519 }
520
521 if(container_size % generator_size ) ++generator_size;
522
523 auto generator_pairs =
524 random_generator.clone_pair(generator_size);
525
526 std::for_each(std::execution::par,
527 generator_pairs.begin(), generator_pairs.end(),
528 [&](auto& pair)
529 {
530 auto index_start = pair.first * span;
531 auto index_end = index_start + span;
532
533 if(index_end > container_size) index_end = container_size;
534
535 for(size_t i = index_start; i < index_end; ++i)
536 container[i] = (Type)pair.second();
537 });
538 }
539
540 template<template<typename, typename...> class ContainerType,
541 typename Type, typename... Types,
542 typename RandomGeneratorType>
543 void random_parallel_fill(ContainerType<Type, Types...>& container,
544 RandomGeneratorType&& random_generator)
545 {
546 if(container.empty()) return;
547
548 size_t container_size = container.size();
549 size_t generator_size = std::thread::hardware_concurrency();
550 size_t span = container_size / generator_size;
551
552 if(span < 100)
553 {
554 random_fill(container, random_generator);
555 return;
556 }
557
558 if(container_size % generator_size ) ++generator_size;
559
560 auto generator_pairs =
561 random_generator.clone_pair(generator_size);
562
563 std::for_each(std::execution::par,
564 generator_pairs.begin(), generator_pairs.end(),
565 [&](auto& pair)
566 {
567 auto index_start = pair.first * span;
568 auto index_end = index_start + span;
569
570 if(index_end > container_size) index_end = container_size;
571
572 for(size_t i = index_start; i < index_end; ++i)
573 container[i] = pair.second();
574 });
575 }
576
593 template<template<typename, typename...> class ContainerType,
594 typename Type, typename... Types, typename SizeType,
595 template<typename, typename...> class RandomGeneratorType, typename... RTypes>
596 void random_fill(ContainerType<Type, Types...>& container,
597 const RandomGeneratorType<Type, RTypes...>& random_generator, SizeType size)
598 {
599 if constexpr (types::is_resize_available_v<ContainerType<Type, Types...>>)
600 {
601 container.resize((size_t)size);
602
603 for(auto& e: container)
604 e = random_generator();
605 }
606 else
607 {
608 container.clear();
609
610 while(container.size() != size)
611 {
613 }
614 }
615 }
616
617 template<typename CharType, size_t Size>
619 {
620 public:
621
622 const CharType* m_alphabet;
626
627 public:
628 template<typename Type, size_t ArraySize>
629 random_words(size_t minimum, size_t maximum, size_t max_words,
630 const Type(&alphabet)[ArraySize]):
631 m_alphabet{alphabet},
632 m_character_selector{ random_generator<size_t>(size_t{}, ArraySize-2)},
633 m_length_selector{ random_generator<size_t>(minimum, maximum) },
634 m_wordcount_selector{ random_generator<size_t>(1, max_words) } { }
635
636 std::basic_string<char> operator()()
637 {
638 // Windows codepage character - char
639 if constexpr(std::is_same_v<CharType, char>)
640 {
641 std::basic_ostringstream<CharType> stream;
642
643 auto word_count = m_wordcount_selector();
644
645 for(size_t j = 0; j < word_count; ++j)
646 {
647 auto length = this->m_length_selector();
648
649 std::basic_string<CharType> text(length, ' ');
650
651 for(size_t i=0; i < length; ++i)
652 text[i] = m_alphabet[m_character_selector()];
653
654 stream << text;
655
656 if(j + 1 != (size_t)word_count) stream <<' ';
657 }
658 return stream.str();
659 }
660 else
661 {
662 // utf16 - wchar_t == CharType
663 std::basic_ostringstream<CharType> stream;
664
665 auto word_count = m_wordcount_selector();
666
667 for(size_t j = 0; j < word_count; ++j)
668 {
669 auto length = this->m_length_selector();
670
671 std::basic_string<CharType> text(length, L' ');
672
673 for(size_t i=0; i < length; ++i)
674 text[i] = m_alphabet[m_character_selector()];
675
676 stream << text;
677
678 if(j + 1 != (size_t)word_count) stream << L' ';
679 }
680
681 // UTF16 - utf8 std::string
682 // conversion::wstring_to_string(stream.str());
683
684 // UTF16 - Windows codepage std::string
685 return conversion::wstring_to_string(stream.str(), CP_ACP);
686 }
687 }
688 };
689
690 template<typename Type, size_t ArraySize>
691 random_words(int, int, int, const Type(&)[ArraySize]) -> random_words<Type, ArraySize>;
692
693
694 } // end of namespace chrono_random
695
696} // end of namespace tpf
697
698#endif // end of file _TPF_CHRONO_RANDOM_HPP
tpf::sstream stream
std::vector< Type >::iterator end()
std::vector< Type >::iterator begin()
fair_dice(Type start, Type end, Type instance=1)
const std::vector< Type > & array()
std::vector< Type >::iterator next()
random_t(Type range_start=Type{}, Type range_end=Type{100}, unsigned int seed=0)
auto clone_pair(SizeType size) const
random_t & operator=(const random_t &)=default
auto clone(SizeType size) const
random_t(const random_t &)=default
random_words(size_t minimum, size_t maximum, size_t max_words, const Type(&alphabet)[ArraySize])
random_uniform_integer_t< size_t > m_wordcount_selector
random_uniform_integer_t< size_t > m_length_selector
random_uniform_integer_t< size_t > m_character_selector
std::basic_string< char > operator()()
std::string elapsed_time(bool bReset=true, TimeUnit dummy_time=TimeUnit{}) const
auto elapsed(bool bReset=true) const
std::string str() const
Definition: tpf_output.hpp:951
std::uniform_int_distribution< IntegralType > random_uniform_integral_distribution
duration_t< nano_t > nanoseconds_t
std::ratio< 3600 > hour_t
auto random_generator(RangeType1 range_start, RangeType2 range_end)
std::chrono::duration< double, TimeUnit > duration_t
duration_t< second_t > seconds_t
std::chrono::time_point< high_resolution_clock_t > time_point_t
unsigned int get_current_tick()
duration_t< micro_t > microseconds_t
duration_t< milli_t > milliseconds_t
double time_difference_in_unit(const time_point_t &start_time, const time_point_t &end_time)
std::chrono::high_resolution_clock high_resolution_clock_t
void random_parallel_fill(ContainerType< Type, Types... > &container, const RandomGeneratorType< RType, RTypes... > &random_generator)
random_words(int, int, int, const Type(&)[ArraySize]) -> random_words< Type, ArraySize >
std::uniform_real_distribution< RealType > random_uniform_real_distribution
duration_t< hour_t > hours_t
std::default_random_engine random_engine_t
duration_t< minute_t > minutes_t
std::ratio< 1 > second_t
std::ratio< 60 > minute_t
void random_fill(ContainerType< Type, Types... > &container, const RandomGeneratorType< RType, RTypes... > &random_generator)
std::string wstring_to_string(const std::wstring &wstr, unsigned int codepage=CP_UTF8)
Converts from std::wstring to std::string with codepage.
constexpr bool is_resize_available_v
Definition: tpf_types.hpp:5365
void push_back(ContainerType< Type, Types... > &container, EleType &&ele)
Definition: tpf_types.hpp:7110
Includes subnamespace conversion.
Definition: 31-visit.cpp:7
auto minimum(Type_1 a, Type_2 b)
Definition: tpf_types.hpp:196
auto maximum(Type_1 a, Type_2 b)
Definition: tpf_types.hpp:181
String conversions are implemented.
Type functions are implemented.