|
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