From 0f4739138cb6f86db6cb2fa5269b703361705819 Mon Sep 17 00:00:00 2001 From: Shardul Chiplunkar <shardul.chiplunkar@epfl.ch> Date: Tue, 30 May 2023 18:32:50 +0200 Subject: [PATCH] Update convolution solution (oops mainly for completeness now) --- .../scala/midterm23/convolution.worksheet.sc | 59 ++++++++++++++++--- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/src/main/scala/midterm23/convolution.worksheet.sc b/src/main/scala/midterm23/convolution.worksheet.sc index 1f76d77..a2457d4 100644 --- a/src/main/scala/midterm23/convolution.worksheet.sc +++ b/src/main/scala/midterm23/convolution.worksheet.sc @@ -16,13 +16,30 @@ def sequentialConvolve( from: Int, until: Int ): Unit = { + // Approach A, as described in the clarification announcement for this + // exercise, where we treat `from` and `until` as indices on `output` + // instead of `input` as in the given code. var iOutput = from while iOutput < until do var iKernel = math.max(0, iOutput - input.length + 1) while iKernel < kernel.length && iKernel <= iOutput do + // `output` is only ever written to between the indices `from` and + // `until`, the range of `iOutput`. The indices for `input` and + // `kernel` are computed accordingly. output(iOutput) += input(iOutput - iKernel) * kernel(iKernel) iKernel += 1 iOutput += 1 + + // ALTERNATE SOLUTION: Approach B, as described in the clarification + // announcement for this exercise, which is unchanged from the given + // code, i.e. we treat `from` and `until` as indices on `input`. + var iInput = from + while iInput < until do + var iKernel = 0 + while iKernel < kernel.length do + output(iInput + iKernel) += input(iInput) * kernel(iKernel) + iKernel += 1 + iInput += 1 } def parallelConvolve( @@ -32,7 +49,12 @@ def parallelConvolve( from: Int, until: Int, threshold: Int -): Unit = +): Unit = + // Approach A, as described in the clarification announcement for this + // exercise, where we treat `from` and `until` as indices on `output` + // instead of `input` as in the given code. This does not require us to + // change anything in this function. Only receives full credit if used + // together with Approach A for `sequentialConvolve`. if (until - from) <= threshold then sequentialConvolve(input, kernel, output, from, until) else @@ -42,6 +64,31 @@ def parallelConvolve( parallelConvolve(input, kernel, output, mid, until, threshold) ) + // ALTERNATE SOLUTION: Approach B, as described in the clarification + // announcement for this exercise, where we treat `from` and `until` as + // indices on `input` as in the given code. This requires up to leave a + // gap in the parallel calls to be filled in sequentially as described + // below. Only receives full credit if used together with Approach B for + // `sequentialConvolve`. + if (until - from) <= threshold then + sequentialConvolve(input, kernel, output, from, until) + else + val mid = from + (until - from) / 2 + val gap = numContributeTo(input, kernel, output, mid) + // Leave a gap large enough that accesses to `output` from the first + // parallel call will not overlap with accesses from the second. This + // gap is of size equal to the number of elements of `input` that will + // contribute to the computation of the result at the lowest index of + // `output` in the second parallel call, namely, at index `mid`. + // However, we are careful not to access indices lower than `from`. + val gapBeforeMid = Math.max(from, mid - gap + 1) + parallel( + parallelConvolve(input, kernel, output, from, gapBeforeMid, threshold), + parallelConvolve(input, kernel, output, mid, until, threshold) + ) + // Fill in the gap sequentially. + sequentialConvolve(input, kernel, output, gapBeforeMid, mid) + object Original_WithOutputRace: def sequentialConvolve( @@ -50,15 +97,13 @@ object Original_WithOutputRace: output: Array[Int], from: Int, until: Int): Unit = - var iOutput = from - while iOutput < until do + var iInput = from + while iInput < until do var iKernel = 0 while iKernel < kernel.length do - val iInput = iOutput - iKernel - if 0 <= iInput && iInput < input.length then - output(iOutput) += input(iInput) * kernel(iKernel) + output(iInput + iKernel) += input(iInput) * kernel(iKernel) iKernel += 1 - iOutput += 1 + iInput += 1 def parallelConvolve( input: Array[Int], -- GitLab