Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • lamp/cs206
  • bwermeil/cs206-2020
  • zabifade/cs206-2020
  • cauderan/cs206-2020
  • malonga/cs206-2020
  • dumoncel/cs206
  • bounekhe/cs206
  • bergerault/cs206
  • flealsan/cs206
  • hsu/cs206
  • mouchel/cs206
  • vebraun/cs206
  • vcanard/cs206
  • ybelghmi/cs206
  • belghmi/cs206
  • bousbina/cs206
  • waked/cs206
  • gtagemou/cs206
  • arahmoun/cs206
  • elhachem/cs206
  • benrahha/cs206
  • benslima/cs206
22 results
Show changes
Showing
with 0 additions and 3461 deletions
# Parallel Box Blur Filter
## Setup
Let's upgrade the IDE support first, close VSCode if it's open and run:
```shell
code --force --install-extension scalameta.metals
```
Use the following commands to make a fresh clone of your repository:
```
git clone -b scalashop git@gitlab.epfl.ch:lamp/student-repositories-s21/cs206-GASPAR.git cs206-scalashop
```
## Useful links
* [A guide to the Scala parallel collections](https://docs.scala-lang.org/overviews/parallel-collections/overview.html)
* [The API documentation of the Scala parallel collections](https://www.javadoc.io/doc/org.scala-lang.modules/scala-parallel-collections_2.13/latest/scala/collection/index.html)
* [The API documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.4)
* [The API documentation of the Java standard library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)
**If you have issues with the IDE, try [reimporting the
build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work),
if you still have problems, use `compile` in sbt instead.**
## Setup scalashop
In this assignment, we will implement a box blur filter, used in applications
like Adobe® PhotoShop® to blur images.
For the purposes of this assignment, a filter is an algorithm that takes an
input image and transforms it in some way into an output image.
The box blur filter outputs an image in which every pixel has an average value
of the surrounding pixels from the original image.
The box blur filter is an example of an *embarrassingly parallel* problem -- no
or very little effort is required to separate it into parallel tasks.
Every pixel of the output image can be computed independently of the other
pixels, and in parallel.
We will proceed in four steps. First, we will implement the kernel of the box
blur filter, a method used to compute a single pixel of the output image.
Then we will implement two versions of the parallel box blur, and measure the
performance difference.
Finally, we will try out our parallel box blur implementations on real images,
using ScalaShop -- the image manipulation tool that would impress even
the Adobe® folks.
By the time you are finished with this assignment, you will:
- understand how the box blur filter works
- be able to recognize embarrassingly parallel problems
- know how to measure the performance of a parallel algorithm
- see how to agglomerate parallel computations into batches
- better understand how memory access patterns affect performance of parallel
algorithms
## Preliminaries
Before we begin, we need to cover some basic data types and helper methods.
These utilities have already been implemented in the package object (in the file `package.scala`) for this
exercise.
First, we will use the `RGBA` type to refer to the value of an image pixel.
We will limit ourselves to 32-bit pixel depth images, so we define `RGBA` to
be equal to the 32-bit integer type:
```scala
type RGBA = Int
```
Why do we call this type `RGBA`?
This is because each pixel value is composed from 4 components - red, green,
blue and alpha, where alpha denotes the amount of transparency in the
respective pixel.
These components are referred to as *channels*.
The value of each channel is at least 0 and at most 255.
We can extract the red, green, blue and alpha channel using the following
utility methods, which use bit masking and bit shifting:
```scala
def red(c: RGBA): Int = (0xff000000 & c) >>> 24
def green(c: RGBA): Int = (0x00ff0000 & c) >>> 16
def blue(c: RGBA): Int = (0x0000ff00 & c) >>> 8
def alpha(c: RGBA): Int = (0x000000ff & c) >>> 0
```
Similarly, given the values of the four channels, we can obtain the pixel value
like this:
```scala
def rgba(r: Int, g: Int, b: Int, a: Int): RGBA =
(r << 24) | (g << 16) | (b << 8) | (a << 0)
```
Now that we know how to manipulate individual pixels, we can define our image
type `Img`:
```scala
class Img(val width: Int, val height: Int) {
private val data = new Array[RGBA](width * height)
def apply(x: Int, y: Int): RGBA = data(y * width + x)
def update(x: Int, y: Int, c: RGBA): Unit = data(y * width + x) = c
}
```
The image is a two-dimensional entity -- to refer to a pixel in an image, we
need to specify an `x` and `y` component.
On the other hand, the underlying memory model is one-dimensional -- a single
offset value specifies the position in the array.
When we store the image into memory, we need to map between the
two-dimensional image model and the one-dimensional memory model.
We will do this by storing consecutive rows of the image one after another, as
illustrated in the following figure:
![mapping](mapping.png)
Thus, the offset of a pixel at coordinates `x` and `y`, is equal to
`y * width + x`, where `width` is the number of pixels in a single row.
Although there are other mappings used in practice, we will restrict to this
simple mapping throughout the exercise.
To ensure that the value of the `x` and `y` coordinates are confined to the
dimensions of the image, namely width and height, occasionally we have to call
the `clamp` method:
```scala
def clamp(v: Int, min: Int, max: Int): Int
```
Finally, we will use the `task` construct to start parallel computations.
Every `task` construct invocation returns an object on which we can call the
`join` method.
Calling the `join` method blocks the execution of the program until the parallel
computation ends.
Below, we calculate the expression `1 + 1` in parallel to the main program:
```scala
val computation = task {
val result = 1 + 1
println("Done!")
result
}
println("About to wait for some heavy calculation...")
computation.join()
```
We now have everything we need to start implementing the parallel box filter.
## The Box Blur Filter Kernel
In the first part of the assignment, we will implement the box blur filter
kernel method.
A kernel is a method that computes the resulting value of a single pixel.
The kernel method is typically computationally cheap and is not worth
parallelizing its implementation.
However, as we will later see, we can apply the same kernel method to different
pixels in parallel.
![kernel](kernel.png)
The `boxBlurKernel` method takes the source image `src`, coordinates `x` and `y`
of the pixel, and the `radius` of the blur.
It returns the resulting average value of the surrounding pixels.
We compute the average value by separating the pixel into four channels,
computing the average of each of the channels,
and using the four average values to produce the final pixel value.
In the previous figure, the `radius` parameter is equal to `1` and the average
is computed from `9` pixels.
You can find its signature in the package object of this assignment:
def boxBlurKernel(src: Img, x: Int, y: Int, radius: Int): RGBA
Implement the `boxBlurKernel` method.
Use two nested `while`-loops.
Make sure that the pixels at the image edges are affected only by the
pixels inside the image (hint: use the `clamp` method from the package object).
## Vertical Stripping Box Blur
We can now implement the parallel box blur filter.
Note that the `boxBlurKernel` method is relatively inexpensive.
Executing `boxBlurKernel` might be much faster than starting a parallel
computation, so having a separate parallel computation for the value of each
pixel would be far too expensive.
For this reason, we want to batch together many `boxBlurKernel` calls, and have
a smaller number of parallel tasks.
This is sometimes referred to as *agglomeration*, and is present in many
parallel algorithm implementations.
There are many different ways we can do agglomeration for the parallel box blur.
One is to divide the image into a fixed number of equally wide vertical strips.
For each strip, we start a parallel task, and wait for their completion.
Within each strip, we traverse the pixels going from the top to the bottom of
the image, as illustrated in the following figure:
![stripping](vertical.png)
We start by implementing the sequential `blur` method in the
`VerticalBoxBlur.scala` source file, which takes the source image `src`, the
destination image `dst`, the starting (included) and ending (excluded) `x` coordinates
(i.e, column indices) of the strip, called `from` and `end`, and the blur `radius`.
The `blur` method blurs the pixels from the `src` image and writes them to the
`dst` image:
```scala
def blur(src: Img, dst: Img, from: Int, end: Int, radius: Int): Unit
```
The implementation of `blur` should rely on the previously defined `boxBlurKernel`.
Then, implement the `parBlur` method, which divides the image into `numTasks` vertical strips and runs each task in parallel:
```scala
def parBlur(src: Img, dst: Img, numTasks: Int, radius: Int): Unit
```
Use Scala ranges to create a list of splitting points
(hint: use the `by` method on ranges).
Then use collection combinators on the list of splitting points to create a list
of start and end tuples, one for each strip
(hint: use the `zip` and `tail` methods).
Finally, use the `task` construct to start a parallel task for each strip,
and then call `join` on each task to wait for its completion.
### Benchmarking VerticalBoxBlur
Before running the benchmarking program, go to the top of `VerticalBoxBlur.scala`
and replace the line:
```scala
Key.verbose -> true
```
by:
```scala
Key.verbose -> false
```
Now you can run the `VerticalBoxBlur` program with the following sbt command:
```
> runMain scalashop.VerticalBoxBlurRunner
```
Change the number of tasks and the radius parameter.
How does the performance change?
## Horizontal Stripping Box Blur
In this part of the exercise we will pick an alternative agglomeration for the
box blur algorithm.
Instead of dividing the image into vertical strips, we will divide it into
horizontal strips in a similar way:
![stripping](horizontal.png)
We implement the two methods, `blur` and `parBlur` in a similar way as before:
```scala
def blur(src: Img, dst: Img, from: Int, end: Int, radius: Int): Unit
def parBlur(src: Img, dst: Img, numTasks: Int, radius: Int): Unit
```
Note that the arguments `from` (included) and `end` (excluded) this time denote the values of the
`y` coordinate (i.e, row indices), and that we traverse the pixels left-to-right within each strip.
### Benchmarking HorizontalBoxBlur
Before running the benchmarking program, go to the top of `HorizontalBoxBlur.scala`
and replace the line:
```scala
Key.verbose -> true
```
by:
```scala
Key.verbose -> false
```
Now you can now run the `HorizontalBoxBlur` program from sbt with:
```
> runMain scalashop.HorizontalBoxBlurRunner
```
If you implemented the two blur versions correctly, you should observe that the
horizontal stripping is slightly faster.
This is because the pixel traversal order visits the pixels which are closer
together in memory (remember the mapping between the pixel coordinates and the
memory addresses). As a result, each core can reuse some of the pixels that it
fetched from the memory during the previous invocation of `boxBlurKernel`.
The processor cores spend less time fetching pixels from memory and lower the
pressure on the memory bus.
## ScalaShop
Now we have everything we need to start ScalaShop, from sbt run:
```
> runMain scalashop.ScalaShop
```
Change the blur implementation, parallelism level and blur radius, and study the
effect your changes have on performance.
* Which of the two blur implementations is faster?
* For which values of the `radius` parameter is the difference most significant?
* Why?
* What if we split the image into rectangles? Will this be faster?
*"Adobe" and "Photoshop" are either registered trademarks or trademarks of Adobe
Systems Incorporated in the United States and/or other countries.*
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\scalashop\kernel.png"
inkscape:export-xdpi="16.044189"
inkscape:export-ydpi="16.044189"
sodipodi:docname="avg.svg">
<defs
id="defs4">
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13978"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13980" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13264"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13266" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker11620"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path11622" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11430"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11432"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11220"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11222"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8210"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8212" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8122"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path8124"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8004"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8006" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7904"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7906" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7810"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7812" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5934"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path5936" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.55904437"
inkscape:cx="498.91476"
inkscape:cy="485.13131"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 569.48922,182.84133 0,536.93787"
id="path3342"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 476.55518,182.84133 0,536.93787"
id="path3346"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 390.18714,182.84133 0,536.93787"
id="path3350"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3352"
d="m 304.82925,182.84133 0,536.93787"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,268.75392 -419.48108,0"
id="path3354"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3356"
d="m 630.8714,359.12582 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,454.81371 -419.48108,0"
id="path3358"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3360"
d="m 630.8714,550.05861 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,649.73349 -419.48108,0"
id="path3362"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 213.41044,182.84133 0,536.93787"
id="path3364"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="643.29187"
y="549.94373"
id="text11422"
sodipodi:linespacing="125%"
transform="scale(1.0677679,0.93653312)"><tspan
sodipodi:role="line"
id="tspan11424"
x="643.29187"
y="549.94373"
style="font-size:65.55731964px">. . .</tspan></text>
<text
sodipodi:linespacing="125%"
id="text11426"
y="-384.24774"
x="803.21533"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0,0.93653312,-1.0677679,0,0,0)"><tspan
style="font-size:65.55731964px"
y="-384.24774"
x="803.21533"
id="tspan11428"
sodipodi:role="line">. . .</tspan></text>
<rect
style="fill:#000000;fill-opacity:0.85806454;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect3403"
width="87.649574"
height="97.272865"
x="389.95117"
y="453.85275" />
<rect
y="358.1488"
x="304.09036"
height="97.272865"
width="87.649574"
id="rect6045"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6047"
width="87.649574"
height="97.272865"
x="389.95117"
y="358.1488" />
<rect
y="358.1488"
x="479.3895"
height="97.272865"
width="87.649574"
id="rect6049"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6051"
width="87.649574"
height="97.272865"
x="304.09036"
y="453.85275" />
<rect
y="453.85275"
x="479.3895"
height="97.272865"
width="87.649574"
id="rect6053"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6055"
width="87.649574"
height="97.272865"
x="479.3895"
y="551.12567" />
<rect
y="551.12567"
x="388.16238"
height="97.272865"
width="87.649574"
id="rect6057"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6059"
width="87.649574"
height="97.272865"
x="302.30157"
y="551.12567" />
<path
inkscape:connector-curvature="0"
id="path6065"
d="m 630.8714,182.89311 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\scalashop\horizontal.png"
inkscape:export-xdpi="32.263706"
inkscape:export-ydpi="32.263706"
sodipodi:docname="horiz.svg">
<defs
id="defs4">
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13978"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13980" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13264"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13266" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker11620"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path11622" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11430"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11432"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11220"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11222"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8210"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8212" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8122"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path8124"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8004"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8006" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7904"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7906" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7810"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7812" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5934"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path5936" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.55904437"
inkscape:cx="498.91476"
inkscape:cy="485.13131"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 569.48922,182.84133 0,536.93787"
id="path3342"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 476.55518,182.84133 0,536.93787"
id="path3346"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 390.18714,182.84133 0,536.93787"
id="path3350"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3352"
d="m 304.82925,182.84133 0,536.93787"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,268.75392 -419.48108,0"
id="path3354"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3356"
d="m 630.8714,359.12582 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,454.81371 -419.48108,0"
id="path3358"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3360"
d="m 630.8714,550.05861 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,649.73349 -419.48108,0"
id="path3362"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 213.41044,182.84133 0,536.93787"
id="path3364"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="643.29187"
y="549.94373"
id="text11422"
sodipodi:linespacing="125%"
transform="scale(1.0677679,0.93653312)"><tspan
sodipodi:role="line"
id="tspan11424"
x="643.29187"
y="549.94373"
style="font-size:65.55731964px">. . .</tspan></text>
<text
sodipodi:linespacing="125%"
id="text11426"
y="-384.24774"
x="803.21533"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0,0.93653312,-1.0677679,0,0,0)"><tspan
style="font-size:65.55731964px"
y="-384.24774"
x="803.21533"
id="tspan11428"
sodipodi:role="line">. . .</tspan></text>
<rect
style="fill:#000000;fill-opacity:0.85806454;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect3403"
width="87.649574"
height="97.272865"
x="389.95117"
y="453.85275" />
<rect
y="358.1488"
x="304.09036"
height="97.272865"
width="87.649574"
id="rect6045"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6047"
width="87.649574"
height="97.272865"
x="389.95117"
y="358.1488" />
<rect
y="358.1488"
x="479.3895"
height="97.272865"
width="87.649574"
id="rect6049"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6051"
width="87.649574"
height="97.272865"
x="304.09036"
y="453.85275" />
<rect
y="453.85275"
x="479.3895"
height="97.272865"
width="87.649574"
id="rect6053"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6055"
width="87.649574"
height="97.272865"
x="479.3895"
y="551.12567" />
<rect
y="551.12567"
x="388.16238"
height="97.272865"
width="87.649574"
id="rect6057"
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="fill:#000000;fill-opacity:0.45161288;fill-rule:evenodd;stroke:#000000;stroke-width:0.93653309px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect6059"
width="87.649574"
height="97.272865"
x="302.30157"
y="551.12567" />
<path
inkscape:connector-curvature="0"
id="path6065"
d="m 630.8714,182.89311 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.53745508;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>
labs/lab1-parallel-box-blur-filter/horizontal.png

6.25 KiB

labs/lab1-parallel-box-blur-filter/kernel.png

872 B

labs/lab1-parallel-box-blur-filter/mapping.png

8.23 KiB

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\scalashop\mapping.png"
inkscape:export-xdpi="32.263699"
inkscape:export-ydpi="32.263699"
sodipodi:docname="mapping.svg">
<defs
id="defs4">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6574"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="scale(0.8) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path6576" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path6282"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13978"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13980" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13264"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13266" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker11620"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path11622" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11430"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11432"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11220"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11222"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8210"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8212" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8122"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path8124"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8004"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8006" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7904"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7906" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7810"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7812" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5934"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path5936" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.39530407"
inkscape:cx="614.73965"
inkscape:cy="665.95015"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 569.48922,182.84133 0,536.93787"
id="path3342"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 476.55518,182.84133 0,536.93787"
id="path3346"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 390.18714,182.84133 0,536.93787"
id="path3350"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3352"
d="m 304.82925,182.84133 0,536.93787"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.60156703;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 652.3366,268.75392 -440.94628,0"
id="path3354"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3356"
d="m 652.3366,359.12582 -440.94628,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.60156703;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.60156703;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 652.3366,454.81371 -440.94628,0"
id="path3358"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3360"
d="m 652.3366,550.05861 -440.94628,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.60156703;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.60156703;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 652.3366,649.73349 -440.94628,0"
id="path3362"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 213.41044,182.84133 0,536.93787"
id="path3364"
inkscape:connector-curvature="0" />
<text
sodipodi:linespacing="125%"
id="text11426"
y="-384.24774"
x="803.21533"
style="font-style:normal;font-weight:normal;font-size:37.4613266px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0,0.93653312,-1.0677679,0,0,0)"><tspan
style="font-size:65.55731964px"
y="-384.24774"
x="803.21533"
id="tspan11428"
sodipodi:role="line">. . .</tspan></text>
<path
inkscape:connector-curvature="0"
id="path6065"
d="m 652.3366,182.89311 -440.94628,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.60156703;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path6126"
d="m 653.44707,182.84133 0,536.93787"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06535697;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="246.84982"
y="240.26208"
id="text6128"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6130"
x="246.84982"
y="240.26208">0</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6132"
y="240.26208"
x="334.49939"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="240.26208"
x="334.49939"
id="tspan6134"
sodipodi:role="line">1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="422.14896"
y="240.26208"
id="text6136"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6138"
x="422.14896"
y="240.26208">2</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6140"
y="240.26208"
x="506.22101"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="240.26208"
x="506.22101"
id="tspan6142"
sodipodi:role="line">3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="597.00092"
y="240.26208"
id="text6144"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6146"
x="597.00092"
y="240.26208">4</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6148"
y="329.70044"
x="246.84982"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="329.70044"
x="246.84982"
id="tspan6150"
sodipodi:role="line">5</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="334.49939"
y="329.70044"
id="text6152"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6154"
x="334.49939"
y="329.70044">6</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6156"
y="329.70044"
x="422.14896"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="329.70044"
x="422.14896"
id="tspan6158"
sodipodi:role="line">7</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="506.22101"
y="329.70044"
id="text6160"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6162"
x="506.22101"
y="329.70044">8</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6164"
y="329.70044"
x="597.00092"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="329.70044"
x="597.00092"
id="tspan6166"
sodipodi:role="line">9</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="233.88127"
y="422.71631"
id="text6168"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6170"
x="233.88127"
y="422.71631">10</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6172"
y="422.71631"
x="321.53082"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="422.71631"
x="321.53082"
id="tspan6174"
sodipodi:role="line">11</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="409.18039"
y="422.71631"
id="text6176"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6178"
x="409.18039"
y="422.71631">12</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6180"
y="422.71631"
x="493.25244"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="422.71631"
x="493.25244"
id="tspan6182"
sodipodi:role="line">13</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="584.03235"
y="422.71631"
id="text6184"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6186"
x="584.03235"
y="422.71631">14</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6188"
y="516.62659"
x="233.88127"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="516.62659"
x="233.88127"
id="tspan6190"
sodipodi:role="line">15</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="321.53082"
y="516.62659"
id="text6192"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6194"
x="321.53082"
y="516.62659">16</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6196"
y="516.62659"
x="409.18039"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="516.62659"
x="409.18039"
id="tspan6198"
sodipodi:role="line">17</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="493.25244"
y="516.62659"
id="text6200"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6202"
x="493.25244"
y="516.62659">18</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6204"
y="516.62659"
x="584.03235"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="516.62659"
x="584.03235"
id="tspan6206"
sodipodi:role="line">19</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="233.88127"
y="615.90314"
id="text6208"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6210"
x="233.88127"
y="615.90314">20</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6212"
y="615.90314"
x="321.53082"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="615.90314"
x="321.53082"
id="tspan6214"
sodipodi:role="line">21</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="409.18039"
y="615.90314"
id="text6216"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6218"
x="409.18039"
y="615.90314">22</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6220"
y="615.90314"
x="493.25244"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="615.90314"
x="493.25244"
id="tspan6222"
sodipodi:role="line">23</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="584.03235"
y="615.90314"
id="text6224"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6226"
x="584.03235"
y="615.90314">24</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.76099992;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
d="m 707.98996,104.47247 -496.59964,0"
id="path6228"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path6572"
d="m 140.93101,679.12051 0,-496.59964"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.76099992;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker6574)" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="671.63489"
y="70.839287"
id="text7312"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan7314"
x="671.63489"
y="70.839287">x</tspan></text>
<text
sodipodi:linespacing="125%"
id="text7316"
y="679.23169"
x="79.685501"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="679.23169"
x="79.685501"
id="tspan7318"
sodipodi:role="line">y</tspan></text>
<text
sodipodi:linespacing="125%"
id="text7342"
y="165.63599"
x="246.84982"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="165.63599"
x="246.84982"
id="tspan7344"
sodipodi:role="line">0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="334.49939"
y="165.63599"
id="text7346"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan7348"
x="334.49939"
y="165.63599">1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text7350"
y="165.63599"
x="422.14896"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="165.63599"
x="422.14896"
id="tspan7352"
sodipodi:role="line">2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="506.22101"
y="165.63599"
id="text7354"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan7356"
x="506.22101"
y="165.63599">3</tspan></text>
<text
sodipodi:linespacing="125%"
id="text7358"
y="165.63599"
x="597.00092"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="165.63599"
x="597.00092"
id="tspan7360"
sodipodi:role="line">4</tspan></text>
<text
sodipodi:linespacing="125%"
id="text7382"
y="240.26208"
x="165.89948"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="240.26208"
x="165.89948"
id="tspan7384"
sodipodi:role="line">0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="165.89948"
y="329.70044"
id="text7386"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan7388"
x="165.89948"
y="329.70044">1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text7402"
y="423.29929"
x="165.89948"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="423.29929"
x="165.89948"
id="tspan7404"
sodipodi:role="line">2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="165.89948"
y="518.10394"
id="text7406"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan7408"
x="165.89948"
y="518.10394">3</tspan></text>
<text
sodipodi:linespacing="125%"
id="text7410"
y="616.93329"
x="165.89948"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="616.93329"
x="165.89948"
id="tspan7412"
sodipodi:role="line">4</tspan></text>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\scalashop\vertical.png"
inkscape:export-xdpi="32.263706"
inkscape:export-ydpi="32.263706"
sodipodi:docname="vert.svg">
<defs
id="defs4">
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13978"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13980" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker13726"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path13728"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13474"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:collect="always">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13476" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker13264"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path13266" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker12964"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path12966"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker12676"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:collect="always">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path12678" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker12514"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path12516"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker11620"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path11622" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11430"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11432"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker11220"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path11222"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8210"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8212" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8122"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path8124"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8004"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path8006" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7904"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7906" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7810"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path7812" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5934"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path5936" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.55904437"
inkscape:cx="358.49657"
inkscape:cy="390.35492"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 569.48922,268.86138 0,514.28572"
id="path3342"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 476.55518,268.86138 0,514.28572"
id="path3346"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 390.18714,268.86138 0,514.28572"
id="path3350"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3352"
d="m 304.82925,268.86138 0,514.28572"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.70941305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,268.92042 -419.48108,0"
id="path3354"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3356"
d="m 630.8714,371.95598 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.70941305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.70941305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,481.05245 -419.48108,0"
id="path3358"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3360"
d="m 630.8714,589.64385 -419.48108,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.70941305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.70941305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 630.8714,703.28601 -419.48108,0"
id="path3362"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 213.41044,268.86138 0,514.28572"
id="path3364"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="686.88641"
y="549.71875"
id="text11422"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan11424"
x="686.88641"
y="549.71875"
style="font-size:70px">. . .</tspan></text>
<text
sodipodi:linespacing="125%"
id="text11426"
y="-410.28741"
x="820.15405"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0,1,-1,0,0,0)"><tspan
style="font-size:70px"
y="-410.28741"
x="820.15405"
id="tspan11428"
sodipodi:role="line">. . .</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12514)"
d="m 247.27796,320.65086 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
id="path12268"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path12674"
d="m 343.09028,320.65086 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12676)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12964)"
d="m 438.58639,320.65086 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
id="path12962"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13262"
d="m 532.49665,320.65086 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13264)" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13466"
d="m 247.27796,421.71618 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13474)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12676)"
d="m 343.09028,421.71618 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
id="path13468"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13470"
d="m 438.58639,421.71618 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12964)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13264)"
d="m 532.49665,421.71618 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
id="path13472"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13726)"
d="m 247.27796,532.61972 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
id="path13718"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13720"
d="m 343.09028,532.61972 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12676)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12964)"
d="m 438.58639,532.61972 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
id="path13722"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13724"
d="m 532.49665,532.61972 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13264)" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13970"
d="m 247.27796,641.73449 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13978)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12676)"
d="m 343.09028,641.73449 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
id="path13972"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13974"
d="m 438.58639,641.73449 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12964)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.80425525;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13264)"
d="m 532.49665,641.73449 c 44.2368,48.29938 61.77332,47.23254 94.62097,3.28287"
id="path13976"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>
labs/lab1-parallel-box-blur-filter/vertical.png

7.31 KiB

# Reductions and Prefix Sums
Use the following commands to make a fresh clone of your repository:
```
git clone -b reductions git@gitlab.epfl.ch:lamp/student-repositories-s21/cs206-GASPAR.git cs206-reductions
```
## Useful links
* [A guide to the Scala parallel collections](https://docs.scala-lang.org/overviews/parallel-collections/overview.html)
* [The API documentation of the Scala parallel collections](https://www.javadoc.io/doc/org.scala-lang.modules/scala-parallel-collections_2.13/latest/scala/collection/index.html)
* [The API documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.4)
* [The API documentation of the Java standard library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)
**If you have issues with the IDE, try [reimporting the
build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work),
if you still have problems, use `compile` in sbt instead.**
## Introduction
In this assignment, you will implement several variants of reduction and prefix
sum algorithms. Each of the three parts of the assignment will exercise a
different aspect of parallel programming:
- choosing the right parallelization threshold
- identifying the correct reduction operator
- identifying the correct prefix sum operator
We will use the `parallel` construct, defined in the file `package.scala`, as in the lecture to start parallel
computations. Every `parallel` construct invocation takes two tasks as input and
outputs the corresponding results as a tuple of two elements. You are not allowed
to use the `task` construct in this assignment.
## Parallel Counting Change
If you took the course Functional Programming in Scala, you surely recall the
assignment in which you had to count the number of ways in which you can make
the change for a given amount of money.
The text of that assignment was as follows:
> Write a recursive function that counts how many different ways you can
> make change for an amount, given a list of coin denominations. For
> example, there are 3 ways to give change for 4 if you have coins with
> denomination 1 and 2: 1+1+1+1, 1+1+2, 2+2.
In this assignment, you will repeat the same task, but this time, your
implementation will be parallel.
Start with the sequential version of this problem once more -- the `countChange`
function takes the amount of money and the list of different coin denominations.
It returns the total number of different ways you can give change:
```scala
def countChange(money: Int, coins: List[Int]): Int
```
Note that the solution to this problem is recursive.
In every recursive call, we either decide to continue subtracting the next coin
in the `coins` list from the `money` amount, or we decide to drop the coin from the list of coins.
For example, if we have 4 CHF, and coin denominations of 1 and 2, the call
graph, in which every node depicts one invocation of the `countChange` method,
is as follows:
4,[1, 2]
3,[1, 2] + 4,[2]
2,[1, 2] + 3,[2] 2,[2] + 4,[]
1,[1, 2] + 2,[2] 1,[2] + 3,[] 0,[2] + 2,[] 0
0,[1, 2] + 1,[2] 1 0 0 1 0
1 0
We can take advantage of this recursive structure by evaluating different
subtrees in parallel.
This is the next part of the assignment -- implement the method `parCountChange`
that counts the amount of change in parallel:
```scala
def parCountChange(money: Int, coins: List[Int], threshold: Threshold): Int
```
As we learned in the lectures, the `parCountChange` should not spawn parallel
computations after reaching the leaf in the call graph -- the synchronization
costs of doing this are way too high.
Instead, we need to *agglomerate* parts of the computation.
We do this by calling the sequential `countChange` method when we decide that
the amount of work is lower than a certain value, called the *threshold*.
To separate the concern of deciding on the threshold value from the
implementation of our parallel algorithm, we implement the threshold
functionality in a separate function, described by the `Threshold` type alias:
```scala
type Threshold = (Int, List[Int]) => Boolean
```
When a `threshold` function returns `true` for a given amount of money and the
given list of coins, the sequential `countChange` implementation must be called.
Implement `parCountChange`!
Now that we have the `parCountChange` method, we ask ourselves what is the right
implementation of the `threshold` function?
Recall the examples from the lectures, such as summing the array values and
computing the norm, where this was easy -- we exactly knew the amount of work
required to traverse a subrange of the array, so `threshold` could return `true`
when the length of the subrange was smaller than a certain value.
Sadly, the total amount of work for a given `parCountChange` invocation is hard
to evaluate from the remaining amount of money and a list of coins.
In fact, the amount of work directly corresponds to the count that
`parCountChange` returns, which is the value that we are trying to compute.
Counting change is a canonical example of a task-parallel problem in which the
partitioning the workload across processors is *solution-driven* -- to know how
to optimally partition the work, we would first need to solve the problem
itself.
For this reason, many parallel algorithms in practice rely on heuristics to
assess the amount of work in a subtask.
We will implement several such heuristics in this exercise, and assess the
effect on performance.
First, implement the `moneyThreshold` method, which creates a threshold function
that returns `true` when the amount of money is less than or equal to `2 / 3` of
the starting amount:
```scala
def moneyThreshold(startingMoney: Int): Threshold
```
Remember that `a / b` will return the integer division of `a` and `b` when both
operands are `Int`s. To avoid this problem, be sure to always do the multiplication of
`startingMoney` by `2` before doing the division by `3`.
Now run the `ParallelCountChange` application in sbt and observe the speedup:
```
> runMain reductions.ParallelCountChangeRunner
```
The previous heuristic did not take into account how many coins were left on the
coins list, so try two other heuristics.
Implement the method `totalCoinsThreshold`, which returns a threshold function
that returns `true` when the number of coins is less than or equal to the `2 / 3` of the
initial number of coins:
```scala
def totalCoinsThreshold(totalCoins: Int): Threshold
```
Again, be careful about the order of operations.
Then, implement the method `combinedThreshold`, which returns a threshold
function that returns `true` when the amount of money multiplied with the number
of remaining coins is less than or equal to the starting money multiplied with
the initial number of coins divided by `2`:
```scala
def combinedThreshold(startingMoney: Int, allCoins: List[Int]): Threshold
```
Which of the three threshold heuristics gives the best speedup?
Can you think of a heuristic that improves performance even more?
## Parallel Parentheses Balancing
In this part of the assignment, we recall the Parenthesis Balancing assignment
that might be familiar to you from the Functional Programming in Scala course.
Here, the task is to, given an array of characters, decide if the parentheses in
the array are balanced.
Let us recall a few examples of strings in which parentheses are correctly
balanced:
```
(if (zero? x) max (/ 1 x))
I told him (that it's not (yet) done). (But he wasn't listening)
```
Similarly, the parentheses in the following strings are not balanced:
```
(o_()
:-)
())(
```
Implement a sequential function `balance`, which returns `true` iff the
parentheses in the array are balanced:
```scala
def balance(chars: Array[Char]): Boolean
```
Next, you will implement a parallel version of this method.
By now, you're already an expert at implementing the structure of a reduction
algorithm, so you should have no problem there.
The tricky part in parallel parentheses balancing is choosing the reduction
operator -- you probably implemented `balance` by keeping an integer
accumulator, incrementing it for left parentheses and decrementing it for the
right ones, taking care that this accumulator does not drop below zero.
Parallel parentheses balancing will require a bit more ingenuity on your part,
so we will give you a hint -- you will need two integer values for the
accumulator.
Implement the `parBalance` method, which checks if the parentheses in the input
array are balanced using two helper methods `reduce` and `traverse`.
These methods implement the parallel reduction and the sequential traversal
part, respectively:
```scala
def parBalance(chars: Array[Char], threshold: Int): Boolean = {
def traverse(idx: Int, until: Int, _???_: Int, _???_: Int): ???
def reduce(from: Int, until: Int): ??? = ???
reduce(0, chars.length) == ???
}
```
In this case, we again use the fixed threshold parameter, as we did in the
lectures. Sections with size smaller or equal to the threshold should be processed sequentially.
For maximum performance, use a `while` loop in the `traverse` method, or make
`traverse` tail-recursive -- do not use a `Range`.
Now, run the `ParallelParenthesesBalancing` application from sbt:
```
> runMain reductions.ParallelParenthesesBalancingRunner
```
How large was your speedup?
If you are looking for additional challenges, prove that your reduction operator
is associative!
## Line of Sight
In the last part of the exercise, you will be implementing an entirely new
parallel algorithm -- you will apply the prefix sum algorithm to computing the
line-of-sight in two-dimensional terrain.
Imagine that you are standing at the zero of a coordinate system.
The curve to your right describes the terrain that you are facing.
This is shown in the following figure:
![terrain](terrain.png)
The task of the line-of-sight algorithm is to compute the visibility of each
point of the terrain, as shown in the following figure, where the visible area
is above of the full line, and the obscured terrain is shown with a dotted
line.
![visibility](visibility.png)
What is the necessary and sufficient condition for a point on the terrain to be
visibile from the zero of the coordinate system, where you are standing?
Imagine that the terrain heights are represented with an array of numbers.
We can compute (the tangent of) the viewing angle of each point on the terrain by dividing the
height of the terrain `xs(i)` with the distance from the viewing point `i`,
as shown in the following figure:
![angle](angle.png)
It turns out that if the viewing angle of some point B is **lower** than the
viewing angle of an earlier point A, then the point B is not visible, as shown
in the following figure:
![angle](angle2.png)
This simple realization allows us to easily compute the line-of-sight on the
terrain -- if you were a sequential programmer, you would traverse the array of
height values from the beginning to the end, and write the maximum angle seen so
far into the output array.
Implement the sequential `lineOfSight` method, which, for each height entry in
the `input` array (except for input(0) which is the location of the observer and
is always zero), writes the maximum angle until that point into the `output`
array (output(0) should be 0):
```scala
def lineOfSight(input: Array[Float], output: Array[Float]): Unit
```
We keep things simple -- instead of outputting an array of booleans denoting the
visibilities, we only output the angles.
Note that what we call an angle in this assignment is actually the tangent
of the angle. Indeed, `xs(i)` is the opposing side of the angle and `i` the adjacent side.
The ratio `xs(i) / i` that you compute is in fact the tangent of the angle!
Since the tangent of an angle is strictly increasing between
0° and 90°, it is a perfectly good replacement for the actual angle in our use case.
Keep this in mind and make sure that you do not apply any trigonometic functions on the tangent!
When we see a sequential algorithm that produces a sequence of values by
traversing the input from left to right, this is an indication that the
algorithm might have a parallel prefix sum variant.
So let's try to implement one!
Recall what you learned in the lectures -- the first phase of the parallel
prefix sum algorithm is the *upsweep* phase.
Here, the algorithm constructs the reduction tree by traversing parts of the
input array in parallel.
Implement the method `upsweepSequential`, which returns the maximum angle in a
given part of the array, and the method `upsweep`, which returns the reduction
tree over parts of the input array. If the length of the given part of the input
array is less than or equal to `threshold`, then `upsweep` calls `upsweepSequential`.
Note that the part of the input array that needs to traversed is represented
using indices 'from' (inclusive) and 'until' (or 'end') (exclusive).
```scala
def upsweepSequential(input: Array[Float], from: Int, until: Int): Float
```
```scala
def upsweep(input: Array[Float], from: Int, end: Int, threshold: Int): Tree
```
The `Tree` data type is either a `Leaf` or an inner `Node`, and it contains the
maximum angle in the corresponding part of the array.
Note that when the number of elements in a part of the input array,
which is `(end - from)`, is smaller or equal to the threshold, the sequential `upsweepSequential`
has to be invoked, and you should return a `Leaf`.
Otherwise, you should process the part of the input array in parallel, and return
a `Node`. Make sure that the work is evenly distributed between the parallel computations.
The second phase is called *downsweep* -- here, the algorithm uses the tree to
push the maximum angle in the corresponding *prefix* of the array to the leaves
of the tree, and outputs the values.
Implement the methods `downsweep` which processes parts of the tree in parallel,
and the method `downsweepSequential`, which traverses the parts of the array
corresponding to leaves of the tree and writes the final angles into the
`output` array:
```scala
def downsweep(input: Array[Float], output: Array[Float],
startingAngle: Float, tree: Tree): Unit
def downsweepSequential(input: Array[Float], output: Array[Float],
startingAngle: Float, from: Int, until: Int): Unit
```
Finally, implement `parLineOfSight` using the `upsweep` and `downsweep` methods:
```scala
def parLineOfSight(input: Array[Float], output: Array[Float],
threshold: Int): Unit
```
Now, run the `LineOfSight` application in sbt and observe the relative speedups:
```
> runMain reductions.LineOfSightRunner
```
How large is the speedup compared to the number of cores in your processor?
Can you explain your results?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="angle-example-2.svg"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\progfun\instructions\angle2.png"
inkscape:export-xdpi="32.263699"
inkscape:export-ydpi="32.263699">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4146"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path4149"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.9899495"
inkscape:cx="488.53326"
inkscape:cy="701.51987"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1"
inkscape:snap-text-baseline="false" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
d="m 142.85714,101.50506 0,298.57143"
id="path3336"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.8496573;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 142.85714,399.21935 668.06991,0"
id="path3340"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:3,3;stroke-dashoffset:0"
d="m 143.44166,399.80366 c 88.89343,-20.20305 105.05587,-39.39595 105.05587,-39.39595"
id="path4640"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,3;stroke-opacity:1;stroke-dashoffset:0"
d="m 248.24499,360.5773 c 0,0 34.72027,-23.20876 57.95379,-32.30013 39.28467,-15.37226 57.45614,8.89703 57.45614,8.89703 19.69797,32.32488 43.43656,27.27412 55.55839,8.08122 l 12.12183,-19.1929 0,0 c 40.4061,-86.87311 77.78174,-113.13708 77.78174,-113.13708 0,0 18.22571,-16.58543 45.38508,0.61276 28.26715,17.89967 41.48804,62.0167 41.48804,62.0167"
id="path4642"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscscccsc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,3;stroke-opacity:1;stroke-dashoffset:0"
d="m 595.70683,274.55743 c 0,0 12.08157,73.3608 31.09283,77.76906 28.85051,6.68975 48.99239,-25.75889 48.99239,-25.75889 0,0 17.42513,-17.42513 27.27412,-14.89975 9.84899,2.52538 30.50526,33.55149 30.50526,33.55149"
id="path4752"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscsc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 142.85714,398.79078 500,221.64792"
id="path4832"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:6,3;stroke-dashoffset:0"
d="m 501.03566,222.01682 0,176.77669"
id="path5388"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path5390"
d="m 142.43151,219.99652 358.60415,-1e-5"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="310.11682"
y="200.8036"
id="text5392"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5394"
x="310.11682"
y="200.8036">i</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5396"
y="293.73761"
x="504.0661"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="293.73761"
x="504.0661"
id="tspan5398"
sodipodi:role="line">xs(i)</tspan></text>
<path
inkscape:connector-curvature="0"
id="path3357"
d="m 632.35549,355.35695 0,41.41625"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6,3;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.48477578;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6.96955149, 3.48477574;stroke-dashoffset:0;stroke-opacity:1"
d="m 148.49243,353.35696 483.86306,-1e-5"
id="path3359"
inkscape:connector-curvature="0" />
<text
sodipodi:linespacing="125%"
id="text3361"
y="347.29602"
x="458.60925"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="347.29602"
x="458.60925"
id="tspan3363"
sodipodi:role="line">i'</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="637.40619"
y="385.66147"
id="text3365"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3367"
x="637.40619"
y="385.66147">xs(i')</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="486.89352"
y="201.81377"
id="text4181"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4183"
x="486.89352"
y="201.81377">A</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="625.28442"
y="344.24527"
id="text4185"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4187"
x="625.28442"
y="344.24527">B</tspan></text>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="angle-example.svg"
inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\progfun\instructions\angle.png"
inkscape:export-xdpi="32.263699"
inkscape:export-ydpi="32.263699">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4146"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path4149"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.9899495"
inkscape:cx="488.53326"
inkscape:cy="701.51987"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1"
inkscape:snap-text-baseline="false" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
d="m 142.85714,101.50506 0,298.57143"
id="path3336"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.8496573;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 142.85714,399.21935 668.06991,0"
id="path3340"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:3,3;stroke-dashoffset:0"
d="m 143.44166,399.80366 c 88.89343,-20.20305 105.05587,-39.39595 105.05587,-39.39595"
id="path4640"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,3;stroke-opacity:1;stroke-dashoffset:0"
d="m 248.24499,360.5773 c 0,0 34.72027,-23.20876 57.95379,-32.30013 39.28467,-15.37226 57.45614,8.89703 57.45614,8.89703 19.69797,32.32488 43.43656,27.27412 55.55839,8.08122 l 12.12183,-19.1929 0,0 c 40.4061,-86.87311 77.78174,-113.13708 77.78174,-113.13708 0,0 18.22571,-16.58543 45.38508,0.61276 28.26715,17.89967 41.48804,62.0167 41.48804,62.0167"
id="path4642"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscscccsc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,3;stroke-opacity:1;stroke-dashoffset:0"
d="m 595.70683,274.55743 c 0,0 12.08157,73.3608 31.09283,77.76906 28.85051,6.68975 48.99239,-25.75889 48.99239,-25.75889 0,0 17.42513,-17.42513 27.27412,-14.89975 9.84899,2.52538 30.50526,33.55149 30.50526,33.55149"
id="path4752"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscsc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 142.85714,398.79078 500,221.64792"
id="path4832"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:6,3;stroke-dashoffset:0"
d="m 501.03566,222.01682 0,176.77669"
id="path5388"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path5390"
d="m 142.43151,219.99652 358.60415,-1e-5"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 3;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="310.11682"
y="200.8036"
id="text5392"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5394"
x="310.11682"
y="200.8036">i</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5396"
y="326.0625"
x="506.0864"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="326.0625"
x="506.0864"
id="tspan5398"
sodipodi:role="line">xs(i)</tspan></text>
</g>
</svg>
labs/lab2-reductions-and-prefix-sums/angle.png

4.04 KiB

labs/lab2-reductions-and-prefix-sums/angle2.png

5.98 KiB

labs/lab2-reductions-and-prefix-sums/terrain.png

2.8 KiB

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="terain.svg">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4146"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path4149"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="363.63782"
inkscape:cy="644.8613"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
d="m 142.85714,101.50506 0,298.57143"
id="path3336"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.8496573;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 142.85714,399.21935 668.06991,0"
id="path3340"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 143.44166,399.80366 c 88.89343,-20.20305 105.05587,-39.39595 105.05587,-39.39595"
id="path4640"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 248.24499,360.5773 c 0,0 34.72027,-23.20876 57.95379,-32.30013 39.28467,-15.37226 57.45614,8.89703 57.45614,8.89703 19.69797,32.32488 43.43656,27.27412 55.55839,8.08122 l 12.12183,-19.1929 0,0 c 40.4061,-86.87311 77.78174,-113.13708 77.78174,-113.13708 0,0 18.22571,-16.58543 45.38508,0.61276 28.26715,17.89967 41.48804,62.0167 41.48804,62.0167"
id="path4642"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscscccsc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 595.70683,274.55743 c 0,0 12.08157,73.3608 31.09283,77.76906 28.85051,6.68975 48.99239,-25.75889 48.99239,-25.75889 0,0 17.42513,-17.42513 27.27412,-14.89975 9.84899,2.52538 30.50526,33.55149 30.50526,33.55149"
id="path4752"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscsc" />
</g>
</svg>
labs/lab2-reductions-and-prefix-sums/visibility.png

3.45 KiB

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="visibility.svg">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4146"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path4149"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="450.29691"
inkscape:cy="792.75432"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="877"
inkscape:window-x="-4"
inkscape:window-y="-4"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
d="m 142.85714,101.50506 0,298.57143"
id="path3336"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.8496573;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 142.85714,399.21935 668.06991,0"
id="path3340"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 143.44166,399.80366 C 229.1208,389.60061 247.60467,362.19342 247.60467,362.19342"
id="path4640"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 247.12126,362.59389 c 0,0 35.844,-25.22535 59.07752,-34.31672 50.7702,-20.12943 91.36602,-35.89748 158.70779,-62.92894 2.54896,-14.01596 48.13888,-55.27993 48.13888,-55.27993"
id="path4642"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1"
d="m 594.1916,275.56758 c 0,0 12.08157,73.3608 31.09283,77.76906 28.85051,6.68975 48.99239,-25.75889 48.99239,-25.75889 0,0 17.42513,-17.42513 27.27412,-14.89975 9.84899,2.52538 30.50526,33.55149 30.50526,33.55149"
id="path4752"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscsc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 312.07723,326.23693 465.71429,265.21935"
id="path4754"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 511.25,211.11221 742.85714,79.505061"
id="path4756"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cscscccsc"
inkscape:connector-curvature="0"
id="path4758"
d="m 245.5023,364.2185 c 0,0 35.844,-25.22535 59.07752,-34.31672 39.28467,-15.37226 57.45614,8.89703 57.45614,8.89703 19.69797,32.32488 43.43656,27.27412 55.55839,8.08122 l 12.12183,-19.1929 0,0 c 40.4061,-86.87311 77.78174,-113.13708 77.78174,-113.13708 0,0 18.22571,-16.58543 45.38508,0.61276 28.26715,17.89967 41.48804,62.0167 41.48804,62.0167"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</svg>
# K-Means
Use the following commands to make a fresh clone of your repository:
```
git clone -b kmeans git@gitlab.epfl.ch:lamp/student-repositories-s21/cs206-GASPAR.git cs206-kmeans
```
## Useful links
* [A guide to the Scala parallel collections](https://docs.scala-lang.org/overviews/parallel-collections/overview.html)
* [The API documentation of the Scala parallel collections](https://www.javadoc.io/doc/org.scala-lang.modules/scala-parallel-collections_2.13/latest/scala/collection/index.html)
* [The API documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.4)
* [The API documentation of the Java standard library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)
**If you have issues with the IDE, try [reimporting the
build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work),
if you still have problems, use `compile` in sbt instead.**
## Introduction
In this assignment, you will implement the K-means algorithm for cluster
detection, which is used to partition *n* vectors into *k* clusters.
Here, vectors are separated into clusters based on their mutual similarity --
vectors that are closer to each other in space are more likely to end up in the
same cluster, and the distant vectors are likely to be in different clusters.
K-means has many applications: it is used in data mining, image filtering and
signal processing.
Here is a simple example -- let's say that we have a set of vectors in 2D space,
as shown in the following figure:
![points](points.png)
As a human, you can visually distinguish the three clusters of points in the
image:
![clusters](clusters.png)
When the number of clusters, dimensions and vectors grows, it becomes difficult
and even impossible to manually determine the clusters.
K-means is a simple algorithm that takes a set of vectors (called *points*) and
outputs as set of clusters as follows:
1. Pick `k` points called *means*. This is called *initialization*.
2. Associate each input point with the *mean* that is closest to it.
We obtain `k` *clusters* of points, and we refer to this process as
*classifying* the points.
3. Update each mean to have the average value of the corresponding cluster.
4. If the `k` means have significantly changed, go back to step 2.
If they did not, we say that the algorithm *converged*.
5. The `k` means represent different clusters -- every point is in the cluster
corresponding to the closest mean.
Above, two steps need additional discussion.
First, how do we pick the initial `k` means?
The initialization step can be done in many different ways -- we will just
randomly pick some of the input vectors.
Second, how do we know that the algorithm converged?
We will check that, for each mean, the square distance between the old value of
the mean and the new value of the mean is less than or equal to some value
`eta`.
For a better illustration, here are a few steps of the K-means algorithm.
Initially, we pick a random set of means, shown with "X" in the figure:
![step0](step0.png)
Then, we classify the points according to the closest mean ("X").
The means divide the space into regions, where each point is closer to the
corresponding mean than any other mean -- in the figure, the dotted line depicts
the borders of different regions:
![step1](step1.png)
All the points in the same region form one cluster. After having classified the
points, we can update the mean values to the average of all the points in the
cluster:
![step2](step2.png)
Each of the means was significantly updated.
This is a good indication that the algorithm did not yet converge,
so we repeat the steps again -- we first classify all the points:
![step3](step3.png)
And then we update the means again:
![step4](step4.png)
One of the means did not change at all in the last step.
Still, other means have changed so we continue this process until the change
in the position of each point drops below the `eta` value.
At each iteration of K-means, we can associate multiple points to clusters,
and compute the average of the `k` clusters, in parallel.
Note that the association of a point to its cluster is independent of the
other points in the input, and similarly, the computation of the average of a cluster
is independent of the other clusters.
Once all parallel tasks of the current iteration complete,
the algorithm can proceed to the next iteration.
K-means is an example of a *bulk synchronous parallel* algorithm (BSP).
BSP algorithms are composed from a sequence of supersteps, each of which
contains:
- *parallel computation*, in which processes independently perform local
computations and produce some values
- *communication*, in which processes exchange data
- *barrier synchronisation*, during which processes wait until every process
finishes
Data-parallel programming models are typically a good fit for BSP algorithms,
as each bulk synchronous phase can correspond to some number of data-parallel
operations.
## Classifying the points
In the first part of this assignment, you will classify the input points
according to the square distance to the means.
Input points are described with the following `Point` data-type:
class Point(val x: Double, val y: Double, val z: Double)
You will start by implementing the `classify` method:
def classify(points: ParSeq[Point], means: ParSeq[Point]): ParMap[Point, ParSeq[Point]]
This method take a sequence of points and a sequence of means, and return
a map collection, which maps each mean to the sequence of points in the corresponding
cluster.
Hint: Use `groupBy` and the `findClosest` method, which is already defined for
you. After that, make sure that all the means are in the resulting map, even if their
sequences are empty.
## Updating the means
In the second part of this assignment, you will update the means corresponding
to different clusters.
Implement the method `update`, which takes the map of classified points produced
in the previous step, and the sequence of previous means.
The method returns the new sequence of means:
def update(classified: ParMap[Point, ParSeq[Point]], oldMeans: ParSeq[Point]): ParSeq[Point]
Take care to preserve order in the resulting sequence -- the mean `i` in
the resulting sequence must correspond to the mean `i` from `oldMeans`.
Hint: Make sure you use the `findAverage` method that is predefined for you.
## Detecting convergence
Finally, you will implement convergence detection.
The convergence detection method takes a sequence of old
means and the sequence of updated means, and returns a boolean indicating if the
algorithm converged or not.
Given an `eta` parameter, `oldMeans` and `newMeans`, it returns `true` if the
algorithm converged, and `false` otherwise:
def converged(eta: Double, oldMeans: ParSeq[Point], newMeans: ParSeq[Point])
The algorithm converged iff the square distance between the old and the new mean is less
than or equal to `eta`, for all means.
Note: the means in the two lists are ordered -- the mean at `i` in `oldMeans`
is the previous value of the mean at `i` in `newMeans`.
Implement `converged`!
## Running the algorithm
We now have everything we need to run the K-means algorithm.
We only need to combine the previously defined methods in the right way.
The tail-recursive `kMeans` method takes a sequence of
points `points`, previously computed sequence of means `means`, and the `eta`
value:
@tailrec final def kMeans(points: ParSeq[Point],
means: ParSeq[Point], eta: Double): ParSeq[Point]
The `kMeans` method should return the sequence of means,
each corresponding to a specific cluster.
Hint: `kMeans` implements the steps 2-4 from the K-means pseudocode.
You can use the following command from within `sbt` to benchmark your code, the
parallel time shoul be significantly faster than the sequential time if your
computer has more than one core:
> runMain kmeans.KMeansRunner
## Use cases
And now for the fun part -- the K-means algorithm has a lot of use-cases!
In image processing applications, it can be used to reduce the size of the
color palette, thus compressing the image. This is done by turning a
[true color image](http://en.wikipedia.org/wiki/Color_depth), where each pixel
is encoded into 32 bits, into [indexed color](http://en.wikipedia.org/wiki/Indexed_color),
where each pixel can be encoded with just a few bits. This is done by using k-means to
"cluster" the important colors in the image, thus reducing its palette from
24-bit (`2^24` colors) to just 32 indexed colors, chosen from the 24-bit palette.
Here, pixels from the image are the input vectors,
and their coordinates are the different color channels.
This is the original true color (24-bit) image:
![start](start.png)
And this is the indexed color (32 colors) version of it:
![uniform-random-30steps](uniform-random-30steps.png)
So, thanks to your k-means implementation, ScalaShop can now compress images!
You can start ScalaShop by invoking from `sbt`:
> runMain kmeans.fun.ScalaShop
The k-means algorithm is very sensitive to the initial choice of means. There
are three choice strategies implemented in ScalaShop:
* `Uniform Choice` is the simplest strategy. It chooses `n` colors uniformly in
the entire color space, regardless of the colors used in the image. If the image
has a dominant color, the means created by this strategy will likely be very far
away from the clusters formed by this dominant color. You can try setting the
`Uniform Choice` strategy with 1, 10 and 30 steps. You will notice the initial
choice is quite bad, but the quality improves as the k-means algorithm is applied
in more steps.
* `Random Sampling` is another simple strategy, but with better results. For the
initial means, it randomly samples `n` colors from the image. This yields good
results if the image has few dominant colors, but it cannot handle subtle nuances
in the image. Again, if you try this strategy with 1, 10 and 30 k-means iteration
steps, you will notice improvements as the k-means algorithm is ran more.
* `Uniform Random` is the most complex strategy to pick means, but it also produces
the best results. It works by uniformly splitting the color space in sub-spaces.
It then counts the number of pixels that have colors belonging to that sub-space.
Based on this number, it chooses a proportional number of means in the sub-space,
by randomly sampling from the pixels in that sub-space. Therefore, if your image
has dominant colors, this strategy will drop a proportional number of means for
each dominant color, thus allowing the k-means algorithm to capture fine nuances.
In the EPFL image now available in ScalaShop, the mountains are a good way to see
how well each initial choice of means fares. You also have different strategies
for deciding convergence:
* `Steps` allows to run a fixed number of steps. After this, the k-means algorithm
is stopped.
* `Eta` corresponds to the means stability, as we showed earlier: if the
means did not move much since the last iteration, the result is considered stable.
* `Sound-to-noise` ratio is a more refined convergence strategy, which does not settle
for stability but tries to minimize the difference between the true color image
and the index color one. This strategy goes beyond `Eta`, but high Sound-to-noise
ratios will prevent the k-means algorithm from finishing!
With this in mind, enjoy ScalaShop, the ultimate image manipulation tool and
the nice, warm, sunny photo of EPFL!
labs/lab3-k-means/clusters.png

12.1 KiB