-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Fix Tensor.StdDev vs TensorPrimitives.StdDev differences for Complex input #119229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+191
−7
Merged
Changes from 3 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
c5fdc22
Initial plan
Copilot 3bc92e3
Initial analysis of Tensor.StdDev vs TensorPrimitivers.StdDev differe…
Copilot a5df4e4
Fix Tensor.StdDev vs TensorPrimitives.StdDev differences for Complex …
Copilot 4585313
Address performance concerns and fix typo in Tensor.StdDev implementa…
Copilot ceaad7e
Return to SumOfSquaredMagnitudeDifferences approach and remove blank …
Copilot d8d8021
Address PR feedback: Make TestComplex throw NotImplementedException f…
Copilot 3b65f24
Remove unneeded asserts and clean up test name comments
jeffhandley 87e9ec0
Clarify absolute value requirement for SumOfSquaredMagnitudeDifferences
jeffhandley 58e1272
Rearrange TestComplex members for clarity
jeffhandley 17a8b82
Remove extra blank line
jeffhandley 007d7b7
Remove unused theory parameters
jeffhandley ce358ad
Rename SumOfSquaredMagnitudeDifferences to SumOfSquaredAbsoluteDiffer…
jeffhandley ff64cf9
Merge branch 'main' into copilot/fix-116133
jeffhandley 670255a
Include absolute value comment on both call sites
jeffhandley 9eabaf4
Merge branch 'main' into copilot/fix-116133
jeffhandley File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 |
|---|---|---|
|
|
@@ -3,6 +3,8 @@ | |
|
|
||
| using System.Buffers; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Globalization; | ||
| using System.Linq; | ||
| using System.Runtime.InteropServices; | ||
| using Xunit; | ||
|
|
@@ -1169,6 +1171,21 @@ public static void TensorStdDevTests() | |
| Assert.Equal(0f, Tensor.StdDev(upperLeft)); | ||
| } | ||
|
|
||
| [Fact] | ||
jeffhandley marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| public static void TensorStdDevComplexTests() | ||
| { | ||
| // Test case from issue: Tensor.StdDev vs TensorPrimitivers.StdDev differences for Complex input | ||
|
||
| var arr = new TestComplex[] { new(new(1, 2)), new(new(3, 4)) }; | ||
| var tensor = Tensor.Create(arr); | ||
|
|
||
| var tensorPrimitivesResult = TensorPrimitives.StdDev<TestComplex>(arr); | ||
| var tensorResult = Tensor.StdDev(tensor.AsReadOnlyTensorSpan()); | ||
|
|
||
| // Both should produce the same result | ||
| Assert.Equal(tensorPrimitivesResult.Real, tensorResult.Real, precision: 10); | ||
| Assert.Equal(tensorPrimitivesResult.Imaginary, tensorResult.Imaginary, precision: 10); | ||
| } | ||
|
|
||
jeffhandley marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| [Fact] | ||
| public static void TensorSumTests() | ||
| { | ||
|
|
@@ -3190,4 +3207,90 @@ public static void ToStringZeroDataTest() | |
| Assert.Equal(expected, tensor.ToString([2, 0, 2])); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Test complex number type that implements IRootFunctions for testing StdDev consistency between | ||
| /// TensorPrimitives.StdDev and Tensor.StdDev | ||
| /// </summary> | ||
| public readonly struct TestComplex(Complex value) : IRootFunctions<TestComplex>, IEquatable<TestComplex> | ||
jeffhandley marked this conversation as resolved.
Show resolved
Hide resolved
jeffhandley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| private readonly Complex _value = value; | ||
|
|
||
| public double Real => _value.Real; | ||
| public double Imaginary => _value.Imaginary; | ||
|
|
||
| public static TestComplex operator +(TestComplex left, TestComplex right) => new(left._value + right._value); | ||
| public static TestComplex operator *(TestComplex left, TestComplex right) => new(left._value * right._value); | ||
| public static TestComplex operator /(TestComplex left, TestComplex right) => new(left._value / right._value); | ||
| public static TestComplex operator -(TestComplex left, TestComplex right) => new(left._value - right._value); | ||
| public static TestComplex Sqrt(TestComplex x) => new(Complex.Sqrt(x._value)); | ||
| public static TestComplex Abs(TestComplex value) => new(new(Complex.Abs(value._value), 0)); | ||
| public static TestComplex AdditiveIdentity => new(Complex.Zero); | ||
| public static TestComplex CreateChecked<TOther>(TOther value) where TOther : INumberBase<TOther> => new(Complex.CreateChecked(value)); | ||
|
|
||
| // Override Object methods | ||
| public override bool Equals(object? obj) => obj is TestComplex other && Equals(other); | ||
| public override int GetHashCode() => _value.GetHashCode(); | ||
| public override string ToString() => _value.ToString(); | ||
|
|
||
| // IEquatable<TestComplex> | ||
| public bool Equals(TestComplex other) => _value.Equals(other._value); | ||
|
|
||
| // Operators | ||
| public static bool operator ==(TestComplex left, TestComplex right) => left.Equals(right); | ||
| public static bool operator !=(TestComplex left, TestComplex right) => !left.Equals(right); | ||
|
|
||
| // Required interface implementations - minimal stubs | ||
| public string ToString(string? format, IFormatProvider? formatProvider) => _value.ToString(format, formatProvider); | ||
| public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) => _value.TryFormat(destination, out charsWritten, format, provider); | ||
| public static TestComplex Parse(string s, IFormatProvider? provider) => new(Complex.Parse(s, provider)); | ||
| public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out TestComplex result) { var success = Complex.TryParse(s, provider, out var c); result = new(c); return success; } | ||
| public static TestComplex Parse(ReadOnlySpan<char> s, IFormatProvider? provider) => new(Complex.Parse(s, provider)); | ||
| public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out TestComplex result) { var success = Complex.TryParse(s, provider, out var c); result = new(c); return success; } | ||
| public static TestComplex operator --(TestComplex value) => new(value._value - Complex.One); | ||
| public static TestComplex operator ++(TestComplex value) => new(value._value + Complex.One); | ||
| public static TestComplex MultiplicativeIdentity => new(Complex.One); | ||
| public static TestComplex operator -(TestComplex value) => new(-value._value); | ||
| public static TestComplex operator +(TestComplex value) => new(value._value); | ||
| public static bool IsCanonical(TestComplex value) => true; | ||
| public static bool IsComplexNumber(TestComplex value) => true; | ||
| public static bool IsEvenInteger(TestComplex value) => false; | ||
| public static bool IsFinite(TestComplex value) => Complex.IsFinite(value._value); | ||
| public static bool IsImaginaryNumber(TestComplex value) => value._value.Real == 0 && value._value.Imaginary != 0; | ||
| public static bool IsInfinity(TestComplex value) => Complex.IsInfinity(value._value); | ||
| public static bool IsInteger(TestComplex value) => false; | ||
| public static bool IsNaN(TestComplex value) => Complex.IsNaN(value._value); | ||
| public static bool IsNegative(TestComplex value) => false; | ||
| public static bool IsNegativeInfinity(TestComplex value) => false; | ||
| public static bool IsNormal(TestComplex value) => true; | ||
| public static bool IsOddInteger(TestComplex value) => false; | ||
| public static bool IsPositive(TestComplex value) => false; | ||
| public static bool IsPositiveInfinity(TestComplex value) => false; | ||
| public static bool IsRealNumber(TestComplex value) => value._value.Imaginary == 0; | ||
| public static bool IsSubnormal(TestComplex value) => false; | ||
| public static bool IsZero(TestComplex value) => value._value == Complex.Zero; | ||
| public static TestComplex MaxMagnitude(TestComplex x, TestComplex y) => Complex.Abs(x._value) >= Complex.Abs(y._value) ? x : y; | ||
| public static TestComplex MaxMagnitudeNumber(TestComplex x, TestComplex y) => MaxMagnitude(x, y); | ||
| public static TestComplex MinMagnitude(TestComplex x, TestComplex y) => Complex.Abs(x._value) <= Complex.Abs(y._value) ? x : y; | ||
| public static TestComplex MinMagnitudeNumber(TestComplex x, TestComplex y) => MinMagnitude(x, y); | ||
| public static TestComplex Parse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider) => new(Complex.Parse(s, style, provider)); | ||
| public static TestComplex Parse(string s, NumberStyles style, IFormatProvider? provider) => new(Complex.Parse(s, style, provider)); | ||
| public static bool TryConvertFromSaturating<TOther>(TOther value, out TestComplex result) where TOther : INumberBase<TOther> { result = default; return false; } | ||
| public static bool TryConvertFromTruncating<TOther>(TOther value, out TestComplex result) where TOther : INumberBase<TOther> { result = default; return false; } | ||
| public static bool TryConvertFromChecked<TOther>(TOther value, out TestComplex result) where TOther : INumberBase<TOther> { result = default; return false; } | ||
| public static bool TryConvertToChecked<TOther>(TestComplex value, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase<TOther> { result = default; return false; } | ||
| public static bool TryConvertToSaturating<TOther>(TestComplex value, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase<TOther> { result = default; return false; } | ||
| public static bool TryConvertToTruncating<TOther>(TestComplex value, [MaybeNullWhen(false)] out TOther result) where TOther : INumberBase<TOther> { result = default; return false; } | ||
| public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out TestComplex result) { var success = Complex.TryParse(s, style, provider, out var c); result = new(c); return success; } | ||
| public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out TestComplex result) { var success = Complex.TryParse(s, style, provider, out var c); result = new(c); return success; } | ||
| public static TestComplex One => new(Complex.One); | ||
| public static int Radix => 2; | ||
| public static TestComplex Zero => new(Complex.Zero); | ||
| public static TestComplex E => new(new(Math.E, 0)); | ||
| public static TestComplex Pi => new(new(Math.PI, 0)); | ||
| public static TestComplex Tau => new(new(Math.Tau, 0)); | ||
| public static TestComplex Cbrt(TestComplex x) => new(Complex.Pow(x._value, 1.0/3.0)); | ||
| public static TestComplex Hypot(TestComplex x, TestComplex y) => new(new(Complex.Abs(Complex.Sqrt(x._value * x._value + y._value * y._value)), 0)); | ||
| public static TestComplex RootN(TestComplex x, int n) => new(Complex.Pow(x._value, 1.0/n)); | ||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.