Giter Site home page Giter Site logo

Comments (16)

bluss avatar bluss commented on August 10, 2024 2

It's more complicated than that, C's complex type needs its own handling in the C ABI and rust can't do that yet. See RFC issue here: rust-lang/rfcs/issues/793

That said, the representation is the same when it comes to accessing complex numbers in memory, so for example BLAS bindings still work with it as it is today: it's only complex by-value function parameters and return values that are not c-compatible as it is now.

Due to being usable with ffi when accessed behind a pointer, I think it would be good to mark it #[repr(C)]? but it needs a highlighted doc to explain the limitations.

from num.

harpocrates avatar harpocrates commented on August 10, 2024

Any chance of this happening? Even when numbers are passed by value, AFAIC tell most modern platforms also use this representation.

Would you need a PR?

from num.

cuviper avatar cuviper commented on August 10, 2024

I'm really hesitant to add this with such documented limitations. People are prone to ignoring that sort of thing until it blows up in their face. Maybe it could be added just for the known-good architectures with cfg_attr. Even then it's a little weird to declare repr(C) for all generic Complex<T>, when it only makes sense for f32 and f64.

Another possibility is to solve it in the hypothetical libm crate, which would present it's own ABI-compatible versions of complex types. We could then add From implementations in both directions for the Complex type here. But I wonder how common it would be to straddle these worlds -- I expect most people would either stay in pure-Rust here or use purely libm.

from num.

clamydo avatar clamydo commented on August 10, 2024

But I wonder how common it would be to straddle these worlds -- I expect most people would either stay in pure-Rust here or use purely libm.

I'd disagree. When interfacing with certain numeric centric libraries with C-ABI, interfacing with _Complex independent of libm can be necessary. For example when calling to FFTW3, it expects an array of double[2]; which is guaranteed to be represented the exactly as _Complex in memory:

505 Each complex type has the same representation and alignment requirements as an array type containing exactly two elements of the corresponding real type;

This does not involve the libm, but nonetheless uses a _Complex representation. I worked around it by defining my own complex type as a tuple struct struct Complex<T>([T; 2]);, which is represented most likely the same as [T; 2] (although AFAIK it is not guaranteed by rustc).

It would be super nice, if we could interface directly with the C _Complex from rust. But I'm not sure, if a two field struct (as in num) with #[repr(C)] meets the requirements of being aligned identically with a double[2]/_Complex in memory. Does anybody has references about this?

from num.

cuviper avatar cuviper commented on August 10, 2024

OK, if libm is too specific, then it probably belongs in libc itself. Something like c_complex_float and c_complex_double which are C-ABI compatible, and num's Complex can cheaply convert. But I'm still really hesitant to make any repr(C) promises in num itself.

from num.

hauleth avatar hauleth commented on August 10, 2024

Could anyone link the section of C99 standard that describes memory layout of _Complex? Because I think that this is implementation defined and if so interop between num_complex::Complex and _Complex would be impossible as it would be easy way to blow up everything.

from num.

clamydo avatar clamydo commented on August 10, 2024

@hauleth See my post above.
505 in http://c0x.coding-guidelines.com/6.2.5.html

from num.

hauleth avatar hauleth commented on August 10, 2024

@fkjogu ok. So now we need to be sure that our struct with #[repr(C)] will have the same memory layout as float[2] or double[2].

from num.

cuviper avatar cuviper commented on August 10, 2024

The memory layout is one thing, but the ABI for complex parameters is certainly implementation defined.

from num.

cuviper avatar cuviper commented on August 10, 2024

FWIW, it's easy to approximate this, if you want to deal with ABI on your own:

#[repr(C)]
struct c_complex_double([f64; 2]);

impl From<Complex64> for c_complex_double {
    fn from(c: Complex64) -> Self {
        c_complex_double([c.re, c.im])
    }
}

impl From<c_complex_double> for Complex64 {
    fn from(c: c_complex_double) -> Self {
        Complex64::new(c.0[0], c.0[1])
    }
}

from num.

clamydo avatar clamydo commented on August 10, 2024

@cuviper Good point. But I'm not sure, what #[repr(C)] actually means for a tuple struct. Does handle Rust tuple structs completely transparent? Is this guaranteed?

Also I'm never sure what consequences this type of copy conversation has on performance in real applications. Definitely more, than just passing a pointer, for some amount of more.

from num.

cuviper avatar cuviper commented on August 10, 2024

I don't know about guarantees, but tuple structs should be transparent as long as you don't implement something like Drop, which adds a hidden drop flag (although that should eventually go away). There's even a warning for this:

warning: implementing Drop adds hidden state to types, possibly conflicting with `#[repr(C)]`, #[warn(drop_with_repr_extern)] on by default

Besides, you can only attach #[repr(C)] to structs or enums in the first place. An array like [f64;2] is surely already C-compatible, but I'm not sure whether that is guaranteed.

As for the performance of copy conversions, I'd expect it to have negligible overhead. This is completely transparent to the optimizer, so in some cases the copies might be avoided entirely. I would avoid conversions back and forth in the loop of a math kernel though.

from num.

bluss avatar bluss commented on August 10, 2024

If it does not have #[repr(C)], then crates will need to migrate off using num's complex. It would be unsound (strictly speaking, but in practice not a problem) for numerical projects to use num's complex when integrating with complex-consuming libraries like BLAS.

from num.

cuviper avatar cuviper commented on August 10, 2024

If it does not have #[repr(C)], then crates will need to migrate off using num's complex.

I think that's overstated. It just means crates just shouldn't use num::Complex directly for FFI is all. I think we really need something in libc for this use case.

It would be unsound (strictly speaking, but in practice not a problem) for numerical projects to use num's complex when integrating with complex-consuming libraries like BLAS.

Adding #[repr(C)] still doesn't correct the parameter ABI, as you stated up front. That's my major gripe here, that this wouldn't actually be solving the whole issue to make this FFI compatible.


That said, I think I can relent. It doesn't look like #[repr(C)] shows up directly in the docs anyway, so it's only discoverable insofar as we describe it. If you want to open a PR with a cautious explanation in the documentation, I'll accept it. FFI is inherently unsafe, so folks always need to be careful, but make sure it's clear what the caveats are in this case.

from num.

bluss avatar bluss commented on August 10, 2024

Great. Using a different type for ffi would mean using a different type all the time. (Converting an ndarray of thousands of entries is not done for free, can't do that just to call a function.)

from num.

IvanUkhov avatar IvanUkhov commented on August 10, 2024

Regarding libc, I just want to link this issue to that one.

from num.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.