Skip to content

Commit 0bbc0e3

Browse files
authored
Merge pull request #298 from jw3126/docs
Use Documenter.jl for documentation (# 70)
2 parents 3801f17 + 6a095e5 commit 0bbc0e3

File tree

8 files changed

+435
-316
lines changed

8 files changed

+435
-316
lines changed

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ julia:
99
notifications:
1010
email: false
1111
branches:
12-
only: # Only kick off CI for master and potential merges to master from within PRs
12+
only:
1313
- master
14+
- /^v[0-9]+\.[0-9]+\.[0-9]+$/ # version tags for Documenter.jl, see # 298
1415
matrix:
1516
allow_failures:
1617
- julia: nightly
@@ -23,3 +24,5 @@ after_success:
2324
- if [ $TRAVIS_JULIA_VERSION = "0.6" ] && [ $TRAVIS_OS_NAME = "linux" ]; then
2425
julia -e 'cd(Pkg.dir("StaticArrays")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder()); Codecov.submit(Codecov.process_folder())';
2526
fi
27+
- julia -e 'Pkg.add("Documenter")'
28+
- julia -e 'cd(Pkg.dir("StaticArrays")); include(joinpath("docs", "make.jl"))'

README.md

Lines changed: 3 additions & 303 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
[![Build status](https://ci.appveyor.com/api/projects/status/xabgh1yhsjxlp30d?svg=true)](https://ci.appveyor.com/project/JuliaArrays/staticarrays-jl)
99
[![Coverage Status](https://coveralls.io/repos/github/JuliaArrays/StaticArrays.jl/badge.svg?branch=master)](https://coveralls.io/github/JuliaArrays/StaticArrays.jl?branch=master)
1010
[![codecov.io](http://codecov.io/github/JuliaArrays/StaticArrays.jl/coverage.svg?branch=master)](http://codecov.io/github/JuliaArrays/StaticArrays.jl?branch=master)
11+
[![](https://img.shields.io/badge/docs-latest-blue.svg)](https://JuliaArrays.github.io/StaticArrays.jl/latest)
12+
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaArrays.github.io/StaticArrays.jl/stable)
1113

1214
**StaticArrays** provides a framework for implementing statically sized arrays
1315
in Julia (≥ 0.5), using the abstract type `StaticArray{Size,T,N} <: AbstractArray{T,N}`.
@@ -22,6 +24,7 @@ Mutable versions `MVector`, `MMatrix` and `MArray` are also exported, as well
2224
as `SizedArray` for annotating standard `Array`s with static size information.
2325
Further, the abstract `FieldVector` can be used to make fast `StaticVector`s
2426
out of any uniform Julia "struct".
27+
Full documentation can be found [here](https://JuliaArrays.github.io/StaticArrays.jl/stable/).
2528

2629
## Speed
2730

@@ -141,309 +144,6 @@ precise dimensions of the input. In combination with intelligent fallbacks to
141144
the methods in Base, we seek to provide a comprehensive support for statically
142145
sized arrays, large or small, that hopefully "just works".
143146

144-
## API Details
145-
146-
### The `Size` trait
147-
148-
The size of a statically sized array is a static parameter associated with the
149-
type of the array. The `Size` trait is provided as an abstract representation of
150-
the dimensions of a static array. An array `sa::SA` of size `(dims...)` is
151-
associated with `Size{(dims...)}()`. The following are equivalent (`@pure`)
152-
constructors:
153-
```julia
154-
Size{(dims...)}()
155-
Size(dims...)
156-
Size(sa::StaticArray)
157-
Size(SA) # SA <: StaticArray
158-
```
159-
This is extremely useful for (a) performing dispatch depending on the size of an
160-
array, and (b) passing array dimensions that the compiler can reason about.
161-
162-
An example of size-based dispatch for the determinant of a matrix would be:
163-
```julia
164-
det(x::StaticMatrix) = _det(Size(x), x)
165-
_det(::Size{(1,1)}, x::StaticMatrix) = x[1,1]
166-
_det(::Size{(2,2)}, x::StaticMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1]
167-
# and other definitions as necessary
168-
```
169-
170-
Examples of using `Size` as a compile-time constant include
171-
```julia
172-
reshape(svector, Size(2,2)) # Convert SVector{4} to SMatrix{2,2}
173-
Size(3,3)(rand(3,3)) # Construct a random 3×3 SizedArray (see below)
174-
```
175-
176-
### Indexing
177-
178-
Statically sized indexing can be realized by indexing each dimension by a
179-
scalar, a `StaticVector` or `:`. Indexing in this way will result a statically
180-
sized array (even if the input was dynamically sized, in the case of
181-
`StaticVector` indices) of the closest type (as defined by `similar_type`).
182-
183-
Conversely, indexing a statically sized array with a dynamically sized index
184-
(such as a `Vector{Integer}` or `UnitRange{Integer}`) will result in a standard
185-
(dynamically sized) `Array`.
186-
187-
### `similar_type()`
188-
189-
Since immutable arrays need to be constructed "all-at-once", we need a way of
190-
obtaining an appropriate constructor if the element type or dimensions of the
191-
output array differs from the input. To this end, `similar_type` is introduced,
192-
behaving just like `similar`, except that it returns a type. Relevant methods
193-
are:
194-
195-
```julia
196-
similar_type{A <: StaticArray}(::Type{A}) # defaults to A
197-
similar_type{A <: StaticArray, ElType}(::Type{A}, ::Type{ElType}) # Change element type
198-
similar_type{A <: AbstractArray}(::Type{A}, size::Size) # Change size
199-
similar_type{A <: AbstractArray, ElType}(::Type{A}, ::Type{ElType}, size::Size) # Change both
200-
```
201-
202-
These setting will affect everything, from indexing, to matrix multiplication
203-
and `broadcast`. Users wanting introduce a new array type should *only* overload
204-
the last method in the above.
205-
206-
Use of `similar` will fall back to a mutable container, such as a `MVector`
207-
(see below), and it requires use of the `Size` trait if you wish to set a new
208-
static size (or else a dynamically sized `Array` will be generated when
209-
specifying the size as plain integers).
210-
211-
### `SVector`
212-
213-
The simplest static array is the type `SVector{N,T}`, which provides an
214-
immutable vector of fixed length `N` and type `T`.
215-
216-
`SVector` defines a series of convenience constructors, so you can just type
217-
e.g. `SVector(1,2,3)`. Alternatively there is an intelligent `@SVector` macro
218-
where you can use native Julia array literals syntax, comprehensions, and the
219-
`zeros()`, `ones()`, `fill()`, `rand()` and `randn()` functions, such as `@SVector [1,2,3]`,
220-
`@SVector Float64[1,2,3]`, `@SVector [f(i) for i = 1:10]`, `@SVector zeros(3)`,
221-
`@SVector randn(Float32, 4)`, etc (Note: the range of a comprehension is evaluated at global scope by the
222-
macro, and must be made of combinations of literal values, functions, or global
223-
variables, but is not limited to just simple ranges. Extending this to
224-
(hopefully statically known by type-inference) local-scope variables is hoped
225-
for the future. The `zeros()`, `ones()`, `fill()`, `rand()` and `randn()` functions do not have this
226-
limitation.)
227-
228-
### `SMatrix`
229-
230-
Statically sized `N×M` matrices are provided by `SMatrix{N,M,T,L}`.
231-
232-
Here `L` is the `length` of the matrix, such that `N × M = L`. However,
233-
convenience constructors are provided, so that `L`, `T` and even `M` are
234-
unnecessary. At minimum, you can type `SMatrix{2}(1,2,3,4)` to create a 2×2
235-
matrix (the total number of elements must divide evenly into `N`). A
236-
convenience macro `@SMatrix [1 2; 3 4]` is provided (which also accepts
237-
comprehensions and the `zeros()`, `ones()`, `fill()`, `rand()`, `randn()` and `eye()`
238-
functions).
239-
240-
### `SArray`
241-
242-
A container with arbitrarily many dimensions is defined as
243-
`struct SArray{Size,T,N,L} <: StaticArray{Size,T,N}`, where
244-
`Size = Tuple{S1, S2, ...}` is a tuple of `Int`s. You can easily construct one with
245-
the `@SArray` macro, supporting all the features of `@SVector` and `@SMatrix`
246-
(but with arbitrary dimension).
247-
248-
The main reason `SVector` and `SMatrix` are defined is to make it easier to
249-
define the types without the extra tuple characters (compare `SVector{3}` to
250-
`SArray{Tuple{3}}`).
251-
252-
### `Scalar`
253-
254-
Sometimes you want to broadcast an operation, but not over one of your inputs.
255-
A classic example is attempting to displace a collection of vectors by the
256-
same vector. We can now do this with the `Scalar` type:
257-
258-
```julia
259-
[[1,2,3], [4,5,6]] .+ Scalar([1,0,-1]) # [[2,2,2], [5,5,5]]
260-
```
261-
262-
`Scalar` is simply an implementation of an immutable, 0-dimensional `StaticArray`.
263-
264-
### Mutable arrays: `MVector`, `MMatrix` and `MArray`
265-
266-
These statically sized arrays are identical to the above, but are defined as
267-
`mutable struct`s, instead of immutable `struct`s. Because they are mutable, they
268-
allow `setindex!` to be defined (achieved through pointer manipulation, into a
269-
tuple).
270-
271-
As a consequence of Julia's internal implementation, these mutable containers
272-
live on the heap, not the stack. Their memory must be allocated and tracked by
273-
the garbage collector. Nevertheless, there is opportunity for speed
274-
improvements relative to `Base.Array` because (a) there may be one less
275-
pointer indirection, (b) their (typically small) static size allows for
276-
additional loop unrolling and inlining, and consequentially (c) their mutating
277-
methods like `map!` are extremely fast. Benchmarking shows that operations such
278-
as addition and matrix multiplication are faster for `MMatrix` than `Matrix`,
279-
at least for sizes up to 14 × 14, though keep in mind that optimal speed will
280-
be obtained by using mutating functions (like `map!` or `A_mul_B!`) where
281-
possible, rather than reallocating new memory.
282-
283-
Mutable static arrays also happen to be very useful containers that can be
284-
constructed on the heap (with the ability to use `setindex!`, etc), and later
285-
copied as e.g. an immutable `SVector` to the stack for use, or into e.g. an
286-
`Array{SVector}` for storage.
287-
288-
Convenience macros `@MVector`, `@MMatrix` and `@MArray` are provided.
289-
290-
### `SizedArray`: a decorate size wrapper for `Array`
291-
292-
Another convenient mutable type is the `SizedArray`, which is just a wrapper-type
293-
about a standard Julia `Array` which declares its knwon size. For example, if
294-
we knew that `a` was a 2×2 `Matrix`, then we can type `sa = SizedArray{Tuple{2,2}}(a)`
295-
to construct a new object which knows the type (the size will be verified
296-
automatically). A more convenient syntax for obtaining a `SizedArray` is by calling
297-
a `Size` object, e.g. `sa = Size(2,2)(a)`.
298-
299-
Then, methods on `sa` will use the specialized code provided by the *StaticArrays*
300-
pacakge, which in many cases will be much, much faster. For example, calling
301-
`eig(sa)` will be signficantly faster than `eig(a)` since it will perform a
302-
specialized 2×2 matrix diagonalization rather than a general algorithm provided
303-
by Julia and *LAPACK*.
304-
305-
In some cases it will make more sense to use a `SizedArray`, and in other cases
306-
an `MArray` might be preferable.
307-
308-
### `FieldVector`
309-
310-
Sometimes it might be useful to imbue your own types, having multiple fields,
311-
with vector-like properties. *StaticArrays* can take care of this for you by
312-
allowing you to inherit from `FieldVector{N, T}`. For example, consider:
313-
314-
```julia
315-
struct Point3D <: FieldVector{3, Float64}
316-
x::Float64
317-
y::Float64
318-
z::Float64
319-
end
320-
```
321-
322-
With this type, users can easily access fields to `p = Point3D(x,y,z)` using
323-
`p.x`, `p.y` or `p.z`, or alternatively via `p[1]`, `p[2]`, or `p[3]`. You may
324-
even permute the coordinates with `p[SVector(3,2,1)]`). Furthermore, `Point3D`
325-
is a complete `AbstractVector` implementation where you can add, subtract or
326-
scale vectors, multiply them by matrices, etc.
327-
328-
It is also worth noting that `FieldVector`s may be mutable or immutable, and
329-
that `setindex!` is defined for use on mutable types. For immutable containers,
330-
you may want to define a method for `similar_type` so that operations leave the
331-
type constant (otherwise they may fall back to `SVector`). For mutable
332-
containers, you may want to define a default constructor (no inputs) and an
333-
appropriate method for `similar`,
334-
335-
### Implementing your own types
336-
337-
You can easily create your own `StaticArray` type, by defining linear
338-
`getindex` (and optionally `setindex!` for mutable types - see
339-
`setindex(::MArray, val, i)` in *MArray.jl* for an example of how to
340-
achieve this through pointer manipulation). Your type should define a constructor
341-
that takes a tuple of the data (and mutable containers may want to define a
342-
default constructor).
343-
344-
Other useful functions to overload may be `similar_type` (and `similar` for
345-
mutable containers).
346-
347-
### Conversions from `Array`
348-
349-
In order to convert from a dynamically sized `AbstractArray` to one of the
350-
statically sized array types, you must specify the size explicitly. For
351-
example,
352-
353-
```julia
354-
v = [1,2]
355-
356-
m = [1 2;
357-
3 4]
358-
359-
# ... a lot of intervening code
360-
361-
sv = SVector{2}(v)
362-
sm = SMatrix{2,2}(m)
363-
sa = SArray{(2,2)}(m)
364-
365-
sized_v = Size(2)(v) # SizedArray{(2,)}(v)
366-
sized_m = Size(2,2)(m) # SizedArray{(2,2)}(m)
367-
```
368-
369-
We have avoided adding `SVector(v::AbstractVector)` as a valid constructor to
370-
help users avoid the type instability (and potential performance disaster, if
371-
used without care) of this innocuous looking expression. However, the simplest
372-
way to deal with an `Array` is to create a `SizedArray` by calling a `Size`
373-
instance, e.g. `Size(2)(v)`.
374-
375-
### Arrays of static arrays
376-
377-
Storing a large number of static arrays is convenient as an array of static
378-
arrays. For example, a collection of positions (3D coordinates - `SVector{3,Float64}`)
379-
could be represented as a `Vector{SVector{3,Float64}}`.
380-
381-
Another common way of storing the same data is as a 3×`N` `Matrix{Float64}`.
382-
Rather conveniently, such types have *exactly* the same binary layout in memory,
383-
and therefore we can use `reinterpret` to convert between the two formats
384-
```julia
385-
function svectors(x::Matrix{Float64})
386-
@assert size(x,1) == 3
387-
reinterpret(SVector{3,Float64}, x, (size(x,2),))
388-
end
389-
```
390-
Such a conversion does not copy the data, rather it refers to the *same* memory
391-
referenced by two different Julia `Array`s. Arguably, a `Vector` of `SVector`s
392-
is preferable to a `Matrix` because (a) it provides a better abstraction of the
393-
objects contained in the array and (b) it allows the fast *StaticArrays* methods
394-
to act on elements.
395-
396-
### Working with mutable and immutable arrays
397-
398-
Generally, it is performant to rebind an *immutable* array, such as
399-
```julia
400-
function average_position(positions::Vector{SVector{3,Float64}})
401-
x = zeros(SVector{3,Float64})
402-
for pos positions
403-
x = x + pos
404-
end
405-
return x / length(positions)
406-
end
407-
```
408-
so long as the `Type` of the rebound variable (`x`, above) does not change.
409-
410-
On the other hand, the above code for mutable containers like `Array`, `MArray`
411-
or `SizedArray` is *not* very efficient. Mutable containers in Julia 0.5 must
412-
be *allocated* and later *garbage collected*, and for small, fixed-size arrays
413-
this can be a leading contribution to the cost. In the above code, a new array
414-
will be instantiated and allocated on each iteration of the loop. In order to
415-
avoid unnecessary allocations, it is best to allocate an array only once and
416-
apply mutating functions to it:
417-
```julia
418-
function average_position(positions::Vector{SVector{3,Float64}})
419-
x = zeros(MVector{3,Float64})
420-
for pos positions
421-
# Take advantage of Julia 0.5 broadcast fusion
422-
x .= (+).(x, pos) # same as broadcast!(+, x, x, positions[i])
423-
end
424-
x .= (/).(x, length(positions))
425-
return x
426-
end
427-
```
428-
Keep in mind that Julia 0.5 does not fuse calls to `.+`, etc (or `.+=` etc),
429-
however the `.=` and `(+).()` syntaxes are fused into a single, efficient call
430-
to `broadcast!`. The simpler syntax `x .+= pos` is expected to be non-allocating
431-
(and therefore faster) in Julia 0.6.
432-
433-
The functions `setindex`, `push`, `pop`, `shift`, `unshift`, `insert` and `deleteat`
434-
are provided for performing certain specific operations on static arrays, in
435-
analogy with the standard functions `setindex!`, `push!`, `pop!`, etc. (Note that
436-
if the size of the static array changes, the type of the output will differ from
437-
the input.)
438-
439-
### SIMD optimizations
440-
441-
It seems Julia and LLVM are smart enough to use processor vectorization
442-
extensions like SSE and AVX - however they are currently partially disabled by
443-
default. Run Julia with `julia -O` or `julia -O3` to enable these optimizations,
444-
and many of your (immutable) `StaticArray` methods *should* become significantly
445-
faster!
446-
447147
## Relationship to *FixedSizeArrays* and *ImmutableArrays*
448148

449149
Several existing packages for statically sized arrays have been developed for

docs/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build
2+
site

docs/make.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Documenter, StaticArrays
2+
3+
makedocs(
4+
format = :html,
5+
modules = [StaticArrays],
6+
sitename = "StaticArrays.jl",
7+
pages = [
8+
"Home" => "index.md",
9+
"API" => "pages/api.md",
10+
"Quick Start" => "pages/quickstart.md",
11+
],
12+
)
13+
14+
deploydocs(
15+
repo = "github.com/JuliaArrays/StaticArrays.jl",
16+
)

docs/src/index.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Static Arrays
2+
*Statically sized arrays for Julia*
3+
4+
**StaticArrays** provides a framework for implementing statically sized arrays
5+
in Julia (≥ 0.5), using the abstract type `StaticArray{Size,T,N} <: AbstractArray{T,N}`.
6+
Subtypes of [`StaticArray`](@ref) will provide fast implementations of common array and
7+
linear algebra operations. Note that here "statically sized" means that the
8+
size can be determined from the *type*, and "static" does **not** necessarily
9+
imply `immutable`.
10+
11+
The package also provides some concrete static array types: [`SVector`](@ref), [`SMatrix`](@ref)
12+
and [`SArray`](@ref), which may be used as-is (or else embedded in your own type).
13+
Mutable versions [`MVector`](@ref), [`MMatrix`](@ref) and [`MArray`](@ref) are also exported, as well
14+
as [`SizedArray`](@ref) for annotating standard `Array`s with static size information.
15+
Further, the abstract [`FieldVector`](@ref) can be used to make fast static vectors
16+
out of any uniform Julia "struct".

0 commit comments

Comments
 (0)