Skip to content
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

Better support for complex numbers #1043

Closed
5 tasks done
Happypig375 opened this issue Jul 8, 2021 · 6 comments
Closed
5 tasks done

Better support for complex numbers #1043

Happypig375 opened this issue Jul 8, 2021 · 6 comments

Comments

@Happypig375
Copy link
Contributor

Better support for complex numbers

F# has numeric literal suffixes for almost all numeric types, including the 8 types of fixed-size integers, 2 types of native integers, 1 type of arbitrary-sized integer, and 3 types of floating-point numbers. However, the cousin of bigint in System.Numerics, Complex doesn’t get much love.

I propose we make this possible:

let a = 1+0i
let b = 1.2+2i
let c = sqrt(3-2.4i)

How does this work? First, FSharp.Core will define a NumericLiterali (like the existing NumericLiteralI for bigints) with a FromFloat is used (#445):

type complex = System.Numerics.Complex
/// i stands for imaginary
module NumericLiterali =
    let FromZero() = complex.Zero
    let FromOne() = complex.ImaginaryOne
    let FromInt32 (x: int32) = complex(0., float x)
    let FromInt64 (x: int64) = complex(0., float x)
    let FromFloat (x:float) = complex(0., x)

This makes the example code equivalent to

type complex = System.Numerics.Complex
let a = 1+complex.Zero
let b = 1.2+complex(0., float 2)
let c = sqrt(3-complex(0., 2.4))

Next, we apply the rule of implicit int32 -> float as added by dotnet/fsharp#10884:

type complex = System.Numerics.Complex
let a = float 1+complex.Zero
let b = 1.2+complex(0., float 2)
let c = sqrt(float 3-complex(0., 2.4))

Now we arrive at currently compilable code.

The existing way of approaching this problem in F# is to open System.Numerics and awkwardly call the constructor despite not having to do this for its cousin bigint. F# tries to compete in the data science and scripting space, but the competitors Python and Julia both have complex number literals built-in:
https://docs.python.org/3/library/cmath.html
b = 1.2 + 2j
https://docs.julialang.org/en/v1/manual/complex-and-rational-numbers/
b = 1.2 + 2im
We should be on-par with them as well.

All these operators for complex are supported fine currently:

let a = System.Numerics.Complex.One
acos a
asin a
atan a
cos a
sin a
tan a
exp a
log a
log10 a
-a
a + a
a - a
a * a
a / a
a ** a
sinh a
cosh a
tanh a
sqrt a

But these error:

abs a
LanguagePrimitives.GenericZero<System.Numerics.Complex>
LanguagePrimitives.GenericOne<System.Numerics.Complex>

For abs, since the Abs of complex returns float which is a different type from complex, this may need its own function called absc (c for complex, just like f for float32. The generic ones and zeros should be fixed as well.

For consistency with nan/nanf and infinity/infinityf, nanc and infinityc should be added as well.

Maybe conj and polar can be added as well for completeness?

Pros and Cons

The advantages of making this adjustment to F# are

  1. Conciseness
  2. Convenience
  3. Competitiveness with other data science languages
  4. Consistency with other numeric types

The disadvantages of making this adjustment to F# are that this is another thing to learn. However, these convenience features are already available for existing numeric types other than complex. Why leave this out?

Extra information

Estimated cost (XS, S, M, L, XL, XXL): S

Related suggestions:
#445 - Extend custom numeric types to support floating point literals
#849 - FS-1093 Additional type directed conversions

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I or my company would be willing to help implement and/or test this

For Readers

If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.

@charlesroddie
Copy link

@charlesroddie
Copy link

charlesroddie commented Jul 17, 2021

That's odd, works in SharpLab but not on my VS:
image
That means the current syntax is not far from the standard mathematical syntax as above (assuming you are willing to sacrifice a bit of performance with extra operations, which this suggestion does assume):

open System.Numerics
let I = Complex.ImaginaryOne // worst thing in .Net complex numbers is this illogical name
let x = 5. + 4.*I

Allowing more numeric literal types and using one for imaginary complex numbers is fine IMO.

I don't think we are going to allow 0+Complex.Zero if we don't allow 0+0.. The latter won't happen surely? Are you suggesting it is related to dotnet/fsharp#10884 ?

@Happypig375
Copy link
Contributor Author

@charlesroddie
It uses this overload added in .NET Core 3.0. https://docs.microsoft.com/en-us/dotnet/api/system.numerics.complex.add?view=net-5.0#System_Numerics_Complex_Add_System_Double_System_Numerics_Complex_

The latter won't happen surely? Are you suggesting it is related to dotnet/fsharp#10884 ?

That PR will introduce an overload resolution rule of int32 -> float64, along with int32 -> int64. Based on the wording of the RFC, I think this is enabled. This makes int32 literals act more like generic number literals.

@charlesroddie
Copy link

Based on the wording of the RFC, I think this is enabled.

Apparently it will be possible after this RFC with user-defined overloads of (+):
https://github.com/fsharp/fslang-design/blob/main/RFCs/FS-1043-extension-members-for-operators-and-srtp-constraints.md#widening-to-specific-type

@dsyme
Copy link
Collaborator

dsyme commented Apr 13, 2023

Programming with complex numbers is just super-rare in practice. I can't see us baking in support for this into the core of F# - programming with these is quite possible using helper functions and so on.

@dsyme dsyme closed this as completed Apr 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants