Generating Biased Random Values (Walker’s Alias Method)

Am simply wondering if I made any egregious mistakes while implementing the Alias Method as an IEnumerator<TElement>; would also like to know if there are any sorts of general improvements that can be made to the design of the class.

Usage:

var rng = Pcg32XshRr.New(0, 1); var generator = ProbabilisticEnumerator     .New(         elementWeights: new Dictionary<string, int> {             { "A", 1 },             { "B", 2 },             { "C", 4 }         },         randomNumberGenerator: rng     )     .Take(100000); var summary = generator     .GroupBy(item => item)     .Select(item => new {         Element = item.Key,         Count = item.Count(),     })     .OrderBy(item => item.Element);  foreach (var item in summary) {     Console.WriteLine($  "{item.Element} | {item.Count}"); } 

Code:

Nuget Package

Source Repository

/// <summary> /// Represents an enumerator that yields elements in accordance with the rules descibed by a probability table; relies on Michael D Vose's implementation of <a href="https://en.wikipedia.org/wiki/Alias_method">Walker's Alias Method.</a> /// </summary> /// <typeparam name="TElement">The type of elements encapsulated by the enumerator.</typeparam> /// <remarks> /// Derived from https://github.com/BlueRaja/Weighted-Item-Randomizer-for-C-Sharp. /// </remarks> public class ProbabilisticEnumerator<TElement> : IEnumerable<TElement>, IEnumerator<TElement> {     private readonly struct ElementMetadata     {         public int ActualIndex { get; }         public int AliasedIndex { get; }         public int Threshold { get; }          public ElementMetadata(int actualIndex, int aliasedIndex, int biasAreaSize) {             ActualIndex = actualIndex;             AliasedIndex = aliasedIndex;             Threshold = biasAreaSize;         }     }      private readonly ElementMetadata[] m_elementMetadata;     private readonly TElement[] m_elements;     private readonly int m_heightPerRectangle;     private readonly IUniformlyDistributedRandomNumberGenerator m_randomNumberGenerator;      /// <summary>     /// Gets the next random element.     /// </summary>     public TElement Current {         get {             var elementMetadata = m_elementMetadata;             var elements = m_elements;             var heightPerRectangle = m_heightPerRectangle;             var randomNumberGenerator = m_randomNumberGenerator;             var randomHeight = randomNumberGenerator.NextInt32(0, heightPerRectangle);             var randomMetadata = elementMetadata[randomNumberGenerator.NextInt32(0, (elementMetadata.Length - 1))];              return ((randomHeight <= randomMetadata.Threshold) ? elements[randomMetadata.ActualIndex] : elements[randomMetadata.AliasedIndex]);         }     }     /// <summary>     /// Gets the next random element.     /// </summary>     object IEnumerator.Current => Current;      /// <summary>     /// Initializes a new instance of the <see cref="ProbabilisticEnumerator{TElement}"/> class.     /// </summary>     /// <param name="elementWeights">The collection of element-to-weight pairs that defines the rules for the table.</param>     /// <param name="randomNumberGenerator">The source of random numbers that will be used to perform extract elements from the table.</param>     private ProbabilisticEnumerator(IReadOnlyDictionary<TElement, int> elementWeights, IUniformlyDistributedRandomNumberGenerator randomNumberGenerator) {         if (elementWeights.IsNull()) {             throw new ArgumentNullException(paramName: nameof(elementWeights));         }          var count = unchecked((ulong)elementWeights.Count);         var elements = new TElement[count];         var index = 0;         var totalWeight = 0UL;          foreach (var kvp in elementWeights) {             var element = kvp.Key;             var weight = kvp.Value;              if (0 > weight) {                 throw new ArgumentOutOfRangeException(actualValue: weight, message: "weight must be a positive integer", paramName: nameof(weight));             }              elements[index++] = element;             totalWeight += unchecked((ulong)weight);         }          var gcd = BitwiseHelpers.GreatestCommonDivisor(count, totalWeight);         var heightPerRectangle = checked((int)(totalWeight / gcd));         var weightMultiplier = checked((int)(count / gcd));          m_elementMetadata = InitializeMetadata(elementWeights, weightMultiplier, heightPerRectangle);         m_elements = elements;         m_heightPerRectangle = heightPerRectangle;         m_randomNumberGenerator = randomNumberGenerator;     }      /// <summary>     /// Releases all resources used by this <see cref="ProbabilisticEnumerator{TElement}"/> instance.     /// </summary>     public void Dispose() { }     /// <summary>     /// Returns an enumerator that yields a random element from the table.     /// </summary>     public IEnumerator<TElement> GetEnumerator() => this;     /// <summary>     /// Returns an enumerator that yields a random element from the table.     /// </summary>     IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();     /// <summary>     /// Returns true.     /// </summary>     public bool MoveNext() => true;     /// <summary>     /// Throws <see cref="NotSupportedException"/>.     /// </summary>     public void Reset() => new NotSupportedException();      private static ElementMetadata[] InitializeMetadata(IReadOnlyDictionary<TElement, int> elementWeights, int weightMultiplier, int heightPerRectangle) {         var count = elementWeights.Count;         var elementMetadata = new ElementMetadata[count];         var index = 0;         var stackLarge = new Stack<KeyValuePair<int, int>>();         var stackSmall = new Stack<KeyValuePair<int, int>>();          foreach (var kvp in elementWeights) {             var newWeight = (kvp.Value * weightMultiplier);              if (newWeight > heightPerRectangle) {                 stackLarge.Push(new KeyValuePair<int, int>(index++, newWeight));             }             else {                 stackSmall.Push(new KeyValuePair<int, int>(index++, newWeight));             }         }          while (0 < stackLarge.Count) {             var largeItem = stackLarge.Pop();             var smallItem = stackSmall.Pop();              largeItem = new KeyValuePair<int, int>(largeItem.Key, (largeItem.Value - (heightPerRectangle - smallItem.Value)));              if (largeItem.Value > heightPerRectangle) {                 stackLarge.Push(largeItem);             }             else {                 stackSmall.Push(largeItem);             }              elementMetadata[--count] = new ElementMetadata(smallItem.Key, largeItem.Key, smallItem.Value);         }          while (0 < stackSmall.Count) {             var smallItem = stackSmall.Pop();              elementMetadata[--count] = new ElementMetadata(smallItem.Key, smallItem.Key, heightPerRectangle);         }          return elementMetadata;     }      /// <summary>     /// Initializes a new instance of the <see cref="ProbabilisticEnumerator{TElement}"/> class.     /// </summary>     /// <param name="elementWeights">The collection of element-to-weight pairs that defines the rules for the table.</param>     /// <param name="randomNumberGenerator">The source of random numbers that will be used to perform extract elements from the table.</param>     public static ProbabilisticEnumerator<TElement> New(IReadOnlyDictionary<TElement, int> elementWeights, IUniformlyDistributedRandomNumberGenerator randomNumberGenerator) => new ProbabilisticEnumerator<TElement>(elementWeights, randomNumberGenerator); }  /// <summary> /// A collection of methods that directly or indirectly augment the <see cref="ProbabilisticEnumerator{TElement}"/> class. /// </summary> public static class ProbabilisticEnumerator {     /// <summary>     /// Initializes a new instance of the <see cref="ProbabilisticEnumerator{TElement}"/> class.     /// </summary>     /// <param name="elementWeights">The collection of element-to-weight pairs that defines the rules for the table.</param>     /// <param name="randomNumberGenerator">The source of random numbers that will be used to perform extract elements from the table.</param>     public static ProbabilisticEnumerator<TElement> New<TElement>(IReadOnlyDictionary<TElement, int> elementWeights, IUniformlyDistributedRandomNumberGenerator randomNumberGenerator) => ProbabilisticEnumerator<TElement>.New(elementWeights, randomNumberGenerator); } 

How would I clear values in ajax loaded select options?

http://pastebin.com/TX2UiJGZ

I have 3 select drop-downs, selecting a value in the first populates the second using ajax, selecting the second populates the third. However when I change the value of the first select it doesn’t reset the second (If I already chose the first and the second drop down initially).

Method

  • Choose an option from the first
  • This populates the second select with options A, B and C
  • If I change the first one it won’t reset the value if that value existed on the first option
  • So if our first option called A, B and C and we change the first drop-down to something else but it calls C, D and E; if C was selected in the second drop-down it doesn’t reset since it existed in both ajax calls, this then doesn’t load in the third select unless you select a different option in the second select.

Basically what I need is to reset the second and third select whenever the first changes.

How to store dynamic “select” values and names in a object for onchange event

I have a table of dynamic data which is echo’ed out on the webpage in a table format as shown in the picture

LINK FOR THE IMAGE: https://ibb.co/RCYwchv

so the table will have a lot of select tags with different names and values depending upon how much (applications are there ) iteration takes place!

     foreach($  data['applicationList'] as $  applications)                 {                       echo '<td><select name='.$  applications['aid'].'>                         <option value=000>Reject All<option>                         <option value=111>Accept All<option>                         <option value=100>Accept 1st Choise<option>                         <option value=010>Accept 2nd Choise<option>                         <option value=001>Accept 3rd Choise<option>                         <option value=110>Accept 1st and 2nd Choise<option>                         <option value=011>Accept 2nd and 3rd Choise<option>                         <option value=101>Accept 1st and 3rd Choise<option>                         </select></td> 

}

Is there any way i could capture all the different selected values and names which are changed and bind them to an object of key value pair to send it to the controller using javascript or jquery ajax? Could someone help me on this!

What happens if an attacker and defender have exactly equal (net difference 0) final values for their attack and defense rolls?

The title somewhat says it all… What happens if an attacker and defender roll exactly equal values? This actually happened to me in a test combat. The other player and I mutually agreed nothing happened.

There’s no entry on the Combat Table for it, this much I know.

List of unique values based on a criterion

I am working on a Google Sheets that has a phrase, assigned number to the phrase and then I want to create a new list on a new column of phrases that have an assigned number less than 5. Moreover, I do not want phrases repeated:

Screenshot of my sheet

Currently I have this as my formula in cell E4:

=IFERROR(INDEX(C4:C25000,SMALL(IF(D4:D25000>5,IF(COUNTIF(C$  4:C4,C4:C25000)=0,ROW(C4:C25000)-ROW(C$  4)+1)),1)),"") 

and it is not working.

Could anyone help me to get this right?

I have access to Excel so that would work too.

Finding multiple “most common values” in a column

I am trying to display the 5 most commonly appearing text values in a column in Google Sheets.

The following will give me the most common value in column A:

=ArrayFormula(INDEX(A:A,MODE(MATCH(A:A,A:A,0)))) 

And this will give me the second most common value in column A, assuming that the formula above is in cell G2 (whose result is being excluded):

=ArrayFormula(INDEX(A:A,MODE(IF(A:A<>G2,MATCH(A:A,A:A,0))))) 

How can I get the third, fourth, fifth, etc most common values? Something like this does not work:

=ArrayFormula(INDEX(A:A,MODE(IF(A:A<>G2:G3,MATCH(A:A,A:A,0))))) 

Basically I need to exclude multiple values from that calculation. Any ideas?