-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
1450813
commit 5f12a7d
Showing
4 changed files
with
198 additions
and
151 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
using System.Collections.Generic; | ||
using OSPSuite.Core.Extensions; | ||
|
||
namespace OSPSuite.Core.Maths | ||
{ | ||
public class SortedFloatArray | ||
{ | ||
private readonly IReadOnlyList<float> _sortedArray; | ||
|
||
/// <summary> | ||
/// Takes a list of floats which will be used to preform quantile operations | ||
/// </summary> | ||
/// <param name="floatArray">The list of floats used to calculate quantiles</param> | ||
/// <param name="alreadySorted">If the list is already sorted, then specify <paramref name="alreadySorted"/> as false | ||
/// If the list needs to be sorted, specify true</param> | ||
public SortedFloatArray(IReadOnlyList<float> floatArray, bool alreadySorted) | ||
{ | ||
_sortedArray = floatArray; | ||
if (!alreadySorted) | ||
_sortedArray = _sortedArray.OrderedAndPurified(); | ||
} | ||
|
||
public float Percentile(double percentile) | ||
{ | ||
return Quantile(percentile / 100); | ||
} | ||
|
||
public float Median() | ||
{ | ||
return Percentile(50); | ||
} | ||
|
||
public float Quantile(double quantile) | ||
{ | ||
int N = _sortedArray.Count; | ||
|
||
if (N == 0) | ||
return float.NaN; | ||
|
||
double n = (N - 1) * quantile + 1; | ||
|
||
if (n == 1d) | ||
return _sortedArray[0]; | ||
|
||
if (n == N) | ||
return _sortedArray[N - 1]; | ||
|
||
int k = (int)n; | ||
var d = n - k; | ||
double value = _sortedArray[k - 1] + d * (_sortedArray[k] - _sortedArray[k - 1]); | ||
return (float)value; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
tests/OSPSuite.Core.Tests/Domain/SortedFloatArraySpecs.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
using OSPSuite.BDDHelper; | ||
using OSPSuite.Core.Maths; | ||
using OSPSuite.BDDHelper.Extensions; | ||
|
||
namespace OSPSuite.Core.Domain | ||
{ | ||
public class concern_for_SortedFloatArray : ContextSpecification<SortedFloatArray> | ||
{ | ||
|
||
} | ||
|
||
public class When_calculating_the_median_of_an_unsorted_array : concern_for_SortedFloatArray | ||
{ | ||
protected override void Context() | ||
{ | ||
sut = new SortedFloatArray(new float[] { 1, 2, 7, 8, 5 }, false); | ||
} | ||
|
||
[Observation] | ||
public void should_return_the_expected_value() | ||
{ | ||
((double)sut.Median()).ShouldBeEqualTo(5); | ||
} | ||
} | ||
|
||
public class When_calculating_the_median_of_an_array : concern_for_SortedFloatArray | ||
{ | ||
private SortedFloatArray _values1; | ||
private SortedFloatArray _values2; | ||
|
||
protected override void Context() | ||
{ | ||
_values1 = new SortedFloatArray(new float[] { 1, 2, 5, 8, 7 }, true); | ||
_values2 = new SortedFloatArray(new float[] { 1, 2, 2, 6, 8, 7 }, true); | ||
} | ||
|
||
[Observation] | ||
public void should_return_the_expected_value() | ||
{ | ||
((double)_values1.Median()).ShouldBeEqualTo(5); | ||
((double)_values2.Median()).ShouldBeEqualTo(4); | ||
} | ||
} | ||
|
||
public class When_calculating_the_percentile : concern_for_SortedFloatArray | ||
{ | ||
protected override void Context() | ||
{ | ||
sut = new SortedFloatArray(new[] { 0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f }, true); | ||
} | ||
|
||
[Observation] | ||
public void should_return_the_expected_value() | ||
{ | ||
((double)sut.Percentile(50)).ShouldBeEqualTo(sut.Median(), 1e-5); | ||
} | ||
} | ||
|
||
public class When_calculating_the_percentile_with_doubled_values : concern_for_SortedFloatArray | ||
{ | ||
protected override void Context() | ||
{ | ||
sut = new SortedFloatArray(new[] { 0f, 1f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f }, true); | ||
} | ||
|
||
[Observation] | ||
public void should_return_the_expected_value() | ||
{ | ||
((double)sut.Percentile(50)).ShouldBeEqualTo(sut.Median(), 1e-5); | ||
} | ||
} | ||
|
||
public class When_calculating_the_quantile_with_doubled_values : concern_for_SortedFloatArray | ||
{ | ||
private SortedFloatArray _values; | ||
private SortedFloatArray _values2; | ||
|
||
protected override void Context() | ||
{ | ||
_values = new SortedFloatArray(new[] { 0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f }, true); | ||
_values2 = new SortedFloatArray(new[] { 2f, 3f, 3f, 4f, 5f, 6f }, true); | ||
} | ||
|
||
[Observation] | ||
public void should_return_the_expected_median() | ||
{ | ||
((double)_values.Quantile(0.5)).ShouldBeEqualTo(5f); | ||
} | ||
|
||
[Observation] | ||
public void should_calculate_Median() | ||
{ | ||
_values.Quantile(0.5).ShouldBeEqualTo(5f); | ||
} | ||
|
||
[Observation] | ||
public void should_calculate_2_5Percentile() | ||
{ | ||
_values.Quantile(0.025).ShouldBeEqualTo(0.25f); | ||
} | ||
|
||
[Observation] | ||
public void should_calculate_5Percentile() | ||
{ | ||
_values.Quantile(0.05).ShouldBeEqualTo(0.5f); | ||
} | ||
|
||
[Observation] | ||
public void should_calculate_25Percentile() | ||
{ | ||
_values.Quantile(0.25).ShouldBeEqualTo(2.5f); | ||
} | ||
|
||
[Observation] | ||
public void should_calculate_75Percentile() | ||
{ | ||
_values.Quantile(0.75).ShouldBeEqualTo(7.5f); | ||
} | ||
|
||
[Observation] | ||
public void should_calculate_Percentiles() | ||
{ | ||
_values.Quantile(0.83).ShouldBeEqualTo(8.3f); | ||
_values.Quantile(0.8).ShouldBeEqualTo(8f); | ||
|
||
_values2.Quantile(0.24).ShouldBeEqualTo(3f); | ||
_values2.Quantile(0).ShouldBeEqualTo(2f); | ||
_values2.Quantile(0.05).ShouldBeEqualTo(2.25f); | ||
_values2.Quantile(0.95).ShouldBeEqualTo(5.75f); | ||
} | ||
} | ||
|
||
public class When_calculating_the_quantile_for_an_array_with_only_one_value : concern_for_SortedFloatArray | ||
{ | ||
[Observation] | ||
public void should_return_the_expected_values() | ||
{ | ||
new SortedFloatArray(new[] { 1f }, true).Quantile(0.5).ShouldBeEqualTo(1f); | ||
new SortedFloatArray(new[] { 5f }, true).Quantile(0.5).ShouldBeEqualTo(5f); | ||
} | ||
} | ||
} |