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

Constructing StaticArrays with generators or ntuple-like syntax #97

Open
dpsanders opened this issue Jan 26, 2017 · 8 comments
Open

Constructing StaticArrays with generators or ntuple-like syntax #97

dpsanders opened this issue Jan 26, 2017 · 8 comments
Labels
design speculative design related issue feature features and feature requests up for grabs Implement me, I'm yours!

Comments

@dpsanders
Copy link
Contributor

The following presumably creates a temporary:

julia> SVector(ntuple(i->i^2, 3))
3-element StaticArrays.SVector{3,Int64}:
 1
 4
 9

It would be great to be able to do

julia> SVector(i->i^2, 3)
3-element StaticArrays.SVector{3,Int64}:
 1
 4
 9

without creating the tuple temporary.

@SimonDanisch
Copy link
Member

You won't be able to make it much better than this, since the innermost constructor of SVector will accept a tuple.
However you can do this: ntuple(i->i^2, Val{3}), to speed things up a bit ;)

@KristofferC
Copy link
Contributor

The tuple "temporary" will just be eliminated in the compiler optimizations though?

@SimonDanisch
Copy link
Member

exactly!

@andyferris
Copy link
Member

Agreed. At least when I checked simple cases for this kind of stuff some time ago, @code_native showed what appeared to be optimal code (but I could be wrong, and that could have changed, and it could depend on exactly what you do and how).

That constructor seems fine, We could maybe provide a @pure version so that we don't need to write the Val around the length (the same goes for ntuple in Base, really). The package has Size trait type which is a bit like Val which could fit into here somewhere.

What I really want is SVector(i^2 for i = 1:3) (or SVector(f(i) for i = 1:N), where N is some Const value). AFAIK this will only be optimally fast if the Generator is Const in inference, which means the constructor for ranges and generators would need to be pure or effect free or have a tfunc (yuck) or something. (When I get into this stuff, this is usually where @vtjnash offers some insight about possibilities and impossibilities - any thoughts, Jameson?)

The final problem with SVector(f(i) for i = 1:N) and SVector(f, N) is when f is a closure (more precisely, a closure that captures at least one variable, or any other kind of non-constant, callable object) then not even a @pure constructor will help. The worst part isn't that the values can't be computed at compile-time; it is that the length of the SVector won't be known at compile time (one way around that for SVector(f, N) is recursive inlining and inference/constant prop, but even that won't work for SVector(f(i) for i=1:N) when f isn't constant, unless we also keep track of Constness for individual fields of immutables. This all seems rather speculative, so I don't know a good solution for any of this, except to use Val/Size for the size).

@c42f c42f added the feature features and feature requests label Jul 31, 2019
@c42f
Copy link
Member

c42f commented Jul 31, 2019

I believe the compiler has matured enough in julia-1.2 that we can finally get the generator version mentioned by @andyferris to work (see #633 (comment) and related discussion on that issue)

@c42f c42f added the up for grabs Implement me, I'm yours! label Jul 31, 2019
@c42f c42f added design speculative design related issue up for grabs Implement me, I'm yours! and removed up for grabs Implement me, I'm yours! labels Aug 1, 2019
@c42f c42f changed the title Function like ntuple for constructing StaticArrays Constructing StaticArrays with generators or ntuple-like syntax Aug 1, 2019
@tkf
Copy link
Member

tkf commented Dec 22, 2019

Alternatively, why not use statically sized range types (e.g., SOneTo) as the input to the generator? Combined with StaticNumbers.jl, I suppose you can implement SVector(f(i) for i = static(1):static(N)) or even SVector(f(i) for i = static(1:N)) without relying on the compiler optimizations.

It might be useful to try similar approach for slicing. Ref: perrutquist/StaticNumbers.jl#4

@perrutquist
Copy link

perrutquist commented Dec 31, 2019

For information: I've now implemented generators with static ranges in StaticNumbers, so the following works:

using StaticArrays, StaticNumbers
N = static(3)
SVector(i^2 for i in static(1):N)

The last statement works even if N is a regular Int, but when N is static, it is type-stable (equivalent to SVector(ntuple(i->i^2, Val(3)))).

(Edit: This was broken when N was not static. Fixed in StaticNumbers 0.2.1.)

@tkf
Copy link
Member

tkf commented Jul 8, 2020

Just as a record, something like SVector{3}(f(x) for x in xs) works as of #792. There is also an internal function sacollect that works with generic iterator with sacollect(SVector{3}, iterator). I'm hoping to introduce an API like into(SVector{N}, iterator) in Base (RFC JuliaLang/julia#36288 / PR JuliaLang/julia#36537) so that we can expose this in a coherent manner.

Note that #792 is not a full solution since the length information comes from the output container type.

oschulz pushed a commit to oschulz/StaticArrays.jl that referenced this issue Apr 4, 2023
* Expose grow_to_structarray! as a public API

* Rename: collect_to_structarray! -> _collect_to_structarray!

* Add collect_to_structarray!(dest, itr)

* Rename: collect_to_structarray! -> append!!

* Mention append!! in README
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design speculative design related issue feature features and feature requests up for grabs Implement me, I'm yours!
Projects
None yet
Development

No branches or pull requests

7 participants