From 37cc04d9dacbb3c261d72719b67f0192c23daf31 Mon Sep 17 00:00:00 2001 From: Andrey Akinshin Date: Fri, 8 Mar 2024 21:30:07 +0100 Subject: [PATCH] Introduce EffecticeShift --- .../Perfolizer/Horology/Frequency.cs | 25 +++++++++-------- .../SimpleEquivalenceTest.cs | 4 +-- .../Perfolizer/Metrology/Threshold.cs | 27 ++++++++++--------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Perfolizer/Perfolizer/Horology/Frequency.cs b/src/Perfolizer/Perfolizer/Horology/Frequency.cs index 4f59640f..479b32fb 100644 --- a/src/Perfolizer/Perfolizer/Horology/Frequency.cs +++ b/src/Perfolizer/Perfolizer/Horology/Frequency.cs @@ -15,11 +15,9 @@ public readonly struct Frequency(double hertz) [PublicAPI] public double Hertz { get; } = hertz; - [PublicAPI] public Frequency(double value, FrequencyUnit unit) : this(value * unit.BaseUnits) - { - } + [PublicAPI] public Frequency(double value, FrequencyUnit unit) : this(value * unit.BaseUnits) { } - [PublicAPI] public static readonly Frequency Zero = new(0); + [PublicAPI] public static readonly Frequency Zero = new (0); [PublicAPI] public static readonly Frequency Hz = FrequencyUnit.Hz.ToFrequency(); [PublicAPI] public static readonly Frequency KHz = FrequencyUnit.KHz.ToFrequency(); [PublicAPI] public static readonly Frequency MHz = FrequencyUnit.MHz.ToFrequency(); @@ -37,16 +35,16 @@ [PublicAPI] public Frequency(double value, FrequencyUnit unit) : this(value * un [PublicAPI] public static Frequency FromMHz(double value) => MHz * value; [PublicAPI] public static Frequency FromGHz(double value) => GHz * value; - [PublicAPI] public static implicit operator Frequency(double value) => new(value); + [PublicAPI] public static implicit operator Frequency(double value) => new (value); [PublicAPI] public static implicit operator double(Frequency property) => property.Hertz; [PublicAPI] public static double operator /(Frequency a, Frequency b) => 1.0 * a.Hertz / b.Hertz; - [PublicAPI] public static Frequency operator /(Frequency a, double k) => new(a.Hertz / k); - [PublicAPI] public static Frequency operator /(Frequency a, int k) => new(a.Hertz / k); - [PublicAPI] public static Frequency operator *(Frequency a, double k) => new(a.Hertz * k); - [PublicAPI] public static Frequency operator *(Frequency a, int k) => new(a.Hertz * k); - [PublicAPI] public static Frequency operator *(double k, Frequency a) => new(a.Hertz * k); - [PublicAPI] public static Frequency operator *(int k, Frequency a) => new(a.Hertz * k); + [PublicAPI] public static Frequency operator /(Frequency a, double k) => new (a.Hertz / k); + [PublicAPI] public static Frequency operator /(Frequency a, int k) => new (a.Hertz / k); + [PublicAPI] public static Frequency operator *(Frequency a, double k) => new (a.Hertz * k); + [PublicAPI] public static Frequency operator *(Frequency a, int k) => new (a.Hertz * k); + [PublicAPI] public static Frequency operator *(double k, Frequency a) => new (a.Hertz * k); + [PublicAPI] public static Frequency operator *(int k, Frequency a) => new (a.Hertz * k); [PublicAPI] public static bool operator <(Frequency a, Frequency b) => a.Hertz < b.Hertz; [PublicAPI] public static bool operator >(Frequency a, Frequency b) => a.Hertz > b.Hertz; [PublicAPI] public static bool operator <=(Frequency a, Frequency b) => a.Hertz <= b.Hertz; @@ -101,12 +99,13 @@ public static bool TryParseGHz([NotNullWhen(true)] string? s, NumberStyles numbe IFormatProvider formatProvider, out Frequency freq) => TryParse(s, FrequencyUnit.GHz, numberStyle, formatProvider, out freq); - public MeasurementUnit Unit => FrequencyUnit.Hz; + // Explicit implementation allows keeping backward compatibility with the current serialization format of BenchmarkDotNet + MeasurementUnit IWithUnits.Unit => FrequencyUnit.Hz; public double GetShift(Sample sample) { if (sample.Unit is not FrequencyUnit frequencyUnit) - throw new InvalidMeasurementUnitExceptions(Unit, sample.Unit); + throw new InvalidMeasurementUnitExceptions(FrequencyUnit.Hz, sample.Unit); return FrequencyUnit.Convert(Hertz, FrequencyUnit.Hz, frequencyUnit); } diff --git a/src/Perfolizer/Perfolizer/Mathematics/SignificanceTesting/SimpleEquivalenceTest.cs b/src/Perfolizer/Perfolizer/Mathematics/SignificanceTesting/SimpleEquivalenceTest.cs index a49835a2..05003bd4 100644 --- a/src/Perfolizer/Perfolizer/Mathematics/SignificanceTesting/SimpleEquivalenceTest.cs +++ b/src/Perfolizer/Perfolizer/Mathematics/SignificanceTesting/SimpleEquivalenceTest.cs @@ -11,10 +11,10 @@ public class SimpleEquivalenceTest(ISignificanceTwoSampleTest oneSidedTest) : IE public ComparisonResult Perform(Sample x, Sample y, Threshold threshold, SignificanceLevel alpha) { var deltas = DeltasEstimator.HodgesLehmannShamos.Deltas(x, y); - double thresholdShift = Max(threshold.GetMaxShift(x), threshold.GetMaxShift(y)); + double thresholdShift = Max(threshold.EffectiveShift(x), threshold.EffectiveShift(y)); // Practical significance - if (deltas.Shift.Abs() > thresholdShift * 10) + if (thresholdShift > 0 && deltas.Shift.Abs() > thresholdShift * 10) return deltas.Shift > 0 ? ComparisonResult.Greater : ComparisonResult.Lesser; // Statistical significance (TOST) diff --git a/src/Perfolizer/Perfolizer/Metrology/Threshold.cs b/src/Perfolizer/Perfolizer/Metrology/Threshold.cs index a28f3336..7941c046 100644 --- a/src/Perfolizer/Perfolizer/Metrology/Threshold.cs +++ b/src/Perfolizer/Perfolizer/Metrology/Threshold.cs @@ -1,6 +1,7 @@ using System.Text; using JetBrains.Annotations; using Perfolizer.Collections; +using Perfolizer.Mathematics.GenericEstimators; namespace Perfolizer.Metrology; @@ -9,7 +10,7 @@ namespace Perfolizer.Metrology; /// public class Threshold(params ISpecificMeasurementValue[] thresholdValues) : IWithUnits, IEquatable { - public static readonly Threshold Zero = new(); + public static readonly Threshold Zero = new (); private const char Separator = '|'; @@ -36,18 +37,18 @@ public Sample ApplyMax(Sample sample) : new Sample(values, sample.Unit); } - public IEnumerable GetShifts(Sample sample) => thresholdValues - .OfType() - .Select(value => value.GetShift(sample)); - - public IEnumerable GetRatios() => thresholdValues - .OfType() - .Select(value => value.GetRatio()); - - public double GetMaxShift(Sample sample, double defaultShift = 0) => - GetShifts(sample).DefaultIfEmpty(defaultShift).Max(); - - public double GetMaxRatio(double defaultRatio = 1.0) => GetRatios().DefaultIfEmpty(defaultRatio).Max(); + public double EffectiveShift(Sample sample) + { + var basicShifts = thresholdValues + .OfType() + .Select(value => value.GetShift(sample)); + var ratioShifts = thresholdValues + .OfType() + .Select(value => value.Apply(sample)) + .WhereNotNull() + .Select(sample2 => HodgesLehmannEstimator.Instance.Shift(sample2, sample)); + return basicShifts.Concat(ratioShifts).DefaultIfEmpty(0).Max(); + } public override string ToString() => presentation; public MeasurementUnit Unit => throw new NotSupportedException("Threshold does not have a measurement unit");