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

Slicing static arrays? #4

Open
tkf opened this issue Dec 21, 2019 · 21 comments
Open

Slicing static arrays? #4

tkf opened this issue Dec 21, 2019 · 21 comments

Comments

@tkf
Copy link
Contributor

tkf commented Dec 21, 2019

It would be great if I can do x[static(1):static(end)-static(1)] to get a static array (when x is an either static or regular array). Is it in the scope of this package?

@tkf tkf closed this as completed Dec 21, 2019
@tkf tkf changed the title Where is StaticArrays_glue.jl? Slicing static arrays? Dec 21, 2019
@tkf tkf reopened this Dec 21, 2019
@perrutquist
Copy link
Owner

I'm working on this. The syntax would be x[static(1):static(end-1)], since static(end)-static(1) would not be a static number.

@tkf
Copy link
Contributor Author

tkf commented Dec 28, 2019

The syntax would be x[static(1):static(end-1)], since static(end)-static(1) would not be a static number.

Ah, I missed that you explained it in README. Actually, why not extend static to UnitRange etc. so that static(1:end-1) would work? It's a bit of a stretch from the name "StaticNumbers.jl" but I think it makes sense from the point of view of the syntax. It'd be even better if StaticNumbers.jl and StaticArrays.jl share the static object/function so that static[1, 2, 3] would work (instead of SA[1, 2, 3]).

@perrutquist
Copy link
Owner

I've thought about this. The problem is deciding what should be static when there are several numbers involved. Currently, there is a function staticlength that will make the length (but not the starting point) of a range static. This would be enough to make x[staticlength(1:end-1)] a static array.
I guess it would make sense to make static(::UnitRange) return a range where both starting point and length are static.
I'm not so sure about static[1, 2, 3] returning a static array. It would seem more consistent with existing Julia syntax if it returned an Array{StaticInteger}, even if that would rarely be a useful thing to have.

@perrutquist
Copy link
Owner

So now, undocumented in the master branch, there's the possibility to do indexing with static numbers and get static arrays back. (Still just proof-of-concept. At the moment you get an MArray. I'll have to think about what the default should be.)

There's also a new macro @stat which provides a convenient shorthand. This macro turns all literals (and the end of static arrays) into static numbers, and also all functions on all-static arguments will have their return values converted to static. This means that @stat x[1:end-k] will give a static array if x is a static array and k is a static number. (Otherwise it yields a regular array).

@tkf
Copy link
Contributor Author

tkf commented Dec 28, 2019

Thanks a lot! I'll play with it.

The problem is deciding what should be static when there are several numbers involved.

Ah, that's interesting. I was not paying attention to this. But yes, it would be great if static(1:2) is equivalent to static(1):static(2).

This would be enough to make x[staticlength(1:end-1)] a static array.

That's OK when x is just an arbitrary array. But I don't think that's enough for efficient code-gen when x is a static array. This is especially the case when index is created somewhere else (as I guess the starting position of x[staticlength(1:end-1)] would still be handled via const-prop).

@perrutquist
Copy link
Owner

That's correct. The most efficient code will be x[@stat 1:end-1], which should always propagate as much information as is type-stably possible. (Although this macro is still work-in-progress.)

@perrutquist
Copy link
Owner

I also liked your idea of defining generators with static ranges to create static vectors. JuliaArrays/StaticArrays.jl#97

It is now possible to do, e.g. SVector(sin(i) for i in static(1):static(5)).

@tkf
Copy link
Contributor Author

tkf commented Dec 30, 2019

This is great! I just quickly played with it but it's super nice to see something like SVector(i^2 for i in static(1):static(5)) computed at compile-time even in Julia 1.0 :)

BTW, I realized that static(1):static(2):static(5) is printed as staticlength(1:2:5) even though the starting position is statically known:

julia> x = static(1):static(2):static(5)
staticlength(1:2:5)

julia> x.zeroth
static(-1)

julia> @code_typed optimize=true first(x)
CodeInfo(
1return 1
) => Int64

Maybe I just hit some WIP portion of the code?

@perrutquist
Copy link
Owner

The reason why first(x) returns an Int rather than a StaticInteger is that the element type of the range is still Int. If indexing into a static range returned static numbers, then there might be millions of them, leading to enormous compiler overhead.

(zeroth does not return an element from the range, so it can return a static.)

@stat first(x) returns a static number iff it is statically known.

@perrutquist
Copy link
Owner

And yes, the display part was work in progress. It shows as static(1:2:5) now, and that syntax can also be used to create the range.

@tkf
Copy link
Contributor Author

tkf commented Jan 1, 2020

Yes, that was my confusion. Thanks a lot for fixing this and introducing static(1:2:5)!

@perrutquist
Copy link
Owner

Going back to the main topic of slicing static arrays using static ranges. It now works for one-dimensional indexing, but not yet for multi-dimensional indexing.

I think the best course would be to hook into the existing machinery in StaticArrays. This would require making a small PR to that package (or a lot of code would need to be duplicated).

I'll leave this issue open, in order to track progress.

@tkf
Copy link
Contributor Author

tkf commented Jan 29, 2020

Re JuliaArrays/StaticArrays.jl#703 (comment):

This makes it possible to do indexing using variables and get an Array/SArray depending on whether everything is static in computing the index.

Based on this idea, wouldn't it be better to treat lastindex(::Array) as non-static? That is to say, @stat b[1:end-1] below would create an Array instead of a static array, while @stat b[1:2] still creates a static array.

julia> a = SA[1, 2, 3];

julia> b = [1, 2, 3];

julia> @stat a[1:end-1]
2-element SArray{Tuple{2},Int64,1,2} with indices SOneTo(2):
 1
 2

julia> @stat b[1:end-1]
2-element MArray{Tuple{2},Int64,1,2} with indices SOneTo(2):
 1
 2

@perrutquist
Copy link
Owner

With the latest release of StaticNumbers, you do get an Array. I think I should lower the version requirement of Requires.jl as that seems to be preventing StaticNumbers from being upgraded in many configurations.

@tkf
Copy link
Contributor Author

tkf commented Jan 29, 2020

I tried it in an isolated environment but I can't make it work:

(tmpkaq1o1hp.julia_tmp) pkg> st
    Status `/tmp/tmpkaq1o1hp.julia_tmp/Project.toml`
  [90137ffa] StaticArrays v0.12.1
  [c5e4b96a] StaticNumbers v0.3.1

julia> using StaticNumbers, StaticArrays

julia> b = [1, 2, 3];

julia> @stat b[1:end-1]
2-element MArray{Tuple{2},Int64,1,2} with indices SOneTo(2):
 1
 2

I tried master (35393ff) but the result is the same.

@tkf
Copy link
Contributor Author

tkf commented Jan 29, 2020

I'm guessing what I'm seeing is expected as I see static(end) in

julia> @macroexpand @stat b[1:end-1]
:((StaticNumbers.maybe_wrap(b))[maybe_static(:, static(1), maybe_static(-, static(end), static(1)))])

@perrutquist
Copy link
Owner

OK. That's clearly a bug. Will look into it.

@perrutquist
Copy link
Owner

Should be fixed now.

@tkf
Copy link
Contributor Author

tkf commented Jan 30, 2020

Thanks for fixing it!

BTW, it's just a bike-shedding (sorry!) but any reason why it's called @stat instead @static? Personally I associate stat with "statistics" (as in StatPlots.jl, Filesystem.stat). Also, it does not seem that adding two more characters reduces readability.

@perrutquist
Copy link
Owner

I would definitely have preferred to name it @static, but that name is already exported by Base.

@tkf
Copy link
Contributor Author

tkf commented Jan 30, 2020

Ah, of course!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants