Skip to content

Commit 07d25c1

Browse files
authored
Kc/ohp6 (#15)
* fix deprecs * add benchmarks * updates
1 parent a67fdc1 commit 07d25c1

24 files changed

+658
-889
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
*.jl.*.cov
33
*.jl.mem
44
docs/build/
5-
docs/site/
5+
docs/site/
6+
*.jld
7+
benchmark/*.md

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,4 @@ script:
1414

1515
after_success:
1616
- julia -e 'cd(Pkg.dir("BlockArrays")); Pkg.add("Coverage"); using Coverage; Codecov.submit(process_folder())'
17-
- julia -e 'Pkg.clone("https://github.com/MichaelHatherly/Documenter.jl")'
1817
- julia -e 'cd(Pkg.dir("BlockArrays")); include(joinpath("docs", "make.jl"))'

REQUIRE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
julia 0.5-
1+
julia 0.6-

benchmark/generate_report.jl

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# The functionality to export the benchmark results to a markdown file heavily uses code from Nanosoldier.jl
2+
# The Nanosoldier.jl package is licensed under the MIT "Expat" License:
3+
#
4+
# Copyright (c) 2015: Jarrett Revels.
5+
6+
const REGRESS_MARK = ":x:"
7+
const IMPROVE_MARK = ":white_check_mark:"
8+
9+
function printreport(io::IO, results; iscomparisonjob::Bool = false)
10+
11+
if iscomparisonjob
12+
print(io, """
13+
A ratio greater than `1.0` denotes a possible regression (marked with $(REGRESS_MARK)), while a ratio less
14+
than `1.0` denotes a possible improvement (marked with $(IMPROVE_MARK)). Only significant results - results
15+
that indicate possible regressions or improvements - are shown below (thus, an empty table means that all
16+
benchmark results remained invariant between builds).
17+
18+
| ID | time ratio | memory ratio |
19+
|----|------------|--------------|
20+
""")
21+
else
22+
print(io, """
23+
| ID | time | GC time | memory | allocations |
24+
|----|------|---------|--------|-------------|
25+
""")
26+
end
27+
28+
entries = BenchmarkTools.leaves(results)
29+
30+
try
31+
entries = entries[sortperm(map(x -> string(first(x)), entries))]
32+
end
33+
34+
35+
for (ids, t) in entries
36+
if !(iscomparisonjob) || BenchmarkTools.isregression(t) || BenchmarkTools.isimprovement(t)
37+
println(io, resultrow(ids, t))
38+
end
39+
end
40+
41+
return nothing
42+
end
43+
44+
idrepr(id) = (str = repr(id); str[searchindex(str, '['):end])
45+
intpercent(p) = string(ceil(Int, p * 100), "%")
46+
resultrow(ids, t::BenchmarkTools.Trial) = resultrow(ids, minimum(t))
47+
48+
function resultrow(ids, t::BenchmarkTools.TrialEstimate)
49+
t_tol = intpercent(BenchmarkTools.params(t).time_tolerance)
50+
m_tol = intpercent(BenchmarkTools.params(t).memory_tolerance)
51+
timestr = string(BenchmarkTools.prettytime(BenchmarkTools.time(t)), " (", t_tol, ")")
52+
memstr = string(BenchmarkTools.prettymemory(BenchmarkTools.memory(t)), " (", m_tol, ")")
53+
gcstr = BenchmarkTools.prettytime(BenchmarkTools.gctime(t))
54+
allocstr = string(BenchmarkTools.allocs(t))
55+
return "| `$(idrepr(ids))` | $(timestr) | $(gcstr) | $(memstr) | $(allocstr) |"
56+
end
57+
58+
function resultrow(ids, t::BenchmarkTools.TrialJudgement)
59+
t_tol = intpercent(BenchmarkTools.params(t).time_tolerance)
60+
m_tol = intpercent(BenchmarkTools.params(t).memory_tolerance)
61+
t_ratio = @sprintf("%.2f", BenchmarkTools.time(BenchmarkTools.ratio(t)))
62+
m_ratio = @sprintf("%.2f", BenchmarkTools.memory(BenchmarkTools.ratio(t)))
63+
t_mark = resultmark(BenchmarkTools.time(t))
64+
m_mark = resultmark(BenchmarkTools.memory(t))
65+
timestr = "$(t_ratio) ($(t_tol)) $(t_mark)"
66+
memstr = "$(m_ratio) ($(m_tol)) $(m_mark)"
67+
return "| `$(idrepr(ids))` | $(timestr) | $(memstr) |"
68+
end
69+
70+
resultmark(sym::Symbol) = sym == :regression ? REGRESS_MARK : (sym == :improvement ? IMPROVE_MARK : "")

benchmark/runbenchmarks.jl

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using BlockArrays
2+
using BenchmarkTools
3+
using FileIO
4+
5+
include("generate_report.jl")
6+
7+
const SUITE = BenchmarkGroup()
8+
9+
g = addgroup!(SUITE, "indexing")
10+
# g_block = addgroup!(SUITE, "blockindexing")
11+
g_size = addgroup!(SUITE, "size")
12+
13+
for n = (5,)
14+
for BT in (BlockArray, PseudoBlockArray)
15+
block_vec = BT(rand(n), [1,3,1])
16+
block_mat = BT(rand(n,n), [1,3,1], [4,1])
17+
block_arr = BT(rand(n,n,n), [1,3,1], [4,1], [3, 2])
18+
g["getindex", BT.name.name, "vector", n] = @benchmarkable getindex($block_vec, 3)
19+
g["getindex", BT.name.name, "matrix", n] = @benchmarkable getindex($block_mat, 3, 2)
20+
g["getindex", BT.name.name, "rank3", n] = @benchmarkable getindex($block_arr, 3, 2 ,3)
21+
22+
g["setindex!", BT.name.name, "vector", n] = @benchmarkable setindex!($block_vec, 3)
23+
g["setindex!", BT.name.name, "matrix", n] = @benchmarkable setindex!($block_mat, 3, 2)
24+
g["setindex!", BT.name.name, "rank3", n] = @benchmarkable setindex!($block_arr, 3, 2 ,3)
25+
26+
g_size[BT.name.name, "vector", n] = @benchmarkable size($block_vec)
27+
g_size[BT.name.name, "matrix", n] = @benchmarkable size($block_mat)
28+
g_size[BT.name.name, "rank3", n] = @benchmarkable size($block_arr)
29+
end
30+
end
31+
32+
33+
function run_benchmarks(name, tagfilter = @tagged ALL)
34+
const paramspath = joinpath(dirname(@__FILE__), "params.jld")
35+
if !isfile(paramspath)
36+
println("Tuning benchmarks...")
37+
tune!(SUITE, verbose=true)
38+
JLD.save(paramspath, "SUITE", params(SUITE))
39+
end
40+
loadparams!(SUITE, JLD.load(paramspath, "SUITE"), :evals, :samples)
41+
results = run(SUITE[tagfilter], verbose = true, seconds = 2)
42+
JLD.save(joinpath(dirname(@__FILE__), name * ".jld"), "results", results)
43+
end
44+
45+
function generate_report(v1, v2)
46+
v1_res = load(joinpath(dirname(@__FILE__), v1 * ".jld"), "results")
47+
v2_res = load(joinpath(dirname(@__FILE__), v2 * ".jld"), "results")
48+
open(joinpath(dirname(@__FILE__), "results_$(v1)_$(v2).md"), "w") do f
49+
printreport(f, judge(minimum(v1_res), minimum(v2_res)); iscomparisonjob = true)
50+
end
51+
end
52+
53+
function generate_report(v1)
54+
v1_res = load(joinpath(dirname(@__FILE__), v1 * ".jld"), "results")
55+
open(joinpath(dirname(@__FILE__), "results_$(v1).md"), "w") do f
56+
printreport(f, minimum(v1_res); iscomparisonjob = false)
57+
end
58+
end
59+

docs/make.jl

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,32 @@ using Documenter, BlockArrays
44
# ====================
55

66
makedocs(
7-
# options
87
modules = [BlockArrays],
9-
clean = true,
8+
format = :html,
9+
sitename = "BlockArrays.jl",
1010
doctest = false,
11-
)
11+
strict = VERSION.minor == 6 && sizeof(Int) == 8, # only strict mode on 0.6 and Int64
12+
pages = Any[
13+
"Home" => "index.md",
14+
"Manual" => [
15+
"man/abstractblockarrayinterface.md",
16+
"man/blockarrays.md",
17+
"man/pseudoblockarrays.md",
18+
],
19+
"API" => [
20+
"lib/public.md",
21+
"lib/internals.md"
22+
]
23+
]
24+
)
1225

1326
# Deploy built documentation from Travis.
1427
# =======================================
1528

1629
deploydocs(
17-
# options
18-
deps = Deps.pip("mkdocs", "python-markdown-math"),
19-
repo = "github.com/KristofferC/BlockArrays.jl.git"
30+
repo = "https://github.com/KristofferC/BlockArrays.jl",
31+
target = "build",
32+
julia = "nightly", # deploy from release bot
33+
deps = nothing,
34+
make = nothing
2035
)

docs/src/index.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ A block array is a partition of an array into blocks or subarrays, see [wikipedi
88

99
Secondly, it also implements two different type of block arrays that follow the `AbstractBlockArray` interface. The type `BlockArray` stores each block contiguously while the type `PseudoBlockArray` stores the full matrix contiguously. This means that `BlockArray` supports fast non copying extraction and insertion of blocks while `PseudoBlockArray` supports fast access to the full matrix to use in in for example a linear solver.
1010

11-
**Note:** Currently, a quite new build of julia master is needed to use this package.
12-
13-
1411
## Manual Outline
1512

1613
```@contents
17-
Pages = ["man/abstractblockarrayinterface.md", "man/blockarrayss.md", "man/pseudoblockarrays.md"]
14+
Pages = ["man/abstractblockarrayinterface.md", "man/blockarrays.md", "man/pseudoblockarrays.md"]
1815
Depth = 2
1916
```
2017

docs/src/lib/public.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ blocksize
3434
getblock
3535
getblock!
3636
setblock!
37-
getindex
38-
setindex!
39-
full
37+
Array
4038
blockcheckbounds
4139
```
4240

docs/src/man/abstractblockarrayinterface.md

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,30 @@ In order to follow the `AbstractBlockArray` the following methods should be impl
1010
| `blocksize(A, i...)` | Size of the block at block index `i...` |
1111
| `getblock(A, i...)` | `X[Block(i...)]`, blocked indexing |
1212
| `setblock!(A, v, i...)` | `X[Block(i...)] = v`, blocked index assignment |
13-
| `full(A)` | The non blocked array |
1413
| **Optional methods** | |
1514
| `getblock!(x, A, i)` | `X[i]`, blocked index assignment with in place storage in `x` |
1615

1716
For a more thorough description of the methods see the public interface documentation.
1817

19-
2018
With the methods above implemented the following are automatically provided:
2119

2220
* A pretty printing `show` function that uses unicode lines to split up the blocks:
23-
24-
julia> A = BlockArray(rand(4, 5), [1,3], [2,3])
25-
2×2-blocked 4×5 BlockArrays.BlockArray{Float64,2,Array{Float64,2}}:
26-
0.28346 0.234328 │ 0.10266 0.0670817 0.941958
27-
--------------------┼-------------------------------
28-
0.881618 0.152164 │ 0.938311 0.819992 0.860623
29-
0.74367 0.16049 │ 0.704886 0.950269 0.601036
30-
0.502035 0.259069 │ 0.857453 0.197673 0.962873
31-
32-
* Indexing with `Enums` works as a way to access blocks and set blocks.
33-
34-
julia> @enum vars u=1 v=2
35-
36-
julia> A[u, v]
37-
1×3 Array{Float64,2}:
38-
0.10266 0.0670817 0.941958
39-
40-
julia> A[u, v] = zeros(1,3);
41-
42-
julia> A[u, v]
43-
1×3 Array{Float64,2}:
44-
0.0 0.0 0.0
45-
21+
```
22+
julia> A = BlockArray(rand(4, 5), [1,3], [2,3])
23+
2×2-blocked 4×5 BlockArrays.BlockArray{Float64,2,Array{Float64,2}}:
24+
0.61179 0.965631 │ 0.696476 0.392796 0.712462
25+
--------------------┼-------------------------------
26+
0.620099 0.364706 │ 0.0311643 0.27895 0.73477
27+
0.215712 0.923602 │ 0.279944 0.994497 0.383706
28+
0.569955 0.754047 │ 0.0190392 0.548297 0.687052
29+
```
4630

4731
* A bounds index checking function for indexing with blocks:
4832

49-
julia> blockcheckbounds(A, 5, 3)
50-
ERROR: BlockBoundsError: attempt to access 2×2-blocked 4×5 BlockArrays.BlockArray{Float64,2,Array{Float64,2}} at block index [5,3]
51-
in blockcheckbounds(::BlockArrays.BlockArray{Float64,2,Array{Float64,2}}, ::Int64, ::Int64) at .julia/v0.5/BlockArrays/src/abstractblockarray.jl:190
52-
in eval(::Module, ::Any) at ./boot.jl:226
33+
```
34+
julia> blockcheckbounds(A, 5, 3)
35+
ERROR: BlockBoundsError: attempt to access 2×2-blocked 4×5 BlockArrays.BlockArray{Float64,2,Array{Float64,2}} at block index [5,3]
36+
```
5337

5438
* Happy users who know how to use your new block array :)
5539

docs/src/man/blockarrayss.md renamed to docs/src/man/blockarrays.md

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
# BlockArrays
22

3-
3+
```@meta
4+
DocTestSetup = quote
5+
srand(1234)
6+
end
7+
```
48

59
## Creating uninitialized `BlockArrays`.
610

711
A `BlockArray` can be created with the blocks left uninitialized using the `BlockArray(block_type, block_sizes...)` function.
812
The `block_type` should be an array type, it could for example be `Matrix{Float64}`. The block sizes are each a `Vector{Int}` which determines the size of the blocks in that dimension. We here create a `[1,2]×[3,2]` block matrix of `Float32`s:
913

10-
```jl
14+
```jldoctest
1115
julia> BlockArray(Matrix{Float32}, [1,2], [3,2])
1216
2×2-blocked 3×5 BlockArrays.BlockArray{Float32,2,Array{Float32,2}}:
1317
#undef #undef #undef │ #undef #undef
@@ -25,6 +29,7 @@ julia> BlockArray(SparseVector{Float64, Int}, [1,2])
2529
------
2630
#undef
2731
#undef
32+
julia> BlockArray(SparseVector{Float64, Int}, [1,2])
2833
```
2934

3035
Note that accessing an undefined block will throw an "access to undefined reference"-error.
@@ -34,7 +39,7 @@ Note that accessing an undefined block will throw an "access to undefined refere
3439
A block can be set by `setblock!(block_array, v, i...)` where `v` is the array to set and `i` is the block index.
3540
An alternative syntax for this is `block_array[Block(i...)] = v`.
3641

37-
```jl
42+
```jldoctest
3843
julia> block_array = BlockArray(Matrix{Float64}, [1,2], [2,2])
3944
2×2-blocked 3×4 BlockArrays.BlockArray{Float64,2,Array{Float64,2}}:
4045
#undef #undef │ #undef #undef
@@ -46,24 +51,24 @@ julia> setblock!(block_array, rand(2,2), 2, 1)
4651
2×2-blocked 3×4 BlockArrays.BlockArray{Float64,2,Array{Float64,2}}:
4752
#undef #undef │ #undef #undef
4853
------------------------┼----------------
49-
0.314407 0.298761#undef #undef
50-
0.91585 0.644499#undef #undef
54+
0.590845 0.566237 │ #undef #undef
55+
0.766797 0.460085 │ #undef #undef
5156
5257
julia> block_array[Block(1, 1)] = [1 2];
5358
5459
julia> block_array
5560
2×2-blocked 3×4 BlockArrays.BlockArray{Float64,2,Array{Float64,2}}:
5661
1.0 2.0 │ #undef #undef
5762
--------------------┼----------------
58-
0.314407 0.298761#undef #undef
59-
0.91585 0.644499#undef #undef
63+
0.590845 0.566237 │ #undef #undef
64+
0.766797 0.460085 │ #undef #undef
6065
```
6166

6267
Note that this will "take ownership" of the passed in array, that is, no copy is made.
6368

6469
A block can be retrieved with `getblock(block_array, i...)` or `block_array[Block(i...)]`:
6570

66-
```jl
71+
```jldoctest
6772
julia> block_array[Block(1, 1)]
6873
1×2 Array{Float64,2}:
6974
1.0 2.0
@@ -84,26 +89,27 @@ An array can be repacked into a `BlockArray` with`BlockArray(array, block_sizes.
8489

8590
```jl
8691
julia> block_array_sparse = BlockArray(sprand(4, 5, 0.7), [1,3], [2,3])
87-
2×2-blocked 4×5 BlockArrays.BlockArray{Float64,2,SparseMatrixCSC{Float64,Int64}
88-
0.0 0.2843380.0 0.52346 0.403969
89-
----------------------------------------------------
90-
0.909193 0.00.0 0.3401 0.922003
91-
0.0 0.7367930.00840872 0.804832 0.441806
92-
0.0 0.0 0.553519 0.757454 0.575238
92+
2×2-blocked 4×5 BlockArrays.BlockArray{Float64,2,SparseMatrixCSC{Float64,Int64}}:
93+
0.0341601 0.3741870.0118196 0.299058 0.0
94+
----------------------------------------------------
95+
0.0945445 0.9311150.0460428 0.0 0.0
96+
0.314926 0.4389390.496169 0.0 0.0
97+
0.12781 0.246862 0.732 0.449182 0.875096
9398
```
9499

95-
To get back the full array use `full`:
100+
To get back the underlying array use `Array`:
96101

97102
```jl
98-
julia> full(block_array_sparse)
99-
4×5 sparse matrix with 13 Float64 nonzero entries:
100-
[2, 1] = 0.909193
101-
[1, 2] = 0.284338
102-
103-
[3, 5] = 0.441806
104-
[4, 5] = 0.575238
103+
julia> Array(block_array_sparse))
104+
4×5 SparseMatrixCSC{Float64,Int64} with 15 stored entries:
105+
[1, 1] = 0.0341601
106+
[2, 1] = 0.0945445
107+
[3, 1] = 0.314926
108+
[4, 1] = 0.12781
109+
110+
[3, 3] = 0.496169
111+
[4, 3] = 0.732
112+
[1, 4] = 0.299058
113+
[4, 4] = 0.449182
114+
[4, 5] = 0.875096
105115
```
106-
107-
## Operations on `BlockArrays`.
108-
109-
Simple unary/binary functions and reductions are available, for an overview, see the `operations.jl` file.

0 commit comments

Comments
 (0)