Christoph,
I meant to also mention an alternative way of displaying histograms in test methods (I find it useful to include output in tests to easily observe the various distribution configurations).
I basically just extended ConsoleHelper with a variety of additional methods to make the output compatible with the MSTest output restrictions (no random console cursor access). The main method for a histogram that can be displayed in test output is shown below.
(I have added a variety of other methods that embellish the output with basic statistics and whatnot, but those have nothing to do with the console output restrictions solved here).
The output for a histogram simply needs to be rotated 90 degrees to make it work reasonably well in tests:
So my tests then can then look something like the following (with no assertions in this case):
;-)
I meant to also mention an alternative way of displaying histograms in test methods (I find it useful to include output in tests to easily observe the various distribution configurations).
I basically just extended ConsoleHelper with a variety of additional methods to make the output compatible with the MSTest output restrictions (no random console cursor access). The main method for a histogram that can be displayed in test output is shown below.
(I have added a variety of other methods that embellish the output with basic statistics and whatnot, but those have nothing to do with the console output restrictions solved here).
The output for a histogram simply needs to be rotated 90 degrees to make it work reasonably well in tests:
public static void DisplayHistogramRotate90(IEnumerable<double> data
, int numBuckets = 20, int maxBarLength = 80)
{
var fmt = "{0, 6} : {1, -" + maxBarLength + "} : {2}";
var blockSymbol = Convert.ToChar(9608);
var hist = new Histogram(data, numBuckets);
var maxBucketCount = 0.0;
for (var i = 0; i < hist.BucketCount; i++)
{
if (hist[i].Count > maxBucketCount)
maxBucketCount = hist[i].Count;
}
Console.WriteLine("Histogram:");
for (var i = 0; i < hist.BucketCount; i++)
{
var fraction = hist[i].Count / maxBucketCount;
var dots = (int)(maxBarLength * fraction);
Console.WriteLine(fmt, i, new string(blockSymbol, dots), hist[i]);
}
}
Also, I added a method to generalize the display for any particular distribution (when there is a chance of throwing a "NotImplementedException" when accessing certain properties): public static void DisplayDiscreteDistribution(IDiscreteDistribution dist, int numHistSamples = 100000, int numHistBuckets = 20)
{
const string fmt = "{0, 20} = {1, 20}";
var divider = new string('*', 120);
Console.WriteLine(divider);
Console.WriteLine("{0}:\n", dist);
try
{
Console.WriteLine(fmt, "CDF (location 3)", dist.CumulativeDistribution(3).ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "Prob (location 3)", dist.Probability(3).ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "ProbLn (location 3)", dist.ProbabilityLn(3).ToString("f5"));
}
catch { }
try
{
Console.WriteLine(fmt, "Entropy", dist.Entropy.ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "MaxValue", dist.Maximum.ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "MinValue", dist.Minimum.ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "Mean", dist.Mean.ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "Mode", dist.Mode.ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "Variance", dist.Variance.ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "StdDev", dist.StdDev.ToString("F5"));
}
catch { }
try
{
Console.WriteLine(fmt, "Skewness", dist.Skewness.ToString("F5"));
}
catch { }
Console.WriteLine();
Console.Write("Samples(10): ");
for (var i = 0; i < 10; i++)
{
Console.Write(dist.Sample().ToString("N5") + " ");
}
Console.WriteLine();
Console.WriteLine();
//// 4. Generate 100000 samples of the distribution and display histogram
var data = new double[numHistSamples];
for (var i = 0; i < data.Length; i++)
{
data[i] = dist.Sample();
}
DisplayHistogramRotate90(data, numHistBuckets);
Console.WriteLine(divider);
}
Obviously, there is another similar method for IContinuousDistribution types.So my tests then can then look something like the following (with no assertions in this case):
[TestMethod]
public void GeometricVariationsTest()
{
var dist = new Geometric(p: 0.01, randomSource: new MersenneTwister());
ConsoleHelper.DisplayDiscreteDistribution(dist, 100000, 40);
dist.P = 0.2;
ConsoleHelper.DisplayDiscreteDistribution(dist, 100000, 40);
dist.P = 0.5;
ConsoleHelper.DisplayDiscreteDistribution(dist, 100000, 40);
dist.P = 0.8;
ConsoleHelper.DisplayDiscreteDistribution(dist, 100000, 40);
}
Hopefully, someone else might find this a useful way of experimenting with the distributions, without needing to create repetitive console application code. ;-)