Skip to content

Commit 478987f

Browse files
Update README
1 parent bae7ace commit 478987f

File tree

1 file changed

+64
-3
lines changed

1 file changed

+64
-3
lines changed

README.md

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ This library provides "vectorized" (with/without multithreading) versions of the
1818
The naming convention is as follows: a vectorized (without threading) version is prefixed by `v`, and a vectorized with threading version is prefixed by `vt`.
1919
There is a single exception to this rule: vectorized (without threading) versions of the functions listed in 1. are prefixed by `vv` in order to avoid name collisions with LoopVectorization and VectorizedStatistics.
2020

21+
This library also provides other, less common, reductions (all of which follow the naming convention above):
22+
1. `mapreducethen` : Apply function `f` to each element of `A`, reduce the result over the dimensions `dims` using the binary function `op`, then apply `g` to the result
23+
2. distances: `manhattan`, `euclidean`, `chebyshe`, `minkowski`
24+
3. norms: `norm`, treating arbitrary slices via `dims` keyword
25+
4. deviances: `counteq`, `countne`, `meanad`, `maxad`, `mse`, `rmse`
26+
5. means: `mean`, `geomean`, `harmmean`
27+
6. entropies: `crossentropy`, `shannonentropy`, `collisionentropy`, `minentropy`, `maxentropy`, `renyientropy`
28+
7. divergences: `kldivergence`, `gkldiv`, `renyidivergence`
29+
2130
## Motivation
2231

2332
When writing numerical code, one may wish to perform a reduction, perhaps across multiple dimensions, as the most natural means of expressing the relevant mathematical operation.
@@ -238,13 +247,65 @@ BenchmarkTools.Trial: 10000 samples with 173 evaluations.
238247
</details>
239248

240249

250+
### `mapreducethen` examples
251+
<details>
252+
<summaryClick me! ></summary>
253+
<p>
254+
255+
Examples of seemingly strange but useful concept: `mapreduce(f, op, ...)`, then apply `g` to each element of the result. However, the post-transform `g` can be fused such that the output array is populated in a single pass, hence, `mapreducethen(f, op, g, ...)`. It happens that many familiar quantities follow this pattern, as shown below.
256+
257+
```julia
258+
# L₂ norm
259+
julia> A = rand(10,10,10,10);
260+
261+
julia> @benchmark vmapreducethen(abs2, +, , $A, dims=(2,4))
262+
BenchmarkTools.Trial: 10000 samples with 10 evaluations.
263+
Range (min max): 1.634 μs 620.474 μs ┊ GC (min max): 0.00% 99.00%
264+
Time (median): 1.969 μs ┊ GC (median): 0.00%
265+
Time (mean ± σ): 2.040 μs ± 6.188 μs ┊ GC (mean ± σ): 3.01% ± 0.99%
266+
267+
Memory estimate: 960 bytes, allocs estimate: 3.
268+
269+
julia> @benchmark .√mapreduce(abs2, +, $A, dims=(2,4))
270+
BenchmarkTools.Trial: 10000 samples with 4 evaluations.
271+
Range (min max): 7.462 μs 13.938 μs ┊ GC (min max): 0.00% 0.00%
272+
Time (median): 7.957 μs ┊ GC (median): 0.00%
273+
Time (mean ± σ): 8.017 μs ± 378.040 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
274+
275+
Memory estimate: 2.05 KiB, allocs estimate: 10.
276+
277+
# Euclidean distance
278+
julia> euclidean(x, y; dims=:) = .√mapreduce(abs2 -, +, x, y, dims=dims);
279+
280+
julia> veuclidean(x, y; dims=:) = vmapreducethen((a, b) -> abs2(a - b), +, , x, y, dims=dims);
281+
282+
julia> @benchmark veuclidean(A, B, dims=(1,3))
283+
BenchmarkTools.Trial: 10000 samples with 8 evaluations.
284+
Range (min max): 3.277 μs 6.065 μs ┊ GC (min max): 0.00% 0.00%
285+
Time (median): 3.576 μs ┊ GC (median): 0.00%
286+
Time (mean ± σ): 3.602 μs ± 202.787 ns ┊ GC (mean ± σ): 0.00% ± 0.00%
287+
288+
Memory estimate: 992 bytes, allocs estimate: 4.
289+
290+
julia> @benchmark euclidean(A, B, dims=(1,3))
291+
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
292+
Range (min max): 11.103 μs 2.024 ms ┊ GC (min max): 0.00% 95.82%
293+
Time (median): 13.781 μs ┊ GC (median): 0.00%
294+
Time (mean ± σ): 17.502 μs ± 58.495 μs ┊ GC (mean ± σ): 9.72% ± 2.90%
295+
296+
Memory estimate: 80.28 KiB, allocs estimate: 13.
297+
```
298+
</p>
299+
</details>
300+
301+
241302
## Acknowledgments
242303
The original motivation for this work was a vectorized & multithreaded multi-dimensional findmin, taking a variable number of array arguments -- it's a long story, but the similarity between findmin and mapreduce motivated a broad approach. My initial attempt (visible in the /attic) did not deliver all the performance possible -- this was only apparent through comparison to C. Elrod's approach to multidimensional forms in VectorizedStatistics. Having fully appreciated the beauty of branching through @generated functions, I decided to take a tour of some low-hanging fruit -- this package is the result.
243304

244305
## Future work
245-
1. post-reduction operators
246-
2. reductions over index subsets within a dimension.
247-
3. actual documentation
306+
1. post-reduction operators
307+
2. reductions over index subsets within a dimension.
308+
3. actual documentation
248309

249310
## Elsewhere
250311
* [LoopVectorization.jl](https://github.com/chriselrod/LoopVectorization.jl) back-end for this package.

0 commit comments

Comments
 (0)