|
1 |
| -# To-do |
2 |
| - |
3 |
| -- Remove Compat.jl from dependencies and test dependencies. |
4 |
| -- Unregistered dependencies: BroadcastMapConversion, NestedPermutedDimsArrays, TypeParameterAccessors. |
5 |
| -- Create SparseArraysBaseLinearAlgebraExt, SparseArraysBaseNestedPermutedDimsArraysExt, SparseArraysBaseVectorInterfaceExt. |
6 |
| -- Change [sources] entries from paths to urls. |
7 |
| - |
8 |
| -# SparseArraysBase |
9 |
| - |
10 |
| -SparseArraysBase is a package that aims to expand on the sparse array functionality that is currently in Julia Base. |
11 |
| -While SparseArrays.jl is centered mostly around `SparseMatrixCSC` and the SuiteSparse library, here we wish to broaden the scope a bit, and consider generic sparse arrays. |
12 |
| -Abstractly, the mental model can be considered as a storage object that holds the stored values, and a bijection between the array indices and the indices of the storage. |
13 |
| -For now, we focus on providing efficient implementations of Dictionary of Key (DOK) type sparse storage formats, but may expand upon this in the future. |
14 |
| -As a result, for typical linear algebra routines, we still expect `SparseMatrixCSC` to be the object of choice. |
15 |
| - |
16 |
| -The design consists of roughly three components: |
17 |
| -- `AbstractSparseArray` interface functions |
18 |
| -- Overloaded Julia base methods |
19 |
| -- `SparseArrayDOK` struct that implements this |
20 |
| - |
21 |
| -## AbstractSparseArray |
22 |
| - |
23 |
| -The first part consists of typical functions that are useful in the context of sparse arrays. |
24 |
| -The minimal interface, which enables the usage of the rest of this package, consists of the following functions: |
25 |
| - |
26 |
| -| Signature | Description | Default | |
27 |
| -|-----------|-------------|---------| |
28 |
| -| `sparse_storage(a::AbstractArray)` | Returns the storage object of the sparse array | `a` | |
29 |
| -| `storage_index_to_index(a::AbstractArray, I)` | Converts a storage index to an array index | `I` | |
30 |
| -| `index_to_storage_index(a::AbstractArray, I)` | Converts an array index to a storage index | `I` | |
31 |
| - |
32 |
| -Using these primitives, several convenience functions are defined to facilitate the writing of sparse array algorithms. |
33 |
| - |
34 |
| -| Signature | Description | Default | |
35 |
| -|-----------|-------------|---------| |
36 |
| -| `storage_indices(a)` | Returns the indices of the storage | `eachindex(sparse_storage(a))` | |
37 |
| -| `stored_indices(a)` | Returns the indices of the stored values | `Iterators.map(Base.Fix1(storage_index_to_index, a), storage_indices(a))` | |
38 |
| -| `stored_length(a)` | Returns the number of stored values | `length(storage_indices(a))` | |
39 |
| - |
40 |
| -<!-- TODO: `getindex!`, `increaseindex!`, `sparse_map`, expose "zero" functionality? --> |
41 |
| - |
42 |
| -Interesting to note here is that the design is such that we can define sparse arrays without having to subtype `AbstractSparseArray`. |
43 |
| -To achieve this, each function `f` is defined in terms of `sparse_f`, rather than directly overloading `f`. |
44 |
| -<!-- |
45 |
| -TODO: |
46 |
| -In order to opt-in to the sparse array functionality, one needs to dispatch the functions through `sparse_f` instead of `f`. |
47 |
| -For convenience, you can automatically dispatch all functions through `sparse_f` by using the following macro: |
48 |
| -
|
49 |
| -```julia |
50 |
| -@abstractsparsearray MySparseArrayType |
51 |
| -``` |
52 |
| ---> |
53 |
| - |
54 |
| -## Overloaded Julia base methods |
55 |
| - |
56 |
| -The second part consists of overloading Julia base methods to work with sparse arrays. |
57 |
| -In particular, specialised implementations exist for the following functions: |
58 |
| - |
59 |
| -- `sparse_similar` |
60 |
| -- `sparse_reduce` |
61 |
| -- `sparse_map` |
62 |
| -- `sparse_map!` |
63 |
| -- `sparse_all` |
64 |
| -- `sparse_any` |
65 |
| -- `sparse_isequal` |
66 |
| -- `sparse_fill!` |
67 |
| -- `sparse_zero`, `sparse_zero!`, `sparse_iszero` |
68 |
| -- `sparse_one`, `sparse_one!`, `sparse_isone` |
69 |
| -- `sparse_reshape`, `sparse_reshape!` |
70 |
| -- `sparse_cat`, `sparse_cat!` |
71 |
| -- `sparse_copy!`, `sparse_copyto!` |
72 |
| -- `sparse_permutedims`, `sparse_permutedims!` |
73 |
| -- `sparse_mul!`, `sparse_dot` |
74 |
| - |
75 |
| -## SparseArrayDOK |
76 |
| - |
77 |
| -Finally, the `SparseArrayDOK` struct is provided as a concrete implementation of the `AbstractSparseArray` interface. |
78 |
| -It is a dictionary of keys (DOK) type sparse array, which stores the values in a `Dictionaries.jl` dictionary, and maps the indices to the keys of the dictionary. |
79 |
| -This model is particularly useful for sparse arrays with a small number of non-zero elements, or for arrays that are constructed incrementally, as it boasts fast random accesses and insertions. |
80 |
| -The drawback is that sequential iteration is slower than for other sparse array types, leading to slower linear algebra operations. |
81 |
| -For the purposes of `SparseArraysBase`, this struct will serve as the canonical example of a sparse array, and will be returned by default when new sparse arrays are created. |
82 |
| - |
83 |
| -One particular feature of `SparseArrayDOK` is that it can be used in cases where the non-stored entries have to be constructed in a non-trivial way. |
84 |
| -Typically, sparse arrays use `zero(eltype(a))` to construct the non-stored entries, but this is not always sufficient. |
85 |
| -A concrete example is found in `BlockSparseArrays.jl`, where initialization of the non-stored entries requires the construction of a block of zeros of appropriate size. |
86 |
| - |
87 |
| -<!-- TODO: update TODOs --> |
88 |
| - |
89 |
| -## TODO |
90 |
| -Still need to implement `Base` functions: |
91 |
| -```julia |
92 |
| -[x] sparse_zero(a::AbstractArray) = similar(a) |
93 |
| -[x] sparse_iszero(a::AbstractArray) = iszero(nonzero_length(a)) # Uses `all`, make `sparse_all`? |
94 |
| -[x] sparse_one(a::AbstractArray) = ... |
95 |
| -[x] sparse_isreal(a::AbstractArray) = ... # Uses `all`, make `sparse_all`? |
96 |
| -[x] sparse_isequal(a1::AbstractArray, a2::AbstractArray) = ... |
97 |
| -[x] sparse_conj!(a::AbstractArray) = conj!(nonzeros(a)) |
98 |
| -[x] sparse_reshape(a::AbstractArray, dims) = ... |
99 |
| -[ ] sparse_all(f, a::AbstractArray) = ... |
100 |
| -[ ] sparse_getindex(a::AbstractArray, 1:2, 2:3) = ... # Slicing |
101 |
| -``` |
102 |
| -`LinearAlgebra` functions: |
103 |
| -```julia |
104 |
| -[ ] sparse_mul! |
105 |
| -[ ] sparse_lmul! |
106 |
| -[ ] sparse_ldiv! |
107 |
| -[ ] sparse_rdiv! |
108 |
| -[ ] sparse_axpby! |
109 |
| -[ ] sparse_axpy! |
110 |
| -[ ] sparse_norm |
111 |
| -[ ] sparse_dot/sparse_inner |
112 |
| -[ ] sparse_adoint! |
113 |
| -[ ] sparse_transpose! |
114 |
| - |
115 |
| -# Using conversion to `SparseMatrixCSC`: |
116 |
| -[ ] sparse_qr |
117 |
| -[ ] sparse_eigen |
118 |
| -[ ] sparse_svd |
119 |
| -``` |
120 |
| -`TensorAlgebra` functions: |
121 |
| -```julia |
122 |
| -[ ] add! |
123 |
| -[ ] contract! |
124 |
| -``` |
| 1 | +- Updates for latest Derive. |
0 commit comments