public FakeCounterCategory(string name)
            : base(name)
        {
            var inSyncRoot = new object();

            InTotal  = new SumTotal(inSyncRoot);
            InPerSec = new RatePerSecond(InTotal, inSyncRoot);

            var outSyncRoot = new object();

            OutTotal     = new SumTotal(outSyncRoot);
            OutPerSec    = new RatePerSecond(OutTotal, outSyncRoot);
            PendingCount = new Delta(
                InTotal,
                OutTotal,
                outSyncRoot);
            PendingTimeAverage = new MovingAverage(
                syncRoot: outSyncRoot);

            var errorsSyncRoot = new object();

            ErrorsTotal  = new SumTotal(errorsSyncRoot);
            ErrorsPerSec = new RatePerSecond(ErrorsTotal, errorsSyncRoot);
            ErrorRatio   = new MeanAverage(
                ErrorsTotal,
                InTotal,
                errorsSyncRoot);
        }
Beispiel #2
0
        /// <summary>
        /// The capital method to get random portions for a list of names.
        /// </summary>
        /// <param name="itemOrGroupNames">
        /// These are the names with which a random portion is supposed to be generated.
        /// </param>
        /// <returns>
        /// A set of item names to some percent where the sum of all the name&apos;s portion is 1 (i.e. 100%).
        /// </returns>
        /// <remarks>
        /// <![CDATA[
        /// FAQ
        /// Q: What happens if no names are given?
        /// A: An ArgumentNullException is thrown.
        ///
        /// Q: What happens if you just invoke it with no options whatsoever (meaning, just instantiate it and call this)?
        /// A: Then every item-name gets a truly random value - the sum of which equals 1.
        ///
        /// Q: How does SumTotal work with GivenDirectly?
        /// A: The only time it matters is when SumTotal exceeds the GivenDirectly's cumulative total; furthermore, SumTotal has no use
        ///    when the GivenDirectly is empty since we are getting random portions and not random values.
        ///
        /// Q: So what happens when there are GivenDirectly values and no SumTotal?
        /// A: Then its just doing the math and nothing is random.
        ///
        /// Q: What happens if SumTotal is less-than GivenDirectly's cumulative total.
        /// A: Then SumTotal is just reassigned to the cumulative total and it again just doing the math - nothing random.
        ///
        /// Q: What about when SumTotal exceeds cumulative total?
        /// A: Then the excess amount is what is used to generate random portions for the other item-names not present
        ///    in GivenDirectly.
        ///
        /// Q: What if there are no items in GivenDirectly?
        /// A: It just resorts back to all item-names having a random portion.
        ///
        /// Q: What happens when the item-names don't match the names present in GivenDirectly?
        /// A: The output is always tied to the item-names - any GivenDirectly not found in the item-names is ignored.
        ///
        /// Q: Can a GivenDirectly entry be assigned an value of zero?
        /// A: Yes, and that is their main purpose to selectively remove randomness for certian item-names - recall
        ///    that the function wants to assign some portion to every item-name, no matter how small.
        ///
        /// Q: What happens if I force every item to be zero using GivenDirectly?
        /// A: An exception is thrown - the function cannot satisfy portions whose sum is equal to both zero and one.
        ///
        /// Q: How do the PossibleZeroOuts play with explict values on GivenDirectly?
        /// A: The PossiableZeroOuts are only considered when they are not present in the GivenDirectly.
        ///
        /// Q: What if the SumTotal exceeds the GivenDirectly's sum but all the other item-names are present
        ///    in the PossiblyZeroOut's and, it just so happens, that they all get selected to be zero-ed out?
        /// A: It leaves one to receive the excess - in effect forcing the dice role to be false for at least
        ///    one of the PossiblyZeroOuts in this case no matter the odds.
        /// ]]>
        /// </remarks>
        public virtual List <Tuple <string, double> > GetNames2Portions(string[] itemOrGroupNames)
        {
            const StringComparison STR_OPT = StringComparison.OrdinalIgnoreCase;

            //make this required
            if (itemOrGroupNames == null || !itemOrGroupNames.Any())
            {
                throw new ArgumentNullException(nameof(itemOrGroupNames));
            }

            var givenDirectlyItems = GivenDirectly ?? new List <Tuple <VocaBase, double> >();

            //immediately reduce this to only the items present in 'itemNames'
            givenDirectlyItems = givenDirectlyItems.Where(gd =>
                                                          itemOrGroupNames.Any(n => string.Equals(gd.Item1.Name, n, STR_OPT))).ToList();

            //get the direct assign's total
            var givenDirectTotal = givenDirectlyItems.Where(x => x?.Item2 != null)
                                   .Select(x => Math.Round(Math.Abs(x.Item2), DF_ROUND_DECIMAL_PLACES)).Sum();

            //get total given by the caller if any
            var sumTotalR = SumTotal.GetValueOrDefault(0);

            //get a random rate for all item names
            var randPortions = Etx.RandomDiminishingPortions(itemOrGroupNames.Length, _derivativeSlope);

            //put this random rate together with each item name
            var randMap = itemOrGroupNames
                          .Zip(randPortions, (n, v) => new Tuple <string, double>(n, v)).ToList();

            //convert it to a dictionary
            var randDict = new Dictionary <string, double>();

            foreach (var t in randMap)
            {
                randDict.Add(t.Item1, t.Item2);
            }

            //filter zero out's down, likewise, to only what's actually in itemNames
            var possibleZeroOuts = Pzos2Prob.Keys.Distinct().ToList();

            possibleZeroOuts = possibleZeroOuts
                               .Where(p => itemOrGroupNames.Any(i => String.Equals(p, i, STR_OPT))).ToList();

            //zero outs will get applied just like any other ReassignRates
            var actualZeroOuts = new List <Tuple <string, double> >();

            //select actual zero outs from the possible zero outs
            if (possibleZeroOuts.Any())
            {
                foreach (var pzo in possibleZeroOuts)
                {
                    //this is the only random part in actual zero-outs
                    var diceRoll = Pzos2Prob.ContainsKey(pzo) ? Pzos2Prob[pzo] : _defaultDice;

                    //these predicates are filters
                    var isAlreadyPresent  = actualZeroOuts.Any(z => z.Item1 == pzo);
                    var isInGivenDirectly = givenDirectlyItems.Any(x =>
                                                                   string.Equals(x.Item1.Name, pzo, STR_OPT));

                    if (diceRoll(pzo) && !isAlreadyPresent && !isInGivenDirectly)
                    {
                        actualZeroOuts.Add(new Tuple <string, double>(pzo, 0.0D));
                    }
                }
            }

            //apply any GivenDirectly's of zero like PossibleZeroOuts
            foreach (var dr in givenDirectlyItems.Where(o => o.Item2 == 0))
            {
                if (actualZeroOuts.All(z => z.Item1 != dr.Item1.Name))
                {
                    actualZeroOuts.Add(new Tuple <string, double>(dr.Item1.Name, 0.0D));
                }
            }

            //zero out all the select names
            if (actualZeroOuts.Any())
            {
                //make one last check that we aren't zero'ing out everything
                if (actualZeroOuts.Count == itemOrGroupNames.Length)
                {
                    throw new WatDaFookIzDis("A sum total of 1 cannot be perserved when " +
                                             "all items have been directly assigned to 0.");
                }

                randDict = ReassignRates(randDict, actualZeroOuts, _derivativeSlope);
            }

            //there is nothing left to do so leave
            if (givenDirectTotal == 0.0D)
            {
                return(randDict.Select(kv => new Tuple <string, double>(kv.Key, kv.Value)).ToList());
            }

            //we will need a denominator if the caller didn't give one use the sum what they did give
            var total = sumTotalR;

            //if caller gives a sumtotal in which all the GivenDirectly won't fit then up the total to make it fit
            if (total < givenDirectTotal)
            {
                total = givenDirectTotal;
            }

            //get a dict of group names to all 0.0D
            var calcDict = new Dictionary <string, double>();

            //get the sum of each given directly item
            foreach (var d in givenDirectlyItems)
            {
                var dName = d.Item1.Name;
                if (string.IsNullOrWhiteSpace(dName) ||
                    d.Item2 == 0)
                {
                    continue;
                }
                if (calcDict.ContainsKey(dName))
                {
                    calcDict[dName] += Math.Abs(d.Item2);
                }
                else
                {
                    calcDict.Add(dName, Math.Abs(d.Item2));
                }
            }

            var calcMap = new List <Tuple <string, double> >();

            //get the item sum as a ratio of the total
            foreach (var k in itemOrGroupNames)
            {
                //we only want to reassign when value was explicitly given in options
                if (!calcDict.ContainsKey(k))
                {
                    continue;
                }

                var rate = Math.Round(calcDict[k] / total, DF_ROUND_DECIMAL_PLACES);
                calcMap.Add(new Tuple <string, double>(k, rate));
            }

            //if the calc map doesn't leave any room for reassignment then we are done
            if (IsCloseEnoughToOne(Math.Round(calcMap.Select(t => t.Item2).Sum(), DF_ROUND_DECIMAL_PLACES)))
            {
                //still need to add in the 0.0 items since calcMap has only the directly assigned values
                foreach (var k in itemOrGroupNames)
                {
                    if (calcMap.Any(t => string.Equals(t.Item1, k, STR_OPT)))
                    {
                        continue;
                    }
                    calcMap.Add(new Tuple <string, double>(k, 0.0D));
                }
                return(calcMap);
            }

            //convert it to a dictionary
            return(ReassignRates(randDict, calcMap).Select(kv => new Tuple <string, double>(kv.Key, kv.Value)).ToList());
        }
 private void ClearAllForm()
 {
     InputOne.Clear();
     InputTwo.Clear();
     SumTotal.Clear();
 }