From f7b40a6d15f91fec31385aedced0a86e9222a7e5 Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain <olivier.blanvillain@gmail.com> Date: Mon, 1 Mar 2021 11:28:01 +0100 Subject: [PATCH] Add labs/lab2-reductions-and-prefix-sums --- .../lab2-reductions-and-prefix-sums/README.md | 355 ++++++++++++++++++ .../angle-example-2.svg | 209 +++++++++++ .../angle-example.svg | 154 ++++++++ .../lab2-reductions-and-prefix-sums/angle.png | Bin 0 -> 4134 bytes .../angle2.png | Bin 0 -> 6122 bytes .../terrain.png | Bin 0 -> 2863 bytes .../terrain.svg | 112 ++++++ .../visibility.png | Bin 0 -> 3534 bytes .../visibility.svg | 131 +++++++ 9 files changed, 961 insertions(+) create mode 100755 labs/lab2-reductions-and-prefix-sums/README.md create mode 100755 labs/lab2-reductions-and-prefix-sums/angle-example-2.svg create mode 100755 labs/lab2-reductions-and-prefix-sums/angle-example.svg create mode 100755 labs/lab2-reductions-and-prefix-sums/angle.png create mode 100755 labs/lab2-reductions-and-prefix-sums/angle2.png create mode 100755 labs/lab2-reductions-and-prefix-sums/terrain.png create mode 100755 labs/lab2-reductions-and-prefix-sums/terrain.svg create mode 100755 labs/lab2-reductions-and-prefix-sums/visibility.png create mode 100755 labs/lab2-reductions-and-prefix-sums/visibility.svg diff --git a/labs/lab2-reductions-and-prefix-sums/README.md b/labs/lab2-reductions-and-prefix-sums/README.md new file mode 100755 index 0000000..42240bb --- /dev/null +++ b/labs/lab2-reductions-and-prefix-sums/README.md @@ -0,0 +1,355 @@ +# 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: + + + +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. + + + +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: + + + +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: + + + +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? diff --git a/labs/lab2-reductions-and-prefix-sums/angle-example-2.svg b/labs/lab2-reductions-and-prefix-sums/angle-example-2.svg new file mode 100755 index 0000000..bd47893 --- /dev/null +++ b/labs/lab2-reductions-and-prefix-sums/angle-example-2.svg @@ -0,0 +1,209 @@ +<?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> diff --git a/labs/lab2-reductions-and-prefix-sums/angle-example.svg b/labs/lab2-reductions-and-prefix-sums/angle-example.svg new file mode 100755 index 0000000..fd67412 --- /dev/null +++ b/labs/lab2-reductions-and-prefix-sums/angle-example.svg @@ -0,0 +1,154 @@ +<?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> diff --git a/labs/lab2-reductions-and-prefix-sums/angle.png b/labs/lab2-reductions-and-prefix-sums/angle.png new file mode 100755 index 0000000000000000000000000000000000000000..50a8cc00497fa82cbb7442ac40ddd56b88dc9885 GIT binary patch literal 4134 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 literal 0 HcmV?d00001 diff --git a/labs/lab2-reductions-and-prefix-sums/angle2.png b/labs/lab2-reductions-and-prefix-sums/angle2.png new file mode 100755 index 0000000000000000000000000000000000000000..d5b4fccface66a660bcee7539458198423fb674e GIT binary patch literal 6122 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 literal 0 HcmV?d00001 diff --git a/labs/lab2-reductions-and-prefix-sums/terrain.png b/labs/lab2-reductions-and-prefix-sums/terrain.png new file mode 100755 index 0000000000000000000000000000000000000000..11ba1b6f55b18bdd7d93e73c3e751739eaf1be32 GIT binary patch literal 2863 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 literal 0 HcmV?d00001 diff --git a/labs/lab2-reductions-and-prefix-sums/terrain.svg b/labs/lab2-reductions-and-prefix-sums/terrain.svg new file mode 100755 index 0000000..d9073e0 --- /dev/null +++ b/labs/lab2-reductions-and-prefix-sums/terrain.svg @@ -0,0 +1,112 @@ +<?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> diff --git a/labs/lab2-reductions-and-prefix-sums/visibility.png b/labs/lab2-reductions-and-prefix-sums/visibility.png new file mode 100755 index 0000000000000000000000000000000000000000..9a26107e64f77f3a6d217f5ea80e0cffdb8127d8 GIT binary patch literal 3534 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 W?hyXq*~-Acz~JfX=d#Wzp$Pz}kdu1= literal 0 HcmV?d00001 diff --git a/labs/lab2-reductions-and-prefix-sums/visibility.svg b/labs/lab2-reductions-and-prefix-sums/visibility.svg new file mode 100755 index 0000000..e4f1882 --- /dev/null +++ b/labs/lab2-reductions-and-prefix-sums/visibility.svg @@ -0,0 +1,131 @@ +<?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> -- GitLab