Browse Source

Added F# Apply example

Added F# DenseVector implementation
Added the Histogram class

Signed-off-by: jvangael <jurgen.vangael@gmail.com>
la-knuth
Jurgen Van Gael 17 years ago
parent
commit
497938a20e
  1. 92
      src/FSharpExamples/Apply.fs
  2. 30
      src/FSharpExamples/DenseVector.fs
  3. 1
      src/FSharpExamples/FSharpExamples.fsproj
  4. 1
      src/Numerics/Numerics.csproj
  5. 22
      src/Numerics/Properties/Resources.Designer.cs
  6. 8
      src/Numerics/Properties/Resources.resx
  7. 455
      src/Numerics/Statistics/Histogram.cs
  8. 250
      src/UnitTests/StatisticsTests/HistogramTests.cs
  9. 1
      src/UnitTests/UnitTests.csproj

92
src/FSharpExamples/Apply.fs

@ -0,0 +1,92 @@
// <copyright file="Apply.fs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra.Double
/// Flag to specify wether we want pretty printing or tab separated output.
let prettyPrint = false
/// The size of the vector we want to map things for.
let N = 1000000
/// The number of times we repeat a call.
let T = 10
/// The list of all functions we want to test.
let FunctionList : (string * (float -> float) * (float -> float)) [] =
[| ("Cosine", cos, System.Math.Cos);
("Sine", sin, System.Math.Sin);
("Tangent", tan, System.Math.Tan);
("Inverse Cosine", acos, System.Math.Acos);
("Inverse Sine", asin, System.Math.Asin);
("Inverse Tangent", atan, System.Math.Atan);
("Hyperbolic Cosine", cosh, System.Math.Cosh);
("Hyperbolic Sine", sinh, System.Math.Sinh);
("Hyperbolic Tangent", tanh, System.Math.Tanh);
("Abs", abs, System.Math.Abs);
("Exp", exp, System.Math.Exp);
("Log", log, System.Math.Log);
("Sqrt", sqrt, System.Math.Sqrt);
("Error Function", SpecialFunctions.Erf, SpecialFunctions.Erf);
("Error Function Complement", SpecialFunctions.Erfc, SpecialFunctions.Erfc);
("Inverse Error Function", SpecialFunctions.ErfInv, SpecialFunctions.ErfInv);
("Inverse Error Function Complement", SpecialFunctions.ErfcInv, SpecialFunctions.ErfcInv) |]
/// A vector with random entries.
let w =
let rnd = new Random.MersenneTwister()
(new DenseVector(Array.init N (fun _ -> rnd.NextDouble() * 10.0))) :> Vector
/// A stopwatch to time the execution.
let sw = new System.Diagnostics.Stopwatch()
for (name, fs, dotnet) in FunctionList do
if prettyPrint then printfn "Running %s on an %d dimensional vector for %d iterations:" name N T
else printf "%s" name
/// Perform the standard F# map function.
do
let v = w.Clone()
sw.Start()
for t in 1 .. T do Vector.mapInPlace fs v
sw.Stop()
if prettyPrint then printfn "\tVector.map (F#): %d milliseconds." sw.ElapsedMilliseconds
else printf "\t%d" sw.ElapsedMilliseconds
sw.Reset()
(*
/// Perform the Apply.Map function.
do
let v = w.Clone()
sw.Start()
for t in 1 .. T do v.Map(fun x -> dotnet x)
sw.Stop()
if prettyPrint then printfn "\tApply.Map (MKL): %d milliseconds." sw.ElapsedMilliseconds
else printf "\t%d" sw.ElapsedMilliseconds
sw.Reset()*)
printfn ""

30
src/FSharpExamples/DenseVector.fs

@ -1,4 +1,32 @@
open MathNet.Numerics.FSharp
// <copyright file="DenseVector.fs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
open MathNet.Numerics.FSharp
open MathNet.Numerics.LinearAlgebra
// Create a new 100 dimensional dense vector.

1
src/FSharpExamples/FSharpExamples.fsproj

@ -51,6 +51,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="DenseVector.fs" />
<Compile Include="Apply.fs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\FSharp\1.0\Microsoft.FSharp.Targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

1
src/Numerics/Numerics.csproj

@ -121,6 +121,7 @@
<Compile Include="SpecialFunctions\Gamma.cs" />
<Compile Include="SpecialFunctions\Stability.cs" />
<Compile Include="Statistics\DescriptiveStatistics.cs" />
<Compile Include="Statistics\Histogram.cs" />
<Compile Include="Statistics\Statistics.cs" />
<Compile Include="Threading\AggregateException.cs" />
<Compile Include="Threading\TaskOfT.cs" />

22
src/Numerics/Properties/Resources.Designer.cs

@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.3074
// Runtime Version:2.0.50727.4016
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -79,7 +79,7 @@ namespace MathNet.Numerics.Properties {
}
/// <summary>
/// Looks up a localized string similar to The histogram does not contains the value {0}..
/// Looks up a localized string similar to The histogram does not contains the value..
/// </summary>
internal static string ArgumentHistogramContainsNot {
get {
@ -114,6 +114,15 @@ namespace MathNet.Numerics.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to han the given upper bound..
/// </summary>
internal static string ArgumentLowerBoundLargerThanUpperBound {
get {
return ResourceManager.GetString("ArgumentLowerBoundLargerThanUpperBound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The matrix indices must not be out of range of the given matrix..
/// </summary>
@ -492,6 +501,15 @@ namespace MathNet.Numerics.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to The two arguments can&apos;t be compared (maybe they are part of a partial ordering?).
/// </summary>
internal static string PartialOrderException {
get {
return ResourceManager.GetString("PartialOrderException", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This special case is not supported yet (but is planned)..
/// </summary>

8
src/Numerics/Properties/Resources.resx

@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentHistogramContainsNot" xml:space="preserve">
<value>The histogram does not contains the value {0}.</value>
<value>The histogram does not contains the value.</value>
</data>
<data name="ArgumentInIntervalXYInclusive" xml:space="preserve">
<value>Value is expected to be between {0} and {1} (including {0} and {1}).</value>
@ -267,4 +267,10 @@
<data name="ArgumentMinValueGreaterThanMaxValue" xml:space="preserve">
<value>In the specified range, the minimum is greater than maximum.</value>
</data>
<data name="ArgumentLowerBoundLargerThanUpperBound" xml:space="preserve">
<value>han the given upper bound.</value>
</data>
<data name="PartialOrderException" xml:space="preserve">
<value>The two arguments can't be compared (maybe they are part of a partial ordering?)</value>
</data>
</root>

455
src/Numerics/Statistics/Histogram.cs

@ -0,0 +1,455 @@
// <copyright file="Histogram.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.Statistics
{
using System;
using System.Text;
using System.Collections.Generic;
using Properties;
/// <summary>
/// A <see cref="Histogram"/> consists of a series of <see cref="Bucket"/>s,
/// each representing a region limited by a lower bound (inclusive) and an upper bound (exclusive).
/// </summary>
[Serializable]
public class Bucket : IComparable<Bucket>
{
/// <summary>
/// This <c>IComparer</c> performs comparisons between a point and a bucket.
/// </summary>
private sealed class PointComparer : IComparer<Bucket>
{
/// <summary>
/// Compares a point and a bucket. The point will be encapsulated in a bucket with width 0.
/// </summary>
/// <param name="bkt1">The first bucket to compare.</param>
/// <param name="bkt2">The second bucket to compare.</param>
/// <returns>-1 when the point is less than this bucket, 0 when it is in this bucket and 1 otherwise.</returns>
public int Compare(Bucket bkt1, Bucket bkt2)
{
if (bkt2.Width == 0.0)
{
return -bkt1.Contains(bkt2.LowerBound);
}
else
{
return -bkt2.Contains(bkt1.LowerBound);
}
}
}
static PointComparer pointComparer = new PointComparer();
/// <summary>
/// Lower Bound of the Bucket.
/// </summary>
public double LowerBound { get; set; }
/// <summary>
/// Upper Bound of the Bucket.
/// </summary>
public double UpperBound { get; set; }
/// <summary>
/// The number of datapoints in the bucket.
/// </summary>
public double Count { get; set; }
/// <summary>
/// Initializes a new instance of the Bucket class.
/// </summary>
public Bucket(double lowerBound, double upperBound) : this(lowerBound, upperBound, 0.0)
{
}
/// <summary>
/// Initializes a new instance of the Bucket class.
/// </summary>
public Bucket(double lowerBound, double upperBound, double count)
{
if (lowerBound > upperBound)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentLowerBoundLargerThanUpperBound);
}
if (count < 0.0)
{
throw new ArgumentOutOfRangeException(Resources.ArgumentMustBePositive);
}
LowerBound = lowerBound;
UpperBound = upperBound;
Count = count;
}
/// <summary>
/// Width of the Bucket.
/// </summary>
public double Width
{
get { return UpperBound - LowerBound; }
}
/// <summary>
/// Default comparer.
/// </summary>
public static IComparer<Bucket> DefaultPointComparer
{
get { return pointComparer; }
}
/// <summary>
/// This method check whether a point is contained within this bucket.
/// </summary>
/// <param name="x">The point to check.</param>
/// <returns>0 if the point falls within the bucket boundaries; -1 if the point is
/// smaller than the bucket, +1 if the point is larger than the bucket.</returns>
public int Contains(double x)
{
if (LowerBound <= x)
{
if (UpperBound > x)
{
return 0;
}
return 1;
}
return -1;
}
/// <summary>
/// Comparison of two disjoint buckets.
/// </summary>
public int CompareTo(Bucket bucket)
{
if(this.UpperBound > bucket.LowerBound && this.LowerBound < bucket.LowerBound)
{
throw new ArgumentException(Resources.PartialOrderException);
}
if (Precision.AlmostEqual(this.UpperBound, bucket.UpperBound)
&& Precision.AlmostEqual(this.LowerBound, bucket.LowerBound))
{
return 0;
}
if (bucket.UpperBound <= this.LowerBound)
{
return 1;
}
return -1;
}
/// <summary>
/// Checks whether two Buckets are equal; this method tolerates a difference in lowerbound, upperbound
/// and count given by <seealso cref="Precsion.AlmostEqual"/>.
/// </summary>
public override bool Equals(object obj)
{
if (!(obj is Bucket))
{
return false;
}
Bucket b = (Bucket) obj;
return Precision.AlmostEqual(this.LowerBound, b.LowerBound)
&& Precision.AlmostEqual(this.UpperBound, b.UpperBound)
&& Precision.AlmostEqual(this.Count, b.Count);
}
/// <summary>
/// Provides a hash code for this bucket.
/// </summary>
public override int GetHashCode()
{
return LowerBound.GetHashCode() ^ UpperBound.GetHashCode() ^ Count.GetHashCode();
}
/// <summary>
/// Formats a human-readable string for this bucket.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "[" + this.LowerBound + ";" + this.UpperBound + "]";
}
}
/// <summary>
/// A class which computes histograms of data.
/// </summary>
[Serializable]
public class Histogram
{
/// <summary>
/// Contains all the <c>Bucket</c>s of the <c>Histogram</c>.
/// </summary>
List<Bucket> buckets;
/// <summary>
/// Indicates whether the elements of <c>buckets</c> are currently sorted.
/// </summary>
bool areBucketsSorted;
/// <summary>
/// Initializes a new instance of the Histogram class.
/// </summary>
public Histogram()
{
buckets = new List<Bucket>();
areBucketsSorted = true;
}
/// <summary>
/// Constructs a Histogram with a specific number of equally sized buckets. The upper and lower bound of the histogram
/// will be set to the smallest and largest datapoint.
/// </summary>
/// <param name="data">The datasequence to build a histogram on.</param>
/// <param name="nbuckets">The number of buckets to use.</param>
public Histogram(IEnumerable<double> data, int nbuckets)
: this()
{
if (nbuckets < 1)
{
throw new ArgumentOutOfRangeException("The number of bins in a histogram should be at least 1.");
}
double lower = data.Minimum();
double upper = data.Maximum().Increment();
double width = (upper - lower) / nbuckets;
// Add buckets for each bin.
for (int n = 0; n < nbuckets; n++)
{
AddBucket(new Bucket(lower + n * width, lower + (n + 1) * width));
}
AddData(data);
}
/// <summary>
/// Constructs a Histogram with a specific number of equally sized buckets.
/// </summary>
/// <param name="data">The datasequence to build a histogram on.</param>
/// <param name="nbuckets">The number of buckets to use.</param>
/// <param name="lower">The histogram lower bound.</param>
/// <param name="upper">The histogram upper bound.</param>
public Histogram(IEnumerable<double> data, int nbuckets, double lower, double upper)
: this()
{
if (lower > upper)
{
throw new ArgumentOutOfRangeException("The histogram lowerbound must be smaller than the upper bound.");
}
if (nbuckets < 1)
{
throw new ArgumentOutOfRangeException("The number of bins in a histogram should be at least 1.");
}
double width = (upper - lower) / nbuckets;
// Add buckets for each bin.
for (int n = 0; n < nbuckets; n++)
{
AddBucket(new Bucket(lower + n * width, lower + (n + 1) * width));
}
AddData(data);
}
/// <summary>
/// Add one data point to the histogram. If the datapoint falls outside the range of the histogram,
/// the lowerbound or upperbound will automatically adapt.
/// </summary>
/// <param name="d">The datapoint which we want to add.</param>
public void AddData(double d)
{
if (d < this.LowerBound)
{
this[0].LowerBound = d;
this[0].Count++;
}
else if (d > this.UpperBound)
{
this[BucketCount - 1].UpperBound = d;
this[BucketCount - 1].Count++;
}
else
{
GetBucketOf(d).Count++;
}
}
/// <summary>
/// Add a sequence of data point to the histogram. If the datapoint falls outside the range of the histogram,
/// the lowerbound or upperbound will automatically adapt.
/// </summary>
/// <param name="data">The sequence of datapoints which we want to add.</param>
public void AddData(IEnumerable<double> data)
{
foreach (double d in data)
{
AddData(d);
}
}
/// <summary>
/// Adds a <c>Bucket</c> to the <c>Histogram</c>.
/// </summary>
public void AddBucket(Bucket bucket)
{
buckets.Add(bucket);
areBucketsSorted = false;
}
/// <summary>
/// Sort the buckets if needed.
/// </summary>
private void LazySort()
{
if (!areBucketsSorted)
{
buckets.Sort();
areBucketsSorted = true;
}
}
/// <summary>
/// Returns the <c>Bucket</c> that contains the value <c>v</c>.
/// </summary>
/// <param name="v">The point to search the bucket for.</param>
/// <returns>The bucket containing the point.</returns>
public Bucket GetBucketOf(double v)
{
return buckets[GetBucketIndexOf(v)];
}
/// <summary>
/// Returns the index in the <c>Histogram</c> of the <c>Bucket</c>
/// that contains the value <c>v</c>.
/// </summary>
/// <param name="v">The point to search the bucket index for.</param>
/// <returns>The index of the bucket containing the point.</returns>
public int GetBucketIndexOf(double v)
{
// Sort if needed.
LazySort();
// Binary search for the bucket index.
int index = buckets.BinarySearch(new Bucket(v,v), Bucket.DefaultPointComparer);
if(index < 0)
{
throw new ArgumentException(Resources.ArgumentHistogramContainsNot);
}
return index;
}
/// <summary>
/// Returns the lower bound of the histogram.
/// </summary>
public double LowerBound
{
get
{
LazySort();
return buckets[0].LowerBound;
}
}
/// <summary>
/// Returns the upper bound of the histogram.
/// </summary>
public double UpperBound
{
get
{
LazySort();
return buckets[buckets.Count-1].UpperBound;
}
}
/// <summary>
/// Gets the <c>n</c>'th bucket.
/// </summary>
/// <param name="n">The index of the bucket to be returned.</param>
/// <returns>The <c>n</c>'th bucket.</returns>
public Bucket this[int n]
{
get
{
LazySort();
return buckets[n];
}
}
/// <summary>
/// Gets the number of buckets.
/// </summary>
public int BucketCount
{
get { return buckets.Count; }
}
/// <summary>
/// Gets the total number of datapoints in the histogram.
/// </summary>
public double DataCount
{
get
{
double totalCount = 0;
for(int i = 0; i < this.BucketCount; i++)
{
totalCount += this[i].Count;
}
return totalCount;
}
}
/// <summary>
/// Prints the buckets contained in the <see cref="Histogram"/>.
/// </summary>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach(Bucket b in buckets)
{
sb.Append(b.ToString());
}
return sb.ToString();
}
}
}

250
src/UnitTests/StatisticsTests/HistogramTests.cs

@ -0,0 +1,250 @@
// <copyright file="HistogramTests.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://mathnet.opensourcedotnet.info
//
// Copyright (c) 2009 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
namespace MathNet.Numerics.UnitTests.StatisticsTests
{
using System;
using System.Collections.Generic;
using System.Text;
using MbUnit.Framework;
using MathNet.Numerics.Statistics;
[TestFixture]
public class HistogramTests
{
#region BucketTests
[Test]
public void CanCreateEmptyBucket()
{
var b = new Bucket(0.0, 1.0);
}
[Test]
public void CanCreateFilledBucket()
{
var b = new Bucket(0.0, 1.0, 10.0);
}
[Test]
[ExpectedArgumentOutOfRangeException]
public void EmptyBucketWithBadBoundsFails()
{
var b = new Bucket(1.0, 0.5);
}
[Test]
[ExpectedArgumentOutOfRangeException]
public void EmptyBucketWithBadCountFails()
{
var b = new Bucket(1.0, 0.5, -1.0);
}
[Test]
public void CanGetBucketWidth()
{
var b = new Bucket(0.0, 1.0, 10.0);
Assert.AreEqual(1.0, b.Width);
}
[Test]
public void CanGetBucketCount()
{
var b = new Bucket(0.0, 1.0, 10.0);
Assert.AreEqual(10.0, b.Count);
}
[Test]
public void CanGetBucketLowerBound()
{
var b = new Bucket(0.0, 1.0, 10.0);
Assert.AreEqual(0.0, b.LowerBound);
}
[Test]
public void CanGetBucketUpperBound()
{
var b = new Bucket(0.0, 1.0, 10.0);
Assert.AreEqual(1.0, b.UpperBound);
}
[Test]
[Row(1.0, 0)]
[Row(2.0, 1)]
[Row(-1.0, -1)]
public void ValidateContains(double x, int r)
{
var b = new Bucket(0.0, 1.5, 10.0);
Assert.AreEqual(r, b.Contains(x));
}
#endregion
#region
[Test]
public void CanCreateEmptyHistogram()
{
var h = new Histogram();
}
[Test]
public void CanAddBucket()
{
var h = new Histogram();
h.AddBucket(new Bucket(0.0, 1.0));
}
[Test]
[Row(0.0, 0)]
[Row(0.5, 0)]
[Row(1.0, 1)]
[Row(10.0, 3)]
[Row(10000.0, 4)]
public void CanGetBucketIndexOf(double x, double i)
{
var h = new Histogram();
h.AddBucket(new Bucket(0.0, 1.0));
h.AddBucket(new Bucket(1.0, 2.0));
h.AddBucket(new Bucket(2.0, 3.0));
h.AddBucket(new Bucket(3.0, 20.0));
h.AddBucket(new Bucket(20.0, Double.PositiveInfinity));
Assert.AreEqual(i, h.GetBucketIndexOf(x));
}
[Test]
public void CanGetBucketOf()
{
var h = new Histogram();
var b = new Bucket(0.0, 1.0);
h.AddBucket(b);
h.AddBucket(new Bucket(1.0, 2.0));
h.AddBucket(new Bucket(2.0, 3.0));
h.AddBucket(new Bucket(3.0, 20.0));
h.AddBucket(new Bucket(20.0, Double.PositiveInfinity));
Assert.AreEqual(b, h.GetBucketOf(0.1));
}
[Test]
[MultipleAsserts]
public void ValidateItem()
{
var h = new Histogram();
var b = new Bucket(0.0, 1.0);
var c = new Bucket(3.0, 20.0);
h.AddBucket(b);
h.AddBucket(c);
h.AddBucket(new Bucket(1.0, 2.0));
h.AddBucket(new Bucket(2.0, 3.0));
h.AddBucket(new Bucket(20.0, Double.PositiveInfinity));
Assert.AreEqual(b, h[0]);
Assert.AreEqual(c, h[3]);
}
[Test]
public void CanGetBucketCountInHistogram()
{
var h = new Histogram();
h.AddBucket(new Bucket(0.0, 1.0));
h.AddBucket(new Bucket(1.0, 2.0));
h.AddBucket(new Bucket(2.0, 3.0));
h.AddBucket(new Bucket(3.0, 20.0));
h.AddBucket(new Bucket(20.0, Double.PositiveInfinity));
Assert.AreEqual(5, h.BucketCount);
}
[Test]
public void CanGetTotalCount()
{
var h = new Histogram();
h.AddBucket(new Bucket(0.0, 1.0, 1));
h.AddBucket(new Bucket(1.0, 2.0, 1));
h.AddBucket(new Bucket(2.0, 3.0, 1));
h.AddBucket(new Bucket(3.0, 20.0, 1));
h.AddBucket(new Bucket(20.0, Double.PositiveInfinity, 1));
Assert.AreEqual(5, h.DataCount);
}
[Test]
public void CanCreateEqualSpacedHistogram()
{
var h = new Histogram(new double[] { 1.0, 5.0, 10.0 }, 2);
}
[Test]
[ExpectedArgumentException]
public void FailCreateEqualSpacedHistogramWithNoData()
{
var h = new Histogram(new List<double>(), 10);
}
[Test]
public void CanCreateEqualSpacedHistogramWithGivenLowerAndUpperBound()
{
var h = new Histogram(new double[] { 1.0, 5.0, 10.0 }, 2, 0.0, 20.0);
}
[Test]
public void CanAddDataSingle()
{
var h = new Histogram(new double[] { 1.0, 5.0, 10.0 }, 2);
h.AddData(7.0);
Assert.AreEqual(2, h[1].Count);
}
[Test]
public void CanAddDataList()
{
var h = new Histogram(new double[] { 1.0, 5.0, 10.0 }, 2);
h.AddData(new double[] { 7.0, 8.0} );
Assert.AreEqual(3, h[1].Count);
}
[Test]
public void AddDataIncreasesUpperBound()
{
var h = new Histogram(new double[] { 1.0, 5.0, 10.0 }, 2);
h.AddData(20.0);
Assert.AreEqual(2, h[1].Count);
}
[Test]
public void AddDataDecreasesLowerBound()
{
var h = new Histogram(new double[] { 1.0, 5.0, 10.0 }, 2);
h.AddData(0.0);
Assert.AreEqual(3, h[0].Count);
}
#endregion
}
}

1
src/UnitTests/UnitTests.csproj

@ -108,6 +108,7 @@
<Compile Include="SpecialFunctionsTests\ErfTests.cs" />
<Compile Include="SpecialFunctionsTests\FactorialTest.cs" />
<Compile Include="SpecialFunctionsTests\SpecialFunctionsTests.cs" />
<Compile Include="StatisticsTests\HistogramTests.cs" />
<Compile Include="StatisticsTests\DescriptiveStatisticsTests.cs" />
<Compile Include="StatisticsTests\StatisticsTests.cs" />
<Compile Include="StatisticsTests\StatTestData.cs" />

Loading…
Cancel
Save