|
9 | 9 | using System.Collections.Generic;
|
10 | 10 | using System.Diagnostics;
|
11 | 11 | using System.IO;
|
| 12 | +using System.Linq; |
12 | 13 | using System.Threading;
|
13 | 14 | using System.Threading.Tasks;
|
14 | 15 |
|
@@ -620,6 +621,69 @@ public TimeSpan RandWeibull(IRandom random, TimeSpan alpha, TimeSpan beta) {
|
620 | 621 | public TimeSpan RandWeibull(TimeSpan alpha, TimeSpan beta) {
|
621 | 622 | return RandWeibull(Random, alpha, beta);
|
622 | 623 | }
|
| 624 | + |
| 625 | + |
| 626 | + /// <summary> |
| 627 | + /// Generates a random sample from a given source |
| 628 | + /// </summary> |
| 629 | + /// <typeparam name="T">The type of the element in parameter source</typeparam> |
| 630 | + /// <exception cref="ArgumentException"> |
| 631 | + /// Thrown when <paramref name="source"/> and <paramref name="weights"/> have different size. |
| 632 | + /// or when <paramref name="weights"/> contains an invalid or negative value. |
| 633 | + /// or when <paramref name="weights"/> sum equals zero or an invalid value. |
| 634 | + /// </exception> |
| 635 | + /// <param name="random">The random number generator to use.</param> |
| 636 | + /// <param name="source">a random sample is generated from its elements.</param> |
| 637 | + /// <param name="weights">The weight associated with each entry in source.</param> |
| 638 | + /// <returns>The generated random samples</returns> |
| 639 | + public T RandChoice<T>(IRandom random, IList<T> source, IList<double> weights) { |
| 640 | + if (source.Count != weights.Count) { |
| 641 | + throw new ArgumentException("source and weights must have same size"); |
| 642 | + } |
| 643 | + |
| 644 | + double totalW = 0; |
| 645 | + foreach (var w in weights) { |
| 646 | + if (w < 0) { |
| 647 | + throw new ArgumentException("weight values must be non-negative", nameof(weights)); |
| 648 | + } |
| 649 | + totalW += w; |
| 650 | + } |
| 651 | + |
| 652 | + if (double.IsNaN(totalW) || double.IsInfinity(totalW)) |
| 653 | + throw new ArgumentException("Not a valid weight", nameof(weights)); |
| 654 | + if (totalW == 0) |
| 655 | + throw new ArgumentException("total weight must be greater than 0", nameof(weights)); |
| 656 | + |
| 657 | + var rnd = random.NextDouble(); |
| 658 | + double aggWeight = 0; |
| 659 | + int idx = 0; |
| 660 | + foreach (var w in weights) { |
| 661 | + if (w > 0) { |
| 662 | + aggWeight += (w / totalW); |
| 663 | + if (rnd <= aggWeight) { |
| 664 | + break; |
| 665 | + } |
| 666 | + } |
| 667 | + idx++; |
| 668 | + } |
| 669 | + return source[idx]; |
| 670 | + } |
| 671 | + /// <summary> |
| 672 | + /// Generates a random sample from a given source |
| 673 | + /// </summary> |
| 674 | + /// <typeparam name="T">The type of the element in parameter source</typeparam> |
| 675 | + /// <exception cref="ArgumentException"> |
| 676 | + /// Thrown when <paramref name="source"/> and <paramref name="weights"/> have different size. |
| 677 | + /// or when <paramref name="weights"/> contains an invalid or negative value. |
| 678 | + /// or when <paramref name="weights"/> sum equals zero |
| 679 | + /// </exception> |
| 680 | + /// <param name="source">a random sample is generated from its elements.</param> |
| 681 | + /// <param name="weights">The weight associated with each entry in source.</param> |
| 682 | + /// <returns>The generated random samples</returns> |
| 683 | + public T RandChoice<T>(IList<T> source, IList<double> weights) { |
| 684 | + return RandChoice(Random, source, weights); |
| 685 | + } |
| 686 | + |
623 | 687 | #endregion
|
624 | 688 |
|
625 | 689 | #region Random timeouts
|
|
0 commit comments