HW2: Add julia implementations for v0.5 and v1

This commit is contained in:
2024-12-24 17:58:10 +02:00
parent 955981d177
commit 61b63016cc
8 changed files with 343 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
#
# ---------------------------------------------
# Bitonic v0.5 functionality
#
function partner(node, step)
partner = node + ((((node+step) % 2) == 0) ? 1 : -1)
end
function active(id, p)
ret = (id >= 0) && (id < p)
end
function exchange(localid, remoteid)
if verbose
println("Exchange local data from $localid with partner $remoteid")
end
nothing # We have all data here ;)
end
function minmax(data, localid, remoteid, keepsmall)
# Keep min-max on local data
temp = copy(data[localid+1, :])
if (keepsmall)
view(data, localid+1, :) .= min.(temp, data[remoteid+1, :])
view(data, remoteid+1, :) .= max.(temp, data[remoteid+1, :])
else
view(data, localid+1, :) .= max.(temp, data[remoteid+1, :])
view(data, remoteid+1, :) .= min.(temp, data[remoteid+1, :])
end
end
"""
distbubletonic!(p, data)
distributed bitonic v0.5 sort using a "bubble sort"-like functionality to propagate large and small
items between nodes.
p: The number of processes
data: (p, N/p) array
"""
function distbubletonic!(p, data)
pid = 0:p-1
ascending = mod.(pid,2) .== 0
if verbose
println("ascending: $ascending")
end
# local full sort here (run all MPI nodes)
for i in 1:p
sort!(view(data, i, :), rev = !ascending[i])
end
for step in 0:p-2
direction = [true for x = 1:p]
partnerid = partner.(pid, step)
activeids = active.(partnerid, p)
keepsmall = pid .< partnerid
if verbose
println("step: $step | active ids: $activeids | partner: $partnerid | keepsmall: $keepsmall")
end
# exchange with partner and keep small or large (run all MPI nodes)
for i in 0:p-1
l_idx = i+1
r_idx = partnerid[i+1]+1
if activeids[l_idx] && i < partnerid[l_idx]
exchange(i, partnerid[l_idx])
minmax(data, i, partnerid[l_idx], keepsmall[l_idx])
sort!(view(data, l_idx, :), rev = !ascending[l_idx]) # elbow sort here
sort!(view(data, r_idx, :), rev = !ascending[r_idx]) # elbow sort here
end
end
end
# [optional] reverse the odd positions (run all MPI nodes)
for i in 1:p
if !ascending[i]
sort!(view(data, i, :))
end
end
nothing
end
#
# Homework setup
# ---------------------------------------------
#
p::Int8 = 3 # The order of number of "processors"
q::Int8 = 8 # The data size order (power of 2) of each "processor"
verbose = false;
# Run Script
# ---------------------------------------------
P::Int = 2^p
Q::Int = 2^q
N::Int = 2^(q+p)
println("Distributed Bubbletonic (v0.5) test")
println("p: $p -> Number of processors: $P")
println("q: $q -> Data length for each node: $Q, Total: $(P*Q)")
println("Create an $P x $Q array")
Data = rand(Int8, P, Q)
println("Sort array with $P (MPI) nodes")
@time distbubletonic!(P, Data)
# Test
if issorted(vec(permutedims(Data)))
println("Test: Passed")
else
println("Test: Failed")
end
+113
View File
@@ -0,0 +1,113 @@
#
# ---------------------------------------------
# Bitonic v0.5 functionality
#
function exchange(localid, remoteid)
if verbose
println("Exchange local data from $localid with partner $remoteid")
end
nothing # We have all data here ;)
end
function minmax(data, localid, remoteid, keepsmall)
# Keep min-max on local data
temp = copy(data[localid+1, :])
if (keepsmall)
view(data, localid+1, :) .= min.(temp, data[remoteid+1, :])
view(data, remoteid+1, :) .= max.(temp, data[remoteid+1, :])
else
view(data, localid+1, :) .= max.(temp, data[remoteid+1, :])
view(data, remoteid+1, :) .= min.(temp, data[remoteid+1, :])
end
end
function sort_network!(data, n, depth)
nodes = 0:n-1
for step = depth-1:-1:0
partnerid = nodes .⊻ (1 << step)
direction = (nodes .& (1 << depth)) .== 0 .& (nodes .< partnerid)
keepsmall = ((nodes .< partnerid) .& direction) .| ((nodes .> partnerid) .& .!direction)
if verbose
println("depth: $depth | step: $step | partner: $partnerid | keepsmall: $keepsmall")
end
# exchange with partner and keep small or large (run all MPI nodes)
for i in 0:n-1
if (i < partnerid[i+1])
exchange(i, partnerid[i+1])
minmax(data, i, partnerid[i+1], keepsmall[i+1])
end
end
end
end
"""
distbitonic!(p, data)
distributed bitonic sort v1 using elbow merge locally except for the first step
p: The number of processes
data: (p, N/p) array
"""
function distbitonic!(p, data)
q = Int(log2(p)) # CPU order
pid = 0:p-1
ascending = mod.(pid,2) .== 0
if verbose
println("ascending: $ascending")
end
# local full sort here (run all MPI nodes)
for i in 1:p
sort!(view(data, i, :), rev = !ascending[i])
end
for depth = 1:q
sort_network!(data, p, depth)
ascending = (pid .& (1 << depth)) .== 0
if verbose
println("ascending: $ascending")
end
# local elbowmerge here (run all MPI nodes)
for i in 1:p
sort!(view(data, i, :), rev = !ascending[i])
end
end
nothing
end
#
# Homework setup
# ---------------------------------------------
#
p::Int8 = 3 # The order of number of "processors"
q::Int8 = 8 # The data size order (power of 2) of each "processor"
verbose = false;
# Run Script
# ---------------------------------------------
P::Int = 2^p
Q::Int = 2^q
N::Int = 2^(q+p)
println("Distributed bitonic (v1) test")
println("p: $p -> Number of processors: $P")
println("q: $q -> Data length for each node: $Q, Total: $(P*Q)")
println("Create an $P x $Q array")
Data = rand(Int8, P, Q)
println("Sort array with $P (MPI) nodes")
@time distbitonic!(P, Data)
# Test
if issorted(vec(permutedims(Data)))
println("Test: Passed")
else
println("Test: Failed")
end
+27
View File
@@ -0,0 +1,27 @@
# distributed bitonic sort using elbow merge locally except for the first step
function distbitonic!(p)
q = Int(log2(p))
pid = 0:p-1
ascending = mod.(pid,2) .== 0
println("ascending: $ascending")
# local full sort here
for k = 1:q
kk = 1 << k
for j = k-1:-1:0
jj = 1 << j
partnerid = pid .⊻ jj
direction = (pid .& kk) .== 0 .& (pid .< partnerid)
keepsmall = ((pid .< partnerid) .& direction) .| ((pid .> partnerid) .& .!direction)
println("k: $k | j: $j | partner: $partnerid | keepsmall: $keepsmall")
# exchange with partner and keep small or large
end
ascending = (pid .& kk) .== 0
println("ascending: $ascending")
# local elbowmerge here
end
nothing
end
+23
View File
@@ -0,0 +1,23 @@
# given a bitonic sequence b, merge it into a sorted sequence s
@inbounds function elbowmerge!(s, b)
n = length(b)
l = argmin(b)
r = l == n ? 1 : l + 1
i = 1
while i <= n
if b[l] < b[r]
s[i] = b[l]
l = l == 1 ? n : l - 1
else
s[i] = b[r]
r = r == n ? 1 : r + 1
end
i += 1
end
nothing
end