stillwater-sc / universal

Large collection of number systems providing custom arithmetic for mixed-precision algorithm development and optimization for AI, Machine Learning, Computer Vision, Signal Processing, CAE, EDA, control, optimization, estimation, and approximation.
MIT License
410 stars 59 forks source link

Clang is enforcing std::complex<> only accepting native floating-point types, find a solution #439

Open Ravenwater opened 2 months ago

Ravenwater commented 2 months ago

First AppleClang and now regular Clang are enforcing that std::complex<> is undefined when the template parameters are not native floating-point types.

This will kill all complex<> use cases of Universal floating-point types, of which there are many:

We need to find a solution to this problem that side-steps this std::complex<> library specification.

willwray commented 2 months ago

I'm looking around for alternatives and thinking about requirements for a custom complex class. Deciding on what customization points are wanted will help guide any design.

A std compatible scalar complex class is relatively straightforward. Then, std::complex has design flaws and limitations that can be addressed in a custom class.

Vectorization could be an important consideration. Should separate real and imag arrays be supported, as in BLAS calls? Possibly via an array specialization, complex<S[N]>? However, that raises an issue; what is the return type of subscripting a complex array type? Indexing an array returns a modifyable lvalue, by convention. This implies that a complex view type is needed to collect the separated real and imag parts. Or, simply don't support indexing.

On the other hand there's a proposal for std::simd to work with std::complex P2663 Interleaved complex values support in std::simd taking the pragmatic approach to work with 'interleaved' storage of real and imag (as per usual) despite this limiting parallelism opportunity on current hardware.

There's a complex specialization in this library by Joel Falcou https://github.com/jfalcou/kyosu done as an alias of a more generic Caley-Dickson type here https://github.com/jfalcou/kyosu/blob/main/include/kyosu/types/complex.hpp designed to work with his EVE simd library (a long time metaprogrammer the code is... very clever...)

I don't find anything useful in Boost yet. (Boost::math has some TR1-era extensions to std::complex) (Boost::units has an example units-compatible complex type).

In fact, I don't find any useful alternative third-party code yet. There's a complex class in Stan math library, but it also (ab)uses std::complex.

willwray commented 2 months ago

FYI I kicked off a discussion on cpplang slack #general channel, including a response from C++ luminary Howard Hinnant. Alfredo is a US national lab HPC coder and author of the boost-multi array library.

Alfredo: @willw for std complex to be a serious type to do high performance numerics, it would have to be trivially default constructible to begin with. For serious applications one ends up with a custom complex type or hacking around the initialization of complex elements in array containers.

howard.hinnant: std::complex was standardized in C++98 and has been largely untouched since then. Meanwhile the C++ language has changed dramatically. An interesting exercise would be to do a clean-sheet design of a complex class by people intimately familiar with both the subject matter and modern C++, and then do a diff between that result and std::complex. Maybe there is a migration path....

Alfredo @howard.hinnant I agree with the assessment and also hope for a bright future. Unfortunately, recent history is not promising. CUDA Thrust had the opportunity to make thrust complex trivially constructible and did not take it. They are designing cuda::complex (in libcudacxx) and I hope they don’t make the same mistake. https://github.com/NVIDIA/cccl/issues/1010, not sure if this more modern view is coming across.

Mikhail Kandel: wonder if there is some advantage to making it a primitive type :-)

Alfredo: in C99 it is a built-in type, e.g. float _Complex, the class std::complex could, and in some cases is, implemented in terms of it.

Ravenwater commented 2 months ago

I will start with the simpler problem of siphoning off the complex regression tests from the individual arithmetic type regression suites and collect them in their own build target, something like BUILD_COMPLEX. We can then also nicely compartmentalize the complex<> library development work.