MoreMaps.jl
A flexible mapping framework for Julia that provides different parallel backends, progress tracking, and iteration patterns.
Features
Multiple backends: Sequential, Threads, Distributed, and Dagger execution
Progress tracking: Support for various progress-logging backends
Nested array support: Map over specific leaf types in nested array structures
Cartesian expansions: Easy cartesian product iterations
Quick Start
using MoreMaps
# Basic usage with default sequential backend
x = rand(100)
C = Chart()
y = map(sqrt, C, x)
# Use threading for parallel execution
C_threaded = Chart(Threaded())
y_threaded = map(sqrt, C_threaded, x)
# Add progress tracking
C_progress = Chart(Threaded(), InfoProgress(10))
y_progress = map(sqrt, C_progress, x)
100-element Vector{Float64}:
0.21073576873920544
0.3933385093554212
0.7736951181035961
0.5096616084679445
0.7731130496985201
0.9478047608430491
0.08355353231655491
0.7200468871178003
0.4594856716422489
0.8116854628406893
⋮
0.5637188513276394
0.18728992876732398
0.9374005323433758
0.4871468095876077
0.43716208888658614
0.6698952421198582
0.8884788088664157
0.37225323516348824
0.7307266869002826
Basics
The basis of a MoreMaps
map is the Chart
type, which configures how mapping operations are executed.
A Chart
has the following fields:
backend
: Specifies the execution backendprogress
: Configures the progress logging behaviorleaf
: Defines the element type where recursion terminates, for mapping nested arraysexpansion
: Determines the expansion strategy (e.g. Cartesian product)
A chart can be constructed using keywords or arbitrary-order positional arguments. The default Chart()
reproduces Base.map()
, and is constructed as:
C = Chart(backend=Sequential(), # No parallel execution; similar to Base.map
progress=NoProgress(), # No progress logging
leaf=MoreMaps.All, # Map over each element of the root array, like Base.map
expansion=NoExpansion()) # Map over the original input arrays, as for Base.map
# Or
C = Chart(Sequential(), NoProgress(), MoreMaps.All, NoExpansion()) # In any order
# Default behavior
C == Chart()
Mapping
Once you have a Chart, pass it to the standard Base.map
function:
using MoreMaps
x = rand(10)
C = Chart()
y = map(sqrt, C, x)
y == map(sqrt, x)
true
See the following pages for details on configuring a Chart
:
Backends - Execution strategies (Sequential, Threaded, Distributed, Dagger)
Progress - Progress tracking options
Leaves - Nested array handling
Expansions - Cartesian product iterations
Expansions
Cartesian Product Expansions
MoreMaps.jl supports automatic expansion of iterators into cartesian products, enabling efficient multi-dimensional mapping operations.
Basic Expansion
Use Iterators.product
as the expansion function to create cartesian products:
x = 1:3
y = 4:6
C = Chart(expansion = Iterators.product)
z = map(+, C, x, y)
3×3 Matrix{Int64}:
5 6 7
6 7 8
7 8 9
Multi-dimensional Expansions
Works with any number of iterators:
x = 1:2
y = 3:4
z = 5:6
C = Chart(expansion = Iterators.product)
result = map((a, b, c) -> a + b + c, C, x, y, z)
2×2×2 Array{Int64, 3}:
[:, :, 1] =
9 10
10 11
[:, :, 2] =
10 11
11 12
Combining with Backends
Expansions work with all execution backends:
x = 1:10
y = 1:10
# Sequential with expansion
C_seq = Chart(Sequential(), NoProgress(), All, Iterators.product)
z_seq = map(*, C_seq, x, y)
# Threaded with expansion
C_thread = Chart(Threaded(), NoProgress(), All, Iterators.product)
z_thread = map(*, C_thread, x, y)
10×10 Matrix{Int64}:
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
Custom Expansion Functions
You can provide custom expansion functions:
# Custom expansion that zips instead of products
function zip_expansion(iters...)
return zip(iters...)
end
x = 1:5
y = 6:10
# Note: This would need proper implementation in the package
# C = Chart(expansion = zip_expansion)
# z = map(+, C, x, y)
6:10
Expansion with Nested Arrays
Expansions interact with leaf types:
x = [[1, 2], [3, 4]]
y = [[5, 6], [7, 8]]
# Expand outer arrays
C_outer = Chart(leaf = All, expansion = Iterators.product)
result_outer = map((a, b) -> length(a) + length(b), C_outer, x, y)
# Expand at leaf level
C_leaf = Chart(leaf = Vector{Int}, expansion = Iterators.product)
result_leaf = map((a, b) -> a .+ b, C_leaf, x, y)
2×2 Matrix{Vector{Int64}}:
[6, 8] [8, 10]
[8, 10] [10, 12]
Performance Considerations
# Small expansions are efficient
x = 1:10
y = 1:10
C = Chart(Threaded(), NoProgress(), All, Iterators.product)
@time z = map(+, C, x, y)
# Be careful with large expansions
# x = 1:1000
# y = 1:1000
# This creates a 1,000,000 element result!
10×10 Matrix{Int64}:
2 3 4 5 6 7 8 9 10 11
3 4 5 6 7 8 9 10 11 12
4 5 6 7 8 9 10 11 12 13
5 6 7 8 9 10 11 12 13 14
6 7 8 9 10 11 12 13 14 15
7 8 9 10 11 12 13 14 15 16
8 9 10 11 12 13 14 15 16 17
9 10 11 12 13 14 15 16 17 18
10 11 12 13 14 15 16 17 18 19
11 12 13 14 15 16 17 18 19 20
Practical Applications
Parameter Sweeps
# Sweep over parameter combinations
alphas = [0.1, 0.5, 1.0]
betas = [1, 2, 3]
C = Chart(Threaded(), InfoProgress(5), All, Iterators.product)
results = map(C, alphas, betas) do α, β
# Simulate some computation
sum(α * sin(x) + β * cos(x) for x in 1:100)
end
3×3 Matrix{Float64}:
-0.545006 -1.07729 -1.60958
-0.595874 -1.12816 -1.66045
-0.65946 -1.19175 -1.72404
Grid Computations
# Create a 2D grid evaluation
x_range = range(-1, 1, length=20)
y_range = range(-1, 1, length=20)
C = Chart(Threaded(), NoProgress(), All, Iterators.product)
grid = map((x, y) -> x^2 + y^2, C, x_range, y_range)
20×20 Matrix{Float64}:
2.0 1.80055 1.62327 1.46814 … 1.62327 1.80055 2.0
1.80055 1.60111 1.42382 1.2687 1.42382 1.60111 1.80055
1.62327 1.42382 1.24654 1.09141 1.24654 1.42382 1.62327
1.46814 1.2687 1.09141 0.936288 1.09141 1.2687 1.46814
1.33518 1.13573 0.958449 0.803324 0.958449 1.13573 1.33518
1.22438 1.02493 0.847645 0.692521 … 0.847645 1.02493 1.22438
1.13573 0.936288 0.759003 0.603878 0.759003 0.936288 1.13573
1.06925 0.869806 0.692521 0.537396 0.692521 0.869806 1.06925
1.02493 0.825485 0.648199 0.493075 0.648199 0.825485 1.02493
1.00277 0.803324 0.626039 0.470914 0.626039 0.803324 1.00277
1.00277 0.803324 0.626039 0.470914 … 0.626039 0.803324 1.00277
1.02493 0.825485 0.648199 0.493075 0.648199 0.825485 1.02493
1.06925 0.869806 0.692521 0.537396 0.692521 0.869806 1.06925
1.13573 0.936288 0.759003 0.603878 0.759003 0.936288 1.13573
1.22438 1.02493 0.847645 0.692521 0.847645 1.02493 1.22438
1.33518 1.13573 0.958449 0.803324 … 0.958449 1.13573 1.33518
1.46814 1.2687 1.09141 0.936288 1.09141 1.2687 1.46814
1.62327 1.42382 1.24654 1.09141 1.24654 1.42382 1.62327
1.80055 1.60111 1.42382 1.2687 1.42382 1.60111 1.80055
2.0 1.80055 1.62327 1.46814 1.62327 1.80055 2.0
NoExpansion (Default)
The default behavior performs element-wise mapping without expansion:
x = 1:3
y = 4:6
C = Chart() # Default: NoExpansion()
z = map(+, C, x, y) # Element-wise addition
3-element Vector{Int64}:
5
7
9